一般來說,在Vue項目中使用父子組建時,都是把通用的HTML結構提取出來寫成一個子組件,需要動態展示的數據用過prop屬性傳遞,不過有時候我們可能想給子組件傳遞一個HTML代碼,這個時候用prop不太適用,Vue給我們提供了slot(插槽)可以實現這種應用場景.下面是自己學習后總結的幾種插槽使用方式
1. 普通使用方式
子組件 <template> <div> <!-- 如果有多個插槽,可以通過name命名 --> <div style="background-color: yellowgreen"> <slot name="header"></slot> </div> <!-- 父組件傳遞過來的值會展示在slot標簽中 --> <slot></slot> <ul v-if="todo"> <li>姓名: {{todo.name}}</li> <li>年齡: {{todo.age}}</li> <li>愛好: {{todo.hobby}}</li> </ul> <div style="color: gold"> <slot name="footer"></slot> </div> </div> </template> <script> export default { name: 'child', props: { todo: Object }, data () { return { } }, created () { console.log(this.todo, 'todo') } } </script> // 父組件 <template> <div> <!-- 引入子組件 --> <child :todo="list"> <!-- 這里的內容會渲染到子組件name為header的標簽中 --> <template slot="header"> <p>放在頭部的內容</p> </template> <!-- 子組件雙標簽中的內容會被渲染到子組件的slot標簽里 --> <h3>插槽標題</h3> <!-- 這里的內容會渲染到子組件name為footer的標簽中 --> <template slot="footer"> <p>放在底部的內容</p> </template> </child> </div> </template> <script> import child from './child' export default { name: 'parent', components: {child}, data () { return { list: { name: '靈夢', age: 18, text: '熱愛學習', hobby: '踢足球' } } } } </script>
渲染效果:
2. 作用域插槽
如果你希望從子組件獲取數據,進行其他數據展示,這個時候你可以使用作用域插槽
子組件 <template> <div> <ul v-if="todo.length" v-for="item in todo" :key="item.id"> <li>姓名: {{item.name}}</li> <li>年齡: {{item.age}}</li> <li>愛好: {{item.hobby}}</li> </ul> </div> </template> <script> export default { name: 'child', props: { todo: Array } </script> // 父組件 <template> <div> <!-- 引入子組件 --> <child :todo="list"> </child> </div> </template> <script> import child from './child' export default { name: 'parent', components: {child}, data () { return { list: [ {name: '靈夢', age: 18, text: '熱愛學習', hobby: '踢足球', id: 1}, {name: '李明', age: 13, text: '畫畫很棒', hobby: '畫畫', id: 2}, {name: '韓梅梅', age: 25, text: '性格文靜', hobby: '做手工', id: 3} ] } } } </script>
普通調用,渲染出來的數據就是這樣,但是如果我們想在第二項渲染中把hobby改成text,這時候就需要子組件把數據傳過來,父組件改變渲染方式了

// 子組件 <template> <div> <ul v-if="todo.length" v-for="(item,index) in todo" :key="item.id"> <li>姓名: {{item.name}}</li> <li>年齡: {{item.age}}</li> <!-- 如果是第二項,就使用作用域插槽,重新展示 --> <li v-if="index === 1"> <!-- 定義了content把item傳遞到父組件,定義的名字可以隨意取,需要傳遞的數據寫在后面 --> <slot :content="item"></slot> </li> <li v-else>愛好: {{item.hobby}}</li> </ul> </div> </template> <script> export default { name: 'child', props: { todo: Array } </script> // 父組件 <template> <div> <!-- 引入子組件 --> <child :todo="list"> <!-- 在子組件用slot-scope結收傳遞過來的數據,接收的名字可以隨意取 --> <template slot-scope="scope"> <!-- scope后接的就是你在子組件定義的傳遞值的名稱,scope.content就拿到了傳遞過來的值,在這里可以直接使用 --> 描述: {{scope.content.text}} </template> </child> </div> </template> <script> import child from './child' export default { name: 'parent', components: {child}, data () { return { list: [ {name: '靈夢', age: 18, text: '熱愛學習', hobby: '踢足球', id: 1}, {name: '李明', age: 13, text: '畫畫很棒', hobby: '畫畫', id: 2}, {name: '韓梅梅', age: 25, text: '性格文靜', hobby: '做手工', id: 3} ] } } } </script>
渲染出來的效果是這樣,第二項李明的展示內容就改變了

在很多Vue的插件中也有使用作用域插槽的,比如element-ui的table組件,它就可以通過添加作用域插槽改變渲染的原始數據
