溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Vue.js之slot深度復(fù)制的示例分析

發(fā)布時(shí)間:2021-08-13 10:15:42 來(lái)源:億速云 閱讀:137 作者:小新 欄目:web開(kāi)發(fā)

這篇文章給大家分享的是有關(guān)Vue.js之slot深度復(fù)制的示例分析的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。

前言

在Vue中,slot是一個(gè)很有用的特性,可以用來(lái)向組件內(nèi)部插入一些內(nèi)容。slot就是“插槽”的意思,用大白話說(shuō)就是:定義組件的時(shí)候留幾個(gè)口子,由用戶來(lái)決定插入的內(nèi)容。

例如我們定義一個(gè)組件MyComponent,其包含一個(gè)slot:

Vue.component('MyComponent', {
 template: `
 <div>
  <slot></slot>
 </div>
 `
})

當(dāng)調(diào)用<MyComponent>123</MyComponent>時(shí),會(huì)渲染為如下DOM結(jié)構(gòu):

<div>
 123
</div>

現(xiàn)在又有新需求了,我們希望調(diào)用<MyComponent>123</MyComponent>時(shí),渲染出這樣的DOM結(jié)構(gòu):

<div>
 123
 123
</div>

看起來(lái)很容易實(shí)現(xiàn),即再為MyComponent添加一個(gè)slot:

Vue.component('MyComponent', {
 template: `
 <div>
  <slot></slot>
  <slot></slot>
 </div>
 `
})

渲染出的結(jié)構(gòu)也確實(shí)如你所愿,唯一美中不足的是控制臺(tái)有一個(gè)小小的Warning:

Duplicate presence of slot "default" found in the same render tree

如果你不是強(qiáng)迫癥患者,這時(shí)候你可以收工安心回家睡覺(jué)了。直到有一天你的同事向你抱怨,為什么向MyComponent插入一個(gè)自定義組件會(huì)渲染不出來(lái)?

例如有一自定義組件MyComponent2:

Vue.component('MyComponent2', {
 template: `
 <div>456</div>
 `
})

當(dāng)調(diào)用<MyComponent><MyComponent2></MyComponent2></MyComponent>時(shí),預(yù)期渲染為如下DOM結(jié)構(gòu):

<div>
 <div>456</div>
 <div>456</div>
</div>

為什么不能正常工作呢?估計(jì)是前面的那個(gè)Warning搞得鬼,通過(guò)查詢發(fā)現(xiàn)在Vue 2.0中不允許有重名的slot:

重名的 Slots 移除

同一模板中的重名 已經(jīng)棄用。當(dāng)一個(gè) slot 已經(jīng)被渲染過(guò)了,那么就不能在同一模板其它地方被再次渲染了。如果要在不同位置渲染同一內(nèi)容,可一用 prop 來(lái)傳遞。

文檔中提示可以用props來(lái)實(shí)現(xiàn),然而在我的用例中顯然是不合適的。經(jīng)過(guò)搜索后,最靠譜的方法是手寫(xiě)render函數(shù),將slot中的內(nèi)容復(fù)制到其他的位置。

將之前的MyComponent改為render函數(shù)的方式定義:

Vue.component('MyComponent', {
 render (createElement) {
 return createElement('div', [
  ...this.$slots.default,
  ...this.$slots.default
 ])
 }
})

在上面的定義中我們插入了兩個(gè)this.$slots.default,測(cè)試下能不能正常工作。然而并沒(méi)有什么卵用,Vue文檔在render函數(shù)這一章有以下說(shuō)明:

VNodes 必須唯一

所有組件樹(shù)中的 VNodes 必須唯一

這意味著我們不能簡(jiǎn)單地在不同位置引用this.$slots.default,必須對(duì)slot進(jìn)行深度復(fù)制。深度復(fù)制的函數(shù)如下:

function deepClone(vnodes, createElement) {
 function cloneVNode (vnode) {
 const clonedChildren = vnode.children && vnode.children.map(vnode => cloneVNode(vnode));
 const cloned = createElement(vnode.tag, vnode.data, clonedChildren);
 cloned.text = vnode.text;
 cloned.isComment = vnode.isComment;
 cloned.componentOptions = vnode.componentOptions;
 cloned.elm = vnode.elm;
 cloned.context = vnode.context;
 cloned.ns = vnode.ns;
 cloned.isStatic = vnode.isStatic;
 cloned.key = vnode.key;
 return cloned;
 }
 const clonedVNodes = vnodes.map(vnode => cloneVNode(vnode))
 return clonedVNodes;
}

上面的核心函數(shù)就是cloneVNode() ,它遞歸地創(chuàng)建VNode,實(shí)現(xiàn)深度復(fù)制。VNode的屬性很多,我并不了解哪些是關(guān)鍵屬性,只是參照著Vue的源碼一并地復(fù)制過(guò)來(lái)。

基于以上函數(shù),我們更改MyComponent的定義:

Vue.component('MyComponent', {
 render (createElement) {
 return createElement('div', [
  ...this.$slots.default,
  ...deepClone(this.$slots.default, createElement)
 ])
 }
})

經(jīng)測(cè)試,一切正常。

感謝各位的閱讀!關(guān)于“Vue.js之slot深度復(fù)制的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI