美文网首页
Vue组件基础内容:插槽、动态组件(二)

Vue组件基础内容:插槽、动态组件(二)

作者: 爱妃给朕躺下 | 来源:发表于2021-06-07 00:06 被阅读0次

    插槽

    插槽内容

    建立一个组件,组件的使用通常用其名字组成的标签,例如<myComponent>组件标签里的内容</myComponent>,在这两个标签的中间,我们可以插入一些内容,这些内容是根据需求可要可不要的,但谁知道到底什么时候会需要呢?并且,自定义组件标签便是组件模板本身,不同于原生标签那样简单。如果组件标签会被渲染成组件模板,那组件标签内的内容该渲染在哪里?于是,插槽的作用显现了。在模板内某个想要插入组件标签内容的地方,放置一对<slot></slot>,这个标签被称为插槽。插槽功能很强大,第一个功能便是上述场景,<slot></slot>可在模板某个位置事先安插,用来动态盛放并在渲染时显示组件标签里的内容。

    // 组件及其标签内容
    <myComponent>组件标签里的内容</myComponent>
    
    // myComponent 组件本身
    <template>
    <div id="app">
    <slot></slot>
    </div>
    </template>
    
    // 渲染后
    <div id="app">
    组件标签里的内容
    </div>
    

    后备内容

    与第一种作用相反,插槽作为内容分发工具,不仅仅可以作为预留空间承载组件标签里的内容,也可以提前放置内容作为组件标签内容的预备。

    <button type="submit">
      <slot>Submit</slot>
    </button>
    
    // 组件标签有内容
    <submit-button>
      Save
    </submit-button>
    
    // 组件标签无内容
    <submit-button>
    </submit-button>
    
    // 渲染后的 element
    <button type="submit">
      Submit
    </button>
    

    插槽编译作用域

    上面提到,组件标签里可以插入内容,只是需要插槽来呈现这些内容,插槽也可以设置后备内容,当组件标签没有内容时作为备用选择。

    当作为呈现子组件标签内容的功能时,子组件标签里如果使用了父组件作用域的数据,插槽作为承载工具可以接收到这些内容。但如果插槽作为后备内容的作用时,插槽使用了所在子组件作用域的数据,希望可以作为子组件标签的后备内容时,是没办法传递这些数据给子组件标签的,因为子组件标签已经处在了父级作用域:

    // 子组件模板
    <div class="hello">
        <slot></slot>
      </div>
    
    // 子组件标签
    <HelloWorld>
          {{message}}
    </HelloWorld>
    
    // 子组件标签所在父组件的 data
    data () {
        return {
          message: '我是父组件内容'
        }
    }
    
    // 以上内容可以渲染
    // 子组件模板
    <div class="hello">
        <slot>{{ message }}</slot>
    </div>
    
    // 子组件标签
    <HelloWorld>
    </HelloWorld>
    
    // 子组件的 data
    data () {
        return {
          message: '我是子组件的内容'
        }
    }
    
    // 插槽里的 message 作为后备内容无法传递给子组件标签
    

    具名插槽

    在前面,我们提到插槽的两个作用,一个是为组件标签提供预设内容,一个是作为承载组件标签内容的预留空间,刚好是一个互补的作用。在这里,具名插槽的意思就是插槽有名字,它的渲染位置可以通过名字来确定。这个具名插槽的作用发挥的是第二种作用:作为承载组件标签内容的预留空间。比如,组件模板已经比较臃肿了,但我又想在模板里加上一些东西,这时我可以在组件标签里设置了一些内容,希望被渲染到组件模板的具体某个位置,便可以使用具名插槽。实现在组件标签里铺设内容;

    <base-layout>
      <template v-slot:header>
        <h1>Here might be a page title</h1>
      </template>
    
      <p>A paragraph for the main content.</p>
      <p>And another one.</p>
    
      <template v-slot:footer>
        <p>Here's some contact info</p>
      </template>
    </base-layout>
    

    可以看到这里的组件标签里的东西类似于一个迷你模板,在上面有一个指令:v-slot,指定了该“模板”的渲染在哪个插槽的位置:

    <div class="container">
      <header>
        <slot name="header"></slot>
      </header>
      <main>
        <slot></slot>
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
    

    这是 base-layout 的模板,可以在这里实现安插插槽,并给插槽一个名字,组件标签里的迷你模板将会被渲染到指定的插槽所在的位置。没有给定插槽名字的插槽拥有一个默认名字:default。

    作用域插槽

    这个插槽释放了插槽的强大能力。在前面,我们提到,子组件标签在父组件里渲染,当希望 slot 可以使用子组件的数据设置后备内容时,子组件标签并不能接收到子组件里的 data 等数据。

    但作用域插槽突破了这个限制,可在子组件插槽添加属性:v-bind:user="user"

    <div class="helloworld">
        <slot v-bind:user="user"></slot>
      </div>
    

    这样,子组件的数据被传递到一个 slotProps 的对象上,当然,这个名字可以自定义。可以在子组件标签里这么使用:

    <HelloWorld>
        <template v-slot:default="slotProps">
            {{ slotProps.user.firstName }}
        </template>
    </HelloWorld>
    

    这样,子组件里的数据便可以子组件标签里使用。同样的,让我们串联起前面具名插槽的知识,这里的 default 指定了插槽的名字,可以更改插槽名字指定使用哪个插槽作为渲染的容器。

    但不得不吐槽的是,在子组件里的数据,费尽九牛二虎之力传到子组件标签所在父组件的作用域里,但渲染后这些内容却又是被渲染回子组件里。这样的折腾实在不知有何意义。也不知有何使用场景,暂且可搁置在一旁。

    插槽的作用其实十分强大,但目前来说暂时没有驾驭它的能力,对插槽的使用场景尚无经验,可对上述基本功能做下掌握。

    动态组件

    想象一下以下场景,点击一个 tab 切换不同的页面。这是一个十分常见的需求,可以使用不同的组件承载不同的内容,点击以下切换组件。除了 v-if 的实现方式,还可以使用 is attribute 来切换不同的组件官方案例
    现在,已经可以通过 is attribute 实现组件的切换。但你会注意到,如果你选择了一篇文章,切换到 Archive 标签,然后再切换回 Posts,是不会继续展示你之前选择的文章的。这是因为你每次切换新标签的时候,Vue 都创建了一个新的 currentTabComponent 实例。

    但如果我们希望切换时组件的状态会被保留,就需要用到 keep-alive 元素的强大能力了。

    <!-- 失活的组件将会被缓存!-->
    <keep-alive>
      <component v-bind:is="currentTabComponent"></component>
    </keep-alive>
    

    这样,组件状态就会被缓存。当你来回切换组件时,你在组件上的操作状态将会被保留,组件不会每次都被刷新,这对于一些无更新的组件来说实现了高效复用。

    相关文章

      网友评论

          本文标题:Vue组件基础内容:插槽、动态组件(二)

          本文链接:https://www.haomeiwen.com/subject/rqhosltx.html