目錄
前言
不小心接觸了vue-template-compiler
,所以藉助他看一下底層編譯出來的數據來探尋vue源碼,接觸的依然是最外層的源碼(o_o)
slot插槽的概念
官方說明
個人理解
插槽就是在子組件裏做定製化內容,當一個複用的組件內有一部分需要針對不同的場景有所差異,且無規律可循時,我們就可以使用<slot></slot>
讓父組件自定義內容。
這種時候又可以分爲兩個場景:
- 內容與子組件內的數據無關
- 內容與子組件內的數據有關
前者使用普通插槽,後者使用作用域插槽,作用域插槽的作用就是拿到子組件的數據
具體介紹及使用可參考官方文檔
https://cn.vuejs.org/v2/guide/components-slots.html
區別
普通插槽在父組件初始化期間會編譯成文本子節點存起來,在子組件渲染的時候直接將插槽替換成父組件裏渲染的節點
作用域插槽在父組件初始化期間會編譯成一個函數,在子組件初始化的時候執行這個函數生成vnode再進行渲染
下面會針對兩種插槽看用vue模板編譯器對模板編譯後的render函數
瞭解一下vue的渲染函數的縮寫
像_c(createElement)
,_t(renderSlot)
,_v(createTextVNode)
是下面會常看到的
普通插槽
r1
爲子組件,r2
爲父組件
let r1 = VueTemplateCompiler.compile('
<div>
<span>hello</span>
<slot name="header">name</slot>
</div>
');
let r2 = VueTemplateCompiler.compile('
<div>
<span>hello</span>
<div slot="header">name</div>
</div>
');
先看父組件渲染結果
r2.render=
'with(this){
return _c(\'div\',[
_c(\'span\',[
_v("hello")
]),
_c(\'div\',{ //在編譯時將插槽已經編譯成虛擬節點存進[_v("name")]
attrs:{
"slot":"header"
},
slot:"header"
},[_v("name")])
])
}'
下面是子組件的render函數
r1.render=
'with(this){
return _c(\'div\',[
_c(\'span\',[
_v("hello")
]),
_t("header",[_v("name")]) //在渲染時將header替換成父組件編譯完成的[_v("name")]
],2)
}'
可以看出父組件在編譯組件時就將slot插槽內容調用_c方法編譯成節點了,並用_v("name")
將文件節點保存,當子組件初始化時,會調_t()
方法渲染插槽,會先去父組件中尋找名爲"header"
的插槽,將"header"
替換成_v("name")
,渲染過程就是將vnode渲染成真實Dom
作用域插槽
r3
爲子組件,r4
爲父組件
let r3 = VueTemplateCompiler.compile('
<div>
<span>hello</span>
<slot name="footer" a="1"></slot>
</div>
');
let r4 = VueTemplateCompiler.compile('
<div>
<span>hello</span>
<div slot="footer" slot-scope="msg">{{msg.a}}</div>
</div>
');
先看父組件
r4.render=
'with(this){
return _c(\'div\',{
scopedSlots:
_u([{
key:"footer",
fn:function(msg){ //將插槽編譯成函數
return _c(\'div\',{},[_v(_s(msg.a))])
}
}])
},
[_c(\'span\',[_v("hello")])]
)
}'
子組件
r3.render=
'with(this){
return _c(\'div\',[
_c(\'span\',[_v("hello")]),
_t("footer",null,{a:"1"})
],2)
}'
父組件編譯時將插槽編譯成函數存進數組裏,子組件初始化時會根據插槽名"footer"
去父組件裏找key
爲"footer"
的函數並執行,然後生成vnode進行渲染
在vue2.6.0以後,舊版的slot、slot-scope的使用就被廢棄了,但是還可以用,推薦統一使用v-slot
我用作用域插槽用的最多的還是在使用組件庫的時候,可見大型組件庫內部留了很多插槽,便於客戶去定製化使用
我們在封裝組件的時候也可以去考慮使用哪種插槽能符合更多場景,提高複用性