framework7官方提供了vue+framework7的组合包,但是那个包用起来复杂度较高,而且不灵活。听说bug也不少。
所以我想用最原始的方式单独使用vue和framework7.
遇到以下问题:
1.framework7的router跳转到新的页面,这个页面的代码无法使用一个普通的包含js,css引用的html文件。
引用的js都要放到主页面中,导致加载速度慢.而且我希望一个html页面可以单独打开,也可以嵌入在单页程序里打开,所以现有的框架并不满足。
解决方案:修改framework7代码,在router加载新页面的时候,原始版本只是加载页面中class为page的div,修改成加载script和css到主页面,返回后再删除script和css,这样就实现了嵌入完整的html页面到单页程序. 需要代码的可以留言
2.framework7页面过度动画完成之前初始化vue,会导致vue无法工作(变量没有渲染)
解决办法:应该可以深入研究framework7和vue的代码从底层解决。 但是这里偷懒了,在页面动画完成后,再初始化vue.
这样就解决了。但是如果前一页面也用了vue,返回时就没法返回了(解决方案见2)
3.vue初始化时会将dom上后添加的一些变量都去掉。会导致从使用vue的页面跳转到另一页面,就返回不了了。
而framework7 会在作为page的div对象上写上一些变量,比如f7Page等。如果在vue初始化之前framework7已经初始化,这些变量会丢失,所以framework7的部分功能就失效了。
实际应用中,发现router受到了影响。 一个页面使用了vue,之后把page div上的f7Page对象删了,然后从这个页面跳到其他页面,就返回不了了。
解决方法:修改 vue.js,在vue初始化函数中,有个替换div的操作, 在替换之后,把旧div上的变量再塞回去。具体代码在patch函数中,修改的代码注释为by xiang. 如下:
return function patch (oldVnode, vnode, hydrating, removeOnly, parentElm, refElm) { if (isUndef(vnode)) { if (isDef(oldVnode)) { invokeDestroyHook(oldVnode); } return }
var isInitialPatch = false; var insertedVnodeQueue = [];
if (isUndef(oldVnode)) { // empty mount (likely as component), create new root element isInitialPatch = true; createElm(vnode, insertedVnodeQueue, parentElm, refElm); } else { var isRealElement = isDef(oldVnode.nodeType); if (!isRealElement && sameVnode(oldVnode, vnode)) { // patch existing root node patchVnode(oldVnode, vnode, insertedVnodeQueue, removeOnly); } else { if (isRealElement) { // mounting to a real element // check if this is server-rendered content and if we can perform // a successful hydration. if (oldVnode.nodeType === 1 && oldVnode.hasAttribute(SSR_ATTR)) { oldVnode.removeAttribute(SSR_ATTR); hydrating = true; } if (isTrue(hydrating)) { if (hydrate(oldVnode, vnode, insertedVnodeQueue)) { invokeInsertHook(vnode, insertedVnodeQueue, true); return oldVnode } else { warn( 'The client-side rendered virtual DOM tree is not matching ' + 'server-rendered content. This is likely caused by incorrect ' + 'HTML markup, for example nesting block-level elements inside ' + '<p>, or missing <tbody>. Bailing hydration and performing ' + 'full client-side render.' ); } } // either not server-rendered, or hydration failed. // create an empty node and replace it oldVnode = emptyNodeAt(oldVnode); }
// replacing existing element var oldElm = oldVnode.elm; var parentElm$1 = nodeOps.parentNode(oldElm);
// create new node createElm( vnode, insertedVnodeQueue, // extremely rare edge case: do not insert if old element is in a // leaving transition. Only happens when combining transition + // keep-alive + HOCs. (#4590) oldElm._leaveCb ? null : parentElm$1, nodeOps.nextSibling(oldElm) );
// update parent placeholder node element, recursively if (isDef(vnode.parent)) { var ancestor = vnode.parent; var patchable = isPatchable(vnode); while (ancestor) { for (var i = 0; i < cbs.destroy.length; ++i) { cbs.destroy(ancestor); } ancestor.elm = vnode.elm; if (patchable) { for (var i$1 = 0; i$1 < cbs.create.length; ++i$1) { cbs.create[i$1](emptyNode, ancestor); } // #6513 // invoke insert hooks that may have been merged by create hooks. // e.g. for directives that uses the "inserted" hook. var insert = ancestor.data.hook.insert; if (insert.merged) { // start at index 1 to avoid re-invoking component mounted hook for (var i$2 = 1; i$2 < insert.fns.length; i$2++) { insert.fns[i$2](); } } } else { registerRef(ancestor); } ancestor = ancestor.parent; } }
var prop;//by xiang to attach the properties removed by vue. framwork7 set some property such as f7Page to Dom, if that is removed, it will not work properly(i've found a problem in the router. it can not return back if the previous page use vue(f7Page is removed)) for (prop in oldVnode.elm) { if (vnode.elm[prop] === undefined) { var op = oldVnode.elm[prop]; if (op) { try { vnode.elm[prop] = op; } catch (e) {} } } } /* function setEvt(obj, arr) { if (obj.id && obj.dom7Listeners) { // var son = $$(vnode.elm).find('#' + obj.id)[0]; if (son && !son.dom7Listeners) { son.dom7Listeners = obj.dom7Listeners; var evt; for (evt in son.dom7Listeners) { son.addEventListener(evt, son.dom7Listeners[evt][0].listener, false); } } } if (obj.children.length > 0) { for (var i = 0; i < obj.children.length; i++) { setEvt(obj.children, arr); } } } setEvt(oldVnode.elm);*/ // destroy old node if (isDef(parentElm$1)) { removeVnodes(parentElm$1, [oldVnode], 0, 0); } else if (isDef(oldVnode.tag)) { invokeDestroyHook(oldVnode); } } }
invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch); return vnode.elm }
4.vue初始化会将dom上的一些通过代码添加的js事件去掉
可以按照第前面的思路把事件塞回去,但是实际测试中还是不能完全解决问题,比如picker控件,可以解决点击input弹出选择框,但是选择框滑动之后,input内容不联动。应该可以从底层解决,但是这里偷懒了,在vue加载完毕之后,再去初始化picker控件。
vue原理解密:
跟踪vue代码后发现,vue的原理就是把挂载div的outerHtml作为模板,填充变量后,生成新的div,然后替换到网页里。outerHtml是原始网页的内容,不会随dom的改变而改变。
5. 做html editor时用到div的contentEditable,div不能正常获取焦点
framework7会自动处理来自document的touchEnd, 其中有个handleTouchEnd函数,因为div中的元素不是activeElement,就会调用e.preventDefault.现在加了一个判断该元素是否是具有contentEditable 的div的子元素。如果是,就不调用activeElement.
|