slot插槽與slot作用域插槽的區別

目錄

 

前言

slot插槽的概念

區別


前言

不小心接觸了vue-template-compiler,所以藉助他看一下底層編譯出來的數據來探尋vue源碼,接觸的依然是最外層的源碼(o_o)

slot插槽的概念

官方說明

 
20315386-025523f560017cce.png
 

 

個人理解
插槽就是在子組件裏做定製化內容,當一個複用的組件內有一部分需要針對不同的場景有所差異,且無規律可循時,我們就可以使用<slot></slot>讓父組件自定義內容。
這種時候又可以分爲兩個場景:

  1. 內容與子組件內的數據無關
  2. 內容與子組件內的數據有關
    前者使用普通插槽,後者使用作用域插槽,作用域插槽的作用就是拿到子組件的數據
    具體介紹及使用可參考官方文檔
    https://cn.vuejs.org/v2/guide/components-slots.html

區別

普通插槽在父組件初始化期間會編譯成文本子節點存起來,在子組件渲染的時候直接將插槽替換成父組件裏渲染的節點
作用域插槽在父組件初始化期間會編譯成一個函數,在子組件初始化的時候執行這個函數生成vnode再進行渲染

下面會針對兩種插槽看用vue模板編譯器對模板編譯後的render函數
瞭解一下vue的渲染函數的縮寫

 
20315386-4b394a2e84645529.png
 

 

 

 
20315386-97a9569b785fe709.png
 


_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

 

 
20315386-152349237efb3a39.png
 

 

我用作用域插槽用的最多的還是在使用組件庫的時候,可見大型組件庫內部留了很多插槽,便於客戶去定製化使用
我們在封裝組件的時候也可以去考慮使用哪種插槽能符合更多場景,提高複用性

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章