Skip to content

插槽的本质

复习插槽的概念:

  • 子组件:通过 slot 来设置插槽
  • 父组件:使用子组件时可以往 slot 的位置插入模板内容

插槽使用层面的本质:父组件向子组件传递模板内容

  • 默认插槽:拥有默认的一些内容
  • 具名插槽:给你的插槽取一个名字
  • 作用域插槽:数据来自于子组件,通过插槽的形式传递给父组件使用

父组件传递内容的本质

传递的是一个对象:

js
{
  default: function(){ ... },
  xxx: function(){ ... },
  xxx: function(){ ... },
}

对于上面的例子来讲,父组件传递的就是这样的一个对象:

jsx
{
  default: function(){
    // 注意返回值是对应结构的虚拟 DOM
    return (
    	 <div class="card-content">
        <img src="./assets/landscape.jpeg" alt="Beautiful landscape" class="card-image" />
        <p>探索未知的自然风光,记录下每一个令人惊叹的瞬间。加入我们的旅程,一起见证世界的壮丽。</p>
      </div>
    )
  },
  header: function(){
    return (
    	<div>摄影作品</div>
    )
  }
}

父组件向子组件传递过去的东西本质上是函数,通过调用这些函数,能够得到对应结构的虚拟 DOM.

子组件设置插槽的本质

其实就是对父组件传递过来的函数进行调用,得到对应的虚拟 DOM.

js
const slots = {
  default: function(){ ... },
  xxx: function(){ ... },
  xxx: function(){ ... },
}; // 该对象是父组件传递过来的对象
slots.default(); // 得到要渲染的虚拟DOM 
slots.header(); // 得到要渲染的虚拟DOM
slots.xxx(); // 得到要渲染的虚拟DOM

进行验证

最后,我们需要对上面的说法进行验证。

js
import { defineComponent, h, ref } from 'vue'
import styles from './CardComponent.module.css'

export default defineComponent({
  name: 'CardComponent',
  setup(_, { slots }) {
    const title = ref('这是子组件标题222')
    const deaultSlotsVNode = slots.default()
    let headerSlotsVnode = null
    // 如果传递了header插槽,就调用header插槽
    if (slots.header) {
      headerSlotsVnode = slots.header({
        title: title.value
      })
    }
    // 但是要注意,调用了之后,不见得有值,所以要判断一下
    if (!headerSlotsVnode.length) {
      headerSlotsVnode = h('div', null, '默认标题')
    }
    return () =>
      h('div', { class: styles.card }, [
        h('div', { class: styles['card-header'] }, headerSlotsVnode),
        h('div', { class: styles['card-body'] }, deaultSlotsVNode)
      ])
  }
})

-EOF-

Released under the MIT License.