Vuejs之Component slot 插槽詳解


Vuejs的component的數據進行了沙箱隔離,除js全局變量如Math, Date之類外無法訪問用戶自定義的變量,所以使用component寫組件或嵌套組件時明白變量的訪問非常重要

編譯作用域

在看componnent的使用之前,來看下component編譯作用域,明白作用域范圍才能順利寫出想要的組件

假設我們有一個組件child-component,在父組件中代碼如下:

<child-component>
  {{ message }}
</child-component>

編譯時message的作用域應該是父組件還是子組件呢,答案是父組件

父組件模板的內容在父組件作用域內編譯;子組件模板的內容在子組件作用域內編譯

Vue.component('child-component', {
  // 有效,因為是在正確的作用域內
  template: '<div v-show="someChildProperty">Child</div>',
  data: function () {
    return {
      someChildProperty: true
    }
  }
})

slot在component中有單slot,具名slot和作用域slot之分,先來看看最簡單的單slot應用

單個slot

直接上代碼,其中的name字段會在父組件中初始化並賦值

父組件
<div id="test">
<test-slot>
      <h3>{{name}}</h3>
      <p>Something bad happened.</p>
</test-slot>
</div>

組件 Vue.component("test-slot",{ // 插槽允許有默認內容 template: `<div> <strong>Error!</strong> <slot></slot> </div> `, data:function () { return { name:"perry" } } }); new Vue({ el:"#test" data:{name:"500 error"} }); 結果: <div> <strong>Error!</strong> <h3>500 error</h3> <p>Something bad happened.</p> </div>

 

具名slot

具名插槽比較有意思,在模板制定時非常好用,比如我們要寫一個模板包含頭尾和內容部分,希望在模板中定義好一部分公共的東西

 具名slot通過name來管理多個slot的解析,其中沒有name的slot會被歸為default slot放到沒有name的節點下面,default slot會無視散落在不同地方的html的位置,都將放到default slot的

模板位置中來

Vue.component("slot-name",{
           template:
               `<div>
                      <header>
                            <slot name="header"></slot>
                      </header>
                     <main>
                        <slot ></slot>
                     </main>
                     <footer>
                        <slot name="footer"></slot>
                     </footer>
 
                </div>
               `
});

<slot-name>
       <h3>開始</h3>
    <p>Default slot內容1</p> <template slot="header"> <ul> <li>主頁</li> <li>分診</li> <li>護理</li> <li>病歷</li> </ul> </template> <template slot="footer"> <p>結尾</p> </template> </slot-name>

運行結果:

 

 作用域slot

 作用域插槽在解決需要動態生成字符串模板時非常有用,特別針對控件編寫者

例如實現一個簡單的datagrid控件,控件在頁面component中相當於子控件,使用者希望只關注表頭和每行數據業務上,直接上代碼

控件代碼
Vue.component("datagrid",{
            props:{
                data:null
            },
            template:`
               <table>
                    <thead>
                        <slot name="headslot"></slot>
                    </thead>
                    <tbody>
                        <tr  v-for="item in data">
                            <slot name="bodyslot" :item="item">{{item.text}</slot>
                        </tr>
                   </tbody>
               </table>
           `
 });


在父組件中(頁面上)使用如下:
<datagrid :data="todos">
       <template slot="headslot">
              <tr>
                    <td>id</td>
                     <td>text</td>
                     <td>isTrue</td>
               </tr>
       </template>
      <template slot="bodyslot" slot-scope="{item}">
                    <td>{{item.id}}</td>
                    <td>{{item.text}}</td>
                    <td>{{item.isTrue}}</td>
      </template>
</datagrid>

如上代碼,簡單的datagrid就實現了,在父組件中只需要在head中指定table的head具體內容,對應的body中tr的每個td的字段綁定,其它交給控件處理

其中數據源是datagrid中的data屬性,與slot通信是通過slot-scope來實現數據域傳遞,這點非常關鍵

控件中 :item="item" 與父組件slot-scope="{item}" 完成數據訪問的傳遞,其中slot-scope="{item}"語句也可以通過"slot-scope="slotProps"來實現數據傳遞,slotProps對像相當於當slot對象上

所有props屬性的根,通過slotProps對象都能訪問到

 

在js調用如下:

var vm = new Vue({
                el:"#app",
                data:{
                    todos:[
                        {text:"A",id:1,isTrue:true},
                        {text:"B",id:2,isTrue:true},
                        {text:"C",id:3,isTrue:false},
                        {text:"D",id:4,isTrue:true},
                    ]
                }
            }); 

在data中的todos屬性已經與頁面的table形成了關聯,只要todos屬性發生變化,頁面的table會自動更新tbody中的數據行,這就是數據驅動的精髓

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM