vue2之插槽

168 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第27天,点击查看活动详情

插槽

1. 什么是插槽

插槽通俗地讲就是在封装组件的时候,对不确定部分的内容的一种占位。这个展位用slot标签表示,然后在具体使用过程中根据实际内容将其放在这个slot标签的位置。

<template>
  <div class="slot-wrapper">
    <div class="titler-wrapper">{{title}}</div>
    <slot></slot>
  </div>
</template>

注意: 只有在组件中使用了slot标签占位之后,组件标签之间的内容才能被渲染,否则是会被抛弃的

2. 插槽的编译作用域

插槽里面的内容是父组件根据自身的实际情况来定义的,是属于父组件作用域的,而子组件是属于子组件作用域的。它们之间是不能直接访问的。 插槽

<template>
  <div class="slot-wrapper">
    <div class="titler-wrapper">{{title}}</div>
    <slot></slot>
  </div>
</template>

父组件

<template>
  <div class="hello">
    <testSlot title="电影分类">
      <span>{{title}}</span>
    </testSlot>
  </div>
</template>

此时这样是获取不到title的, 页面会报错。

3. 组件的分类

我们在使用插槽的时候,主要可以分为三类:默认插槽,具名插槽,作用域插槽

默认插槽

默认插槽很简单,就是子组件中写了一个slot标签,那么在父组件中子组件中间的所有内容都是默认插槽的内容。

<template>
  <div class="slot-wrapper">
    <div class="titler-wrapper">{{title}}</div>
    <slot>好听的歌曲</slot>
  </div>
</template>
<script>
export default {
  name: 'testSlot',
  props: ['title'],
  data() {
    return {
    }
  }
}
</script>
<style lang="css" scoped>
.slot-wrapper {
  width: 200px;
  height: 500px;
  border: 1px solid #999;
  border-radius: 4px;
}
.titler-wrapper {
  width: 100%;
  height: 40px;
  line-height: 40px;
  background-color: aquamarine;
  text-align: center;
}
</style>

像上面这种,slot标签上没有任何属性,那么这个插槽就是默认插槽,组件中只能有一个默认插槽

1. 后备内容

<template>
  <div class="hello">
    <testSlot :title="title">
    </testSlot>
  </div>
</template>

<script>
import testSlot from './testSlot.vue';
export default {
  name: 'HelloWorld',
  components: {
    testSlot
  },
  data() {
    return {
      title: '电影分类'
    }
  },
  methods: {
  }
}
</script>

<style scoped>
</style>

如果父组件不传插槽的内容,那么就默认展示后备内容

image.png

2. 展示配置的插槽内容

<template>
  <div class="hello">
    <testSlot :title="title">
      <div>经典歌曲</div>
      <div>流行歌曲</div>
      <div>排行歌曲</div>
      <div>热门歌曲</div>
    </testSlot>
  </div>
</template>

<script>
import testSlot from './testSlot.vue';
export default {
  name: 'HelloWorld',
  components: {
    testSlot
  },
  data() {
    return {
      title: '电影分类'
    }
  },
  methods: {
  }
}
</script>

<style scoped>
</style>

image.png

具名插槽

当组件中需要根据结构区分很多插槽时,需要给每个插槽命一个名,这时就有了具名插槽

<template>
  <div class="slot-wrapper">
    <div class="titler-wrapper">{{title}}</div>
    <slot name="center"></slot>
    <slot name="footer"></slot>
  </div>
</template>
<script>
export default {
  name: 'testSlot',
  props: ['title'],
  data() {
    return {
    }
  }
}
</script>
<style lang="css" scoped>
.slot-wrapper {
  width: 200px;
  height: 500px;
  border: 1px solid #999;
  border-radius: 4px;
}
.titler-wrapper {
  width: 100%;
  height: 40px;
  line-height: 40px;
  background-color: aquamarine;
  text-align: center;
}
</style>

废弃写法

<template>
  <div class="hello">
    <testSlot :title="title">
      <div slot="center">
        <div>经典歌曲</div>
        <div>流行歌曲</div>
        <div>排行歌曲</div>
        <div>热门歌曲</div>
      </div>
      <div slot="footer">更多好听音乐请关注公众号</div>
    </testSlot>
  </div>
</template>

<script>
import testSlot from './testSlot.vue';
export default {
  name: 'HelloWorld',
  components: {
    testSlot
  },
  data() {
    return {
      title: '电影分类'
    }
  },
  methods: {
  }
}
</script>

<style scoped>
</style>

最新写法

<template>
  <div class="hello">
    <testSlot :title="title">
      <template v-slot:center>
        <div>经典歌曲</div>
        <div>流行歌曲</div>
        <div>排行歌曲</div>
        <div>热门歌曲</div>
      </template>
      <template v-slot:footer>更多好听音乐请关注公众号</template>
    </testSlot>
  </div>
</template>

<script>
import testSlot from './testSlot.vue';
export default {
  name: 'HelloWorld',
  components: {
    testSlot
  },
  data() {
    return {
      title: '电影分类'
    }
  },
  methods: {
  }
}
</script>

<style scoped>
</style>

简写形式

<template>
  <div class="hello">
    <testSlot :title="title">
      <template #center>
        <div>经典歌曲</div>
        <div>流行歌曲</div>
        <div>排行歌曲</div>
        <div>热门歌曲</div>
      </template>
      <template #footer>更多好听音乐请关注公众号</template>
    </testSlot>
  </div>
</template>

效果如下:

image.png

注意 v-slot 只能添加在 <template> 上

作用域插槽

前面我们介绍过插槽中的作用域,父级作用域和子级作用域是不能互相直接访问的。如果要访问的话,那就只能使用作用域插槽了。

1. 基础用法

slot中要将内容绑定上

<template>
  <div class="slot-wrapper">
    <div class="titler-wrapper">{{title}}</div>
    <slot :user="user">{{user.lastName}}</slot>
  </div>
</template>
<script>
export default {
  name: 'testSlot',
  props: ['title'],
  data() {
    return {
      user: {
        firstName: '张',
        lastName: '阿强'
      }
    }
  }
}
</script>
<style lang="css" scoped>
.slot-wrapper {
  width: 200px;
  height: 500px;
  border: 1px solid #999;
  border-radius: 4px;
}
.titler-wrapper {
  width: 100%;
  height: 40px;
  line-height: 40px;
  background-color: aquamarine;
  text-align: center;
}
</style>

插槽中使用v-slot:插槽名=“变量名进行获取”,如果是默认插槽可以简写为v-slot="slotProps"

<template>
  <div class="hello">
    <testSlot :title="title">
      <template v-slot:default="slotProps">
        {{ slotProps.user.firstName }}
      </template>
    </testSlot>
  </div>
</template>

<script>
import testSlot from './testSlot.vue';
export default {
  name: 'HelloWorld',
  components: {
    testSlot
  },
  data() {
    return {
      title: '电影分类'
    }
  },
  methods: {
  }
}
</script>

<style scoped>
</style>

效果如下:

image.png

2. 解构插槽

如果插槽中的作用域变量是个对象,还可以进行解构。

<template>
  <div class="hello">
    <testSlot :title="title">
      <template v-slot:default="{ user }">
        {{ user.firstName }}
      </template>
    </testSlot>
  </div>
</template>

也可以赋值

<template>
  <div class="hello">
    <testSlot :title="title">
      <template v-slot:default="{ user = { firstName: '李' } }">
        {{ user.firstName }}
      </template>
    </testSlot>
  </div>
</template>

这种解构和es6中的解构是一样的