欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue的Virtual Dom實(shí)現(xiàn)snabbdom解密

 更新時(shí)間:2017年05月03日 11:25:59   作者:尋圖  
這篇文章主要介紹了vue的Virtual Dom實(shí)現(xiàn)- snabbdom解密,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

vue在官方文檔中提到與react的渲染性能對(duì)比中,因?yàn)槠涫褂昧藄nabbdom而有更優(yōu)異的性能。

JavaScript 開銷直接與求算必要 DOM 操作的機(jī)制相關(guān)。盡管 Vue 和 React 都使用了 Virtual Dom 實(shí)現(xiàn)這一點(diǎn),但 Vue 的 Virtual Dom 實(shí)現(xiàn)(復(fù)刻自 snabbdom)是更加輕量化的,因此也就比 React 的實(shí)現(xiàn)更高效。

看到火到不行的國產(chǎn)前端框架vue也在用別人的 Virtual Dom開源方案,是不是很好奇snabbdom有何強(qiáng)大之處呢?不過正式解密snabbdom之前,先簡(jiǎn)單介紹下Virtual Dom。

什么是Virtual Dom

Virtual Dom可以看做一棵模擬了DOM樹的JavaScript樹,其主要是通過vnode,實(shí)現(xiàn)一個(gè)無狀態(tài)的組件,當(dāng)組件狀態(tài)發(fā)生更新時(shí),然后觸發(fā)Virtual Dom數(shù)據(jù)的變化,然后通過Virtual Dom和真實(shí)DOM的比對(duì),再對(duì)真實(shí)DOM更新??梢院?jiǎn)單認(rèn)為Virtual Dom是真實(shí)DOM的緩存。

為什么用Virtual Dom

我們知道,當(dāng)我們希望實(shí)現(xiàn)一個(gè)具有復(fù)雜狀態(tài)的界面時(shí),如果我們?cè)诿總€(gè)可能發(fā)生變化的組件上都綁定事件,綁定字段數(shù)據(jù),那么很快由于狀態(tài)太多,我們需要維護(hù)的事件和字段將會(huì)越來越多,代碼也會(huì)越來越復(fù)雜,于是,我們想我們可不可以將視圖和狀態(tài)分開來,只要視圖發(fā)生變化,對(duì)應(yīng)狀態(tài)也發(fā)生變化,然后狀態(tài)變化,我們?cè)僦乩L整個(gè)視圖就好了。

這樣的想法雖好,但是代價(jià)太高了,于是我們又想,能不能只更新狀態(tài)發(fā)生變化的視圖?于是Virtual Dom應(yīng)運(yùn)而生,狀態(tài)變化先反饋到Virtual Dom上,Virtual Dom在找到最小更新視圖,最后批量更新到真實(shí)DOM上,從而達(dá)到性能的提升。

除此之外,從移植性上看,Virtual Dom還對(duì)真實(shí)dom做了一次抽象,這意味著Virtual Dom對(duì)應(yīng)的可以不是瀏覽器的DOM,而是不同設(shè)備的組件,極大的方便了多平臺(tái)的使用。如果是要實(shí)現(xiàn)前后端同構(gòu)直出方案,使用Virtual Dom的框架實(shí)現(xiàn)起來是比較簡(jiǎn)單的,因?yàn)樵诜?wù)端的Virtual Dom跟瀏覽器DOM接口并沒有綁定關(guān)系。

基于Virtual DOM 的數(shù)據(jù)更新與UI同步機(jī)制:

初始渲染時(shí),首先將數(shù)據(jù)渲染為 Virtual DOM,然后由 Virtual DOM 生成 DOM。

數(shù)據(jù)更新時(shí),渲染得到新的 Virtual DOM,與上一次得到的 Virtual DOM 進(jìn)行 diff,得到所有需要在 DOM 上進(jìn)行的變更,然后在 patch 過程中應(yīng)用到 DOM 上實(shí)現(xiàn)UI的同步更新。

Virtual DOM 作為數(shù)據(jù)結(jié)構(gòu),需要能準(zhǔn)確地轉(zhuǎn)換為真實(shí) DOM,并且方便進(jìn)行對(duì)比。

介紹完Virtual DOM,我們應(yīng)該對(duì)snabbdom的功用有個(gè)認(rèn)識(shí)了,下面具體解剖下snabbdom這只“小麻雀”。

snabbdom

vnode

DOM 通常被視為一棵樹,元素則是這棵樹上的節(jié)點(diǎn)(node),而 Virtual DOM 的基礎(chǔ),就是 Virtual Node 了。

Snabbdom 的 Virtual Node 則是純數(shù)據(jù)對(duì)象,通過 vnode 模塊來創(chuàng)建,對(duì)象屬性包括:

sel
data
children
text
elm
key

可以看到 Virtual Node 用于創(chuàng)建真實(shí)節(jié)點(diǎn)的數(shù)據(jù)包括:

元素類型
元素屬性
元素的子節(jié)點(diǎn)

源碼:

//VNode函數(shù),用于將輸入轉(zhuǎn)化成VNode
 /**
 *
 * @param sel 選擇器
 * @param data 綁定的數(shù)據(jù)
 * @param children 子節(jié)點(diǎn)數(shù)組
 * @param text 當(dāng)前text節(jié)點(diǎn)內(nèi)容
 * @param elm 對(duì)真實(shí)dom element的引用
 * @returns {{sel: *, data: *, children: *, text: *, elm: *, key: undefined}}
 */
function vnode(sel, data, children, text, elm) {

 var key = data === undefined ? undefined : data.key;
 return { sel: sel, data: data, children: children,
 text: text, elm: elm, key: key };
}

snabbdom并沒有直接暴露vnode對(duì)象給我們用,而是使用h包裝器,h的主要功能是處理參數(shù):

h(sel,[data],[children],[text]) => vnode

從snabbdom的typescript的源碼可以看出,其實(shí)就是這幾種函數(shù)重載:

export function h(sel: string): VNode; 
export function h(sel: string, data: VNodeData): VNode; 
export function h(sel: string, text: string): VNode; 
export function h(sel: string, children: Array<VNode | undefined | null>): VNode; 
export function h(sel: string, data: VNodeData, text: string): VNode; 
export function h(sel: string, data: VNodeData, children: Array<VNode | undefined | null>): VNode; 

patch

創(chuàng)建vnode后,接下來就是調(diào)用patch方法將Virtual Dom渲染成真實(shí)DOM了。patch是snabbdom的init函數(shù)返回的。
snabbdom.init傳入modules數(shù)組,module用來擴(kuò)展snabbdom創(chuàng)建復(fù)雜dom的能力。

不多說了直接上patch的源碼:

return function patch(oldVnode, vnode) {
 var i, elm, parent;
 //記錄被插入的vnode隊(duì)列,用于批觸發(fā)insert
 var insertedVnodeQueue = [];
 //調(diào)用全局pre鉤子
 for (i = 0; i < cbs.pre.length; ++i) cbs.pre[i]();
 //如果oldvnode是dom節(jié)點(diǎn),轉(zhuǎn)化為oldvnode
 if (isUndef(oldVnode.sel)) {
 oldVnode = emptyNodeAt(oldVnode);
 }
 //如果oldvnode與vnode相似,進(jìn)行更新
 if (sameVnode(oldVnode, vnode)) {
 patchVnode(oldVnode, vnode, insertedVnodeQueue);
 } else {
 //否則,將vnode插入,并將oldvnode從其父節(jié)點(diǎn)上直接刪除
 elm = oldVnode.elm;
 parent = api.parentNode(elm);

 createElm(vnode, insertedVnodeQueue);

 if (parent !== null) {
 api.insertBefore(parent, vnode.elm, api.nextSibling(elm));
 removeVnodes(parent, [oldVnode], 0, 0);
 }
 }
 //插入完后,調(diào)用被插入的vnode的insert鉤子
 for (i = 0; i < insertedVnodeQueue.length; ++i) {
 insertedVnodeQueue[i].data.hook.insert(insertedVnodeQueue[i]);
 }
 //然后調(diào)用全局下的post鉤子
 for (i = 0; i < cbs.post.length; ++i) cbs.post[i]();
 //返回vnode用作下次patch的oldvnode
 return vnode;
 };

先判斷新舊虛擬dom是否是相同層級(jí)vnode,是才執(zhí)行patchVnode,否則創(chuàng)建新dom刪除舊dom,判斷是否相同vnode比較簡(jiǎn)單:

function sameVnode(vnode1, vnode2) {
 //判斷key值和選擇器
 return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel;
}

patch方法里面實(shí)現(xiàn)了snabbdom 作為一個(gè)高效virtual dom庫的法寶—高效的diff算法,可以用一張圖示意:

diff算法的核心是比較只會(huì)在同層級(jí)進(jìn)行, 不會(huì)跨層級(jí)比較。而不是逐層逐層搜索遍歷的方式,時(shí)間復(fù)雜度將會(huì)達(dá)到 O(n^3)的級(jí)別,代價(jià)非常高,而只比較同層級(jí)的方式時(shí)間復(fù)雜度可以降低到O(n)。

patchVnode函數(shù)的主要作用是以打補(bǔ)丁的方式去更新dom樹。

function patchVnode(oldVnode, vnode, insertedVnodeQueue) {
 var i, hook;
 //在patch之前,先調(diào)用vnode.data的prepatch鉤子
 if (isDef(i = vnode.data) && isDef(hook = i.hook) && isDef(i = hook.prepatch)) {
 i(oldVnode, vnode);
 }
 var elm = vnode.elm = oldVnode.elm, oldCh = oldVnode.children, ch = vnode.children;
 //如果oldvnode和vnode的引用相同,說明沒發(fā)生任何變化直接返回,避免性能浪費(fèi)
 if (oldVnode === vnode) return;
 //如果oldvnode和vnode不同,說明vnode有更新
 //如果vnode和oldvnode不相似則直接用vnode引用的DOM節(jié)點(diǎn)去替代oldvnode引用的舊節(jié)點(diǎn)
 if (!sameVnode(oldVnode, vnode)) {
 var parentElm = api.parentNode(oldVnode.elm);
 elm = createElm(vnode, insertedVnodeQueue);
 api.insertBefore(parentElm, elm, oldVnode.elm);
 removeVnodes(parentElm, [oldVnode], 0, 0);
 return;
 }
 //如果vnode和oldvnode相似,那么我們要對(duì)oldvnode本身進(jìn)行更新
 if (isDef(vnode.data)) {
 //首先調(diào)用全局的update鉤子,對(duì)vnode.elm本身屬性進(jìn)行更新
 for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode);
 //然后調(diào)用vnode.data里面的update鉤子,再次對(duì)vnode.elm更新
 i = vnode.data.hook;
 if (isDef(i) && isDef(i = i.update)) i(oldVnode, vnode);
 }
 //如果vnode不是text節(jié)點(diǎn)
 if (isUndef(vnode.text)) {
 //如果vnode和oldVnode都有子節(jié)點(diǎn)
 if (isDef(oldCh) && isDef(ch)) {
 //當(dāng)Vnode和oldvnode的子節(jié)點(diǎn)不同時(shí),調(diào)用updatechilren函數(shù),diff子節(jié)點(diǎn)
 if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue);
 }
 //如果vnode有子節(jié)點(diǎn),oldvnode沒子節(jié)點(diǎn)
 else if (isDef(ch)) {
 //oldvnode是text節(jié)點(diǎn),則將elm的text清除
 if (isDef(oldVnode.text)) api.setTextContent(elm, '');
 //并添加vnode的children
 addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
 }
 //如果oldvnode有children,而vnode沒children,則移除elm的children
 else if (isDef(oldCh)) {
 removeVnodes(elm, oldCh, 0, oldCh.length - 1);
 }
 //如果vnode和oldvnode都沒chidlren,且vnode沒text,則刪除oldvnode的text
 else if (isDef(oldVnode.text)) {
 api.setTextContent(elm, '');
 }
 }

 //如果oldvnode的text和vnode的text不同,則更新為vnode的text
 else if (oldVnode.text !== vnode.text) {
 api.setTextContent(elm, vnode.text);
 }
 //patch完,觸發(fā)postpatch鉤子
 if (isDef(hook) && isDef(i = hook.postpatch)) {
 i(oldVnode, vnode);
 }
 }

patchVnode將新舊虛擬DOM分為幾種情況,執(zhí)行替換textContent還是updateChildren。

updateChildren是實(shí)現(xiàn)diff算法的主要地方:

function updateChildren(parentElm, oldCh, newCh, insertedVnodeQueue) {
 var oldStartIdx = 0, newStartIdx = 0;
 var oldEndIdx = oldCh.length - 1;
 var oldStartVnode = oldCh[0];
 var oldEndVnode = oldCh[oldEndIdx];
 var newEndIdx = newCh.length - 1;
 var newStartVnode = newCh[0];
 var newEndVnode = newCh[newEndIdx];
 var oldKeyToIdx;
 var idxInOld;
 var elmToMove;
 var before;
 while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
 if (oldStartVnode == null) {
 oldStartVnode = oldCh[++oldStartIdx]; // Vnode might have been moved left
 }
 else if (oldEndVnode == null) {
 oldEndVnode = oldCh[--oldEndIdx];
 }
 else if (newStartVnode == null) {
 newStartVnode = newCh[++newStartIdx];
 }
 else if (newEndVnode == null) {
 newEndVnode = newCh[--newEndIdx];
 }
 else if (sameVnode(oldStartVnode, newStartVnode)) {
 patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue);
 oldStartVnode = oldCh[++oldStartIdx];
 newStartVnode = newCh[++newStartIdx];
 }
 else if (sameVnode(oldEndVnode, newEndVnode)) {
 patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue);
 oldEndVnode = oldCh[--oldEndIdx];
 newEndVnode = newCh[--newEndIdx];
 }
 else if (sameVnode(oldStartVnode, newEndVnode)) {
 patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue);
 api.insertBefore(parentElm, oldStartVnode.elm, api.nextSibling(oldEndVnode.elm));
 oldStartVnode = oldCh[++oldStartIdx];
 newEndVnode = newCh[--newEndIdx];
 }
 else if (sameVnode(oldEndVnode, newStartVnode)) {
 patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue);
 api.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
 oldEndVnode = oldCh[--oldEndIdx];
 newStartVnode = newCh[++newStartIdx];
 }
 else {
 if (oldKeyToIdx === undefined) {
  oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx);
 }
 idxInOld = oldKeyToIdx[newStartVnode.key];
 if (isUndef(idxInOld)) {
  api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm);
  newStartVnode = newCh[++newStartIdx];
 }
 else {
  elmToMove = oldCh[idxInOld];
  if (elmToMove.sel !== newStartVnode.sel) {
  api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm);
  }
  else {
  patchVnode(elmToMove, newStartVnode, insertedVnodeQueue);
  oldCh[idxInOld] = undefined;
  api.insertBefore(parentElm, elmToMove.elm, oldStartVnode.elm);
  }
  newStartVnode = newCh[++newStartIdx];
 }
 }
 }
 if (oldStartIdx > oldEndIdx) {
 before = newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].elm;
 addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
 }
 else if (newStartIdx > newEndIdx) {
 removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
 }
 }

updateChildren的代碼比較有難度,借助幾張圖比較好理解些:

過程可以概括為:oldCh和newCh各有兩個(gè)頭尾的變量StartIdx和EndIdx,它們的2個(gè)變量相互比較,一共有4種比較方式。如果4種比較都沒匹配,如果設(shè)置了key,就會(huì)用key進(jìn)行比較,在比較的過程中,變量會(huì)往中間靠,一旦StartIdx>EndIdx表明oldCh和newCh至少有一個(gè)已經(jīng)遍歷完了,就會(huì)結(jié)束比較。

具體的diff分析:
對(duì)于與sameVnode(oldStartVnode, newStartVnode)和sameVnode(oldEndVnode,newEndVnode)為true的情況,不需要對(duì)dom進(jìn)行移動(dòng)。

有3種需要dom操作的情況:

1.當(dāng)oldStartVnode,newEndVnode相同層級(jí)時(shí),說明oldStartVnode.el跑到oldEndVnode.el的后邊了。

2.當(dāng)oldEndVnode,newStartVnode相同層級(jí)時(shí),說明oldEndVnode.el跑到了newStartVnode.el的前邊。

3.newCh中的節(jié)點(diǎn)oldCh里沒有,將新節(jié)點(diǎn)插入到oldStartVnode.el的前邊。

在結(jié)束時(shí),分為兩種情況:

1.oldStartIdx > oldEndIdx,可以認(rèn)為oldCh先遍歷完。當(dāng)然也有可能newCh此時(shí)也正好完成了遍歷,統(tǒng)一都?xì)w為此類。此時(shí)newStartIdx和newEndIdx之間的vnode是新增的,調(diào)用addVnodes,把他們?nèi)坎暹M(jìn)before的后邊,before很多時(shí)候是為null的。addVnodes調(diào)用的是insertBefore操作dom節(jié)點(diǎn),我們看看insertBefore的文檔:parentElement.insertBefore(newElement, referenceElement)如果referenceElement為null則newElement將被插入到子節(jié)點(diǎn)的末尾。如果newElement已經(jīng)在DOM樹中,newElement首先會(huì)從DOM樹中移除。所以before為null,newElement將被插入到子節(jié)點(diǎn)的末尾。

2.newStartIdx > newEndIdx,可以認(rèn)為newCh先遍歷完。此時(shí)oldStartIdx和oldEndIdx之間的vnode在新的子節(jié)點(diǎn)里已經(jīng)不存在了,調(diào)用removeVnodes將它們從dom里刪除。

hook

shabbdom主要流程的代碼在上面就介紹完畢了,在上面的代碼中可能看不出來如果要?jiǎng)?chuàng)建比較復(fù)雜的dom,比如有attribute、props、eventlistener的dom怎么辦?奧秘就在與shabbdom在各個(gè)主要的環(huán)節(jié)提供了鉤子。鉤子方法中可以執(zhí)行擴(kuò)展模塊,attribute、props、eventlistener等可以通過擴(kuò)展模塊實(shí)現(xiàn)。

在源碼中可以看到hook是在snabbdom初始化的時(shí)候注冊(cè)的。

var hooks = ['create', 'update', 'remove', 'destroy', 'pre', 'post'];
var h_1 = require("./h");
exports.h = h_1.h;
var thunk_1 = require("./thunk");
exports.thunk = thunk_1.thunk;
function init(modules, domApi) {
 var i, j, cbs = {};
 var api = domApi !== undefined ? domApi : htmldomapi_1.default;
 for (i = 0; i < hooks.length; ++i) {
 cbs[hooks[i]] = [];
 for (j = 0; j < modules.length; ++j) {
 var hook = modules[j][hooks[i]];
 if (hook !== undefined) {
 cbs[hooks[i]].push(hook);
 }
 }
 }

snabbdom在全局下有6種類型的鉤子,觸發(fā)這些鉤子時(shí),會(huì)調(diào)用對(duì)應(yīng)的函數(shù)對(duì)節(jié)點(diǎn)的狀態(tài)進(jìn)行更改首先我們來看看有哪些鉤子以及它們觸發(fā)的時(shí)間:

比如在patch的代碼中可以看到調(diào)用了pre鉤子

return function patch(oldVnode, vnode) {
 var i, elm, parent;
 var insertedVnodeQueue = [];
 for (i = 0; i < cbs.pre.length; ++i)
 cbs.pre[i]();
 if (!isVnode(oldVnode)) {
 oldVnode = emptyNodeAt(oldVnode);
 }

我們找一個(gè)比較簡(jiǎn)單的class模塊來看下其源碼:

function updateClass(oldVnode, vnode) {
 var cur, name, elm = vnode.elm, oldClass = oldVnode.data.class, klass = vnode.data.class;
 if (!oldClass && !klass)
 return;
 if (oldClass === klass)
 return;
 oldClass = oldClass || {};
 klass = klass || {};
 for (name in oldClass) {
 if (!klass[name]) {
 elm.classList.remove(name);
 }
 }
 for (name in klass) {
 cur = klass[name];
 if (cur !== oldClass[name]) {
 elm.classList[cur ? 'add' : 'remove'](name);
 }
 }
}
exports.classModule = { create: updateClass, update: updateClass };
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = exports.classModule;

},{}]},{},[1])(1)
});

可以看出create和update鉤子方法調(diào)用的時(shí)候,可以執(zhí)行class模塊的updateClass:從elm中刪除vnode中不存在的或者值為false的類。

將vnode中新的class添加到elm上去。

總結(jié)snabbdom

  • vnode是基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)
  • patch創(chuàng)建或更新DOM樹
  • diff算法只比較同層級(jí)
  • 通過鉤子和擴(kuò)展模塊創(chuàng)建有attribute、props、eventlistener的復(fù)雜dom

參考:

snabbdom

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • vue+element UI實(shí)現(xiàn)樹形表格

    vue+element UI實(shí)現(xiàn)樹形表格

    這篇文章主要為大家詳細(xì)介紹了vue+element UI實(shí)現(xiàn)樹形表格,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • Vue手寫橫向輪播圖的實(shí)例

    Vue手寫橫向輪播圖的實(shí)例

    這篇文章主要介紹了Vue手寫橫向輪播圖的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • vue通過點(diǎn)擊事件讀取音頻文件的方法

    vue通過點(diǎn)擊事件讀取音頻文件的方法

    最近做項(xiàng)目遇到這樣的一個(gè)需求,通過select元素來選擇音頻文件的名稱,點(diǎn)擊按鈕可以進(jìn)行試聽。接下來通過本文給大家介紹vue項(xiàng)目中通過點(diǎn)擊事件讀取音頻文件的方法,需要的朋友可以參考下
    2018-05-05
  • 詳解vue-cli中配置sass

    詳解vue-cli中配置sass

    本篇文章主要介紹了詳解vue-cli中配置sass ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • vue+element開發(fā)一個(gè)谷歌插件的全過程

    vue+element開發(fā)一個(gè)谷歌插件的全過程

    這篇文章主要給大家介紹了關(guān)于vue+element開發(fā)一個(gè)谷歌插件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • Vue3中引用本地圖片路徑的方法詳解

    Vue3中引用本地圖片路徑的方法詳解

    這篇文章主要為大家詳細(xì)介紹了Vue3中引用本地圖片路徑的常用方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • 詳解在Vue中使用TypeScript的一些思考(實(shí)踐)

    詳解在Vue中使用TypeScript的一些思考(實(shí)踐)

    這篇文章主要介紹了詳解在Vue中使用TypeScript的一些思考(實(shí)踐),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-07-07
  • MVVM模型在Vue中的使用詳解

    MVVM模型在Vue中的使用詳解

    MVVM模型主要是為了分離視圖(View)和模型(Model),其優(yōu)點(diǎn)為:低耦合、可重用性、獨(dú)立開發(fā)以及可測(cè)試,視圖和模型分離的特點(diǎn)給了 Vue 很大的啟發(fā),這篇文章主要介紹了MVVM模型在Vue中的使用,需要的朋友可以參考下
    2022-11-11
  • vue倉庫的使用方式

    vue倉庫的使用方式

    這篇文章主要介紹了vue倉庫的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • Vue2中引入使用ElementUI的教程詳解

    Vue2中引入使用ElementUI的教程詳解

    這篇文章主要為大家詳細(xì)介紹了Vue2中引入使用ElementUI教程的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的可以參考下
    2024-03-03

最新評(píng)論