vue2.x之插槽

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> //虽然定义了默认插槽,但是此时<testSlot> '填写内容区域' </testSlot> 没有填写任何内容
  </div>
</template>

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

<style scoped>
</style>

如果父组件不传插槽的内容,那么就默认展示后备内容(意思就是说原先插槽里面,写了啥就显示啥,因为你父组件没定义插槽里面的内容,我只能显示原本默认的了)

 

⏰ 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>

如果父组件自定义了插槽的内容,那么就默认展示后备内容就将被父组件自定义的内容所覆盖

具名插槽

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

👀 一个插槽不够用了,我要用多个,怎么区分这多个插槽呢? 这就需要这多个插槽取个名字了!

<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> //你去子组件插槽名字叫“center”那个位置
        <div>经典歌曲</div>
        <div>流行歌曲</div>
        <div>排行歌曲</div>
        <div>热门歌曲</div>
      </template>
      <template v-slot:footer>更多好听音乐请关注公众号</template> //你去子组件内部插槽名字叫“footer”那个位置
    </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>

效果如下:

⚠️ 注意: 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>

效果如下:

⏰ 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中的解构是一样的

posted on 2024-07-10 16:48  梁飞宇  阅读(42)  评论(0)    收藏  举报