一般来说,在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组件,它就可以通过添加作用域插槽改变渲染的原始数据