Vue.js插槽slot和作用域插槽slot-scope学习小结

一般来说,在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组件,它就可以通过添加作用域插槽改变渲染的原始数据
原文地址:https://www.cnblogs.com/steamed-twisted-roll/p/10001512.html