framework7的改進,以及與vue組合使用遇到的問題以及解決方法 (附vue的原理)

voiceangel發表於2018-10-11

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[i](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[i], 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.

 

相關文章