深入理解Vue中的插槽、内容分发、具名插槽

广告:宝塔服务器面板,一键全能部署及管理,送你10850元礼包,点我领取~~~

深入理解Vue中的插槽、内容分发、具名插槽

本篇文章给大家分享Vue进阶技巧,深入理解下Vue中的插槽、内容分发、具名插槽,希望对大家有所帮助。

插槽 Slots简介

Vue中组件的数据可以通过props进行传递,或者通过事件的方式进行获取传递,但当需要接收模板内容(任意合法的模板内容,代码片段、Vue组件)时,就需要使用插槽来实现了。当然也可以通过函数式编程间接实现;【相关推荐:vuejs视频教程】

可以将插槽理解为js中的函数进行编译
// 父元素传入插槽内容FancyButton('Click me!')// FancyButton 在自己的模板中渲染插槽内容function FancyButton(slotContent) {    return `<button class="fancy-btn">      ${slotContent}    </button>`}
登录后复制最好的封装方式是将共性抽取到组件中,将不同点暴露为插槽 - 抽取共性,保留不同父组件模板的所有东西都会在父组件作用域中编译,子组件模板的所有东西都会在子组件作用域内编译 - 编译作用域slot-scope浅析

常规的slot可以用于自定义组件的模板,但只是限制于固定的模板,无法自定义内部的具体的某一项,即常规的slot无法实现对组件循环体的每一项进行不同的内容分发,此时可以通过slot-scope进行实现,本质上和slot一样,不同点在于可以进行参数传递

//普通的组件定义<ul>    <li v-for="book in books" :key="book.id">    {{ book.name }}    </li></ul>//slot-scope组件定义<ul>    <li v-for="book in books" :key="book.id">        <slot :book="book" name="bookInfo">            <!-- 默认内容 -->            {{ book.name }}        </slot>    </li></ul>//父组件使用<book-list :books="books">    <template slot-scope="slotProps" slot="bookInfo">        <span v-if="slotProps.book.sale">限时优惠</span>        {{ slotProps.book.name }}    </template></book-list>
登录后复制

使用slot-scope时,当父组件使用该API,对应的插槽会替换模板中的slot进行展示

常用API浅析具名插槽

在组件中定义多个插槽出口可以兼容多个不同需求的兼容性,使得多个插槽内容传入到各自的插槽出口中;当插槽中配置了name属性时,此插槽就被称为具名插槽(named slots),没有提供name的插槽会隐式命名为「default」

v-slot 可以简写为#,其值对应于插槽中的name对应的值;当在一个组件中同时存在默认插槽和具名插槽时,所有位于顶级的非template节点都被隐式的视为默认插槽的内容,因此可以省略默认插槽的template节点标签;
<Com>    <!-- 隐式的默认插槽 -->    <!-- <p>A paragraph for the main content.</p>    <p>And another one.</p> -->    <template #default>        <p>A paragraph for the main content.</p>        <p>And another one.</p>    </template>    <template #footer>        <p>Here's some contact info</p>    </template></Com>
登录后复制作用域插槽

普通的插槽,是无法获取其他作用域下的数据的,即父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域但在某些情况下,插槽中的内容想要同时使用父组件和子组件内的数据,可以通过像组件传递数据props那样,让子组件在渲染时将一部分数据提供给插槽,这样在组件外部(父组件)中就可以使用子组件中的数据了-通过slot的方式

子组件传入插槽的 props 作为了 v-slot 指令的值,可以在插槽内的表达式中访问,其中name是Vue特意保留的attribute,不会作为props进行传递

数据传递
//子组件<template>     <slot :shopInfo="shopInfo" :userInfo="userInfo"></slot> </template>
登录后复制数据接收默认插槽接收
//父组件 - 使用方<MyCom v-slot="{shopInfo,userInfo}">  {{ shopInfo }} {{ userInfo }}</MyCom>
登录后复制具名插槽接收
<MyCom>  <template v-slot:header="shopInfo">    {{ shopInfo }}  </template>  <template #default="introduction">    {{ introduction }}  </template>  <template #footer="userInfo">    {{ userInfo }}  </template></MyCom>
登录后复制使用slot-scope时,用最后一个slot-scope替换模板中的slot
<cpm>    <!-- 不显示 -->    <div>555</div>    <!-- 不显示 -->    <div slot-scope="scope">        <div>{{scope.name}}</div>    </div>    <!-- 显示 -->    <div slot-scope="scope">        <div>{{scope}}</div>        <div>{{scope.name}}</div>        <div>{{scope.age}}</div>    </div></cpm>
登录后复制使用作用域插槽时,可以实现既可以复用子组件slot,又可以使得slot的内容不一致,它允许使用者传递一个模板而不是已经渲染好的元素给插槽,所谓作用域是指模板虽然在父级作用域中渲染的,但是却可以拿到子组件的数据常规的v-bind需要携带参数key值进行传递,例如v-bind:info = '123';但是有时候会省略这个key值,直接进行传递数据,如v-bind = 'item',这种用法会将整个对象的所有属性都绑定到当前元素上,适用于需要绑定的属性过多的场景
// data: {//     shapes: [//         { name: 'Square', sides: 4 },//         { name: 'Hexagon', sides: 6 },//         { name: 'Triangle', sides: 3 }//     ],//     colors: [//         { name: 'Yellow', hex: '#F4D03F', },//         { name: 'Green', hex: '#229954' },//         { name: 'Purple', hex: '#9B59B6' }//     ]// }<my-list title="Shapes" :items="shapes">    <template scope="shape">        <div>{{ shape.name }} <small>({{ shape.sides }} sides)</small></div>    </template></my-list><my-list title="Colors" :items="colors">    <template scope="color">        <div>            <div class="swatch" :style="{ background: color.hex }"></div>            {{ color.name }}        </div>    </template></my-list><div id="my-list">    <div class="title">{{ title }}</div>    <div class="list">        <div v-for="scope in items">            <slot v-bind="scope"></slot>        </div>    </div></div>Vue.component('my-list', {    template: '#my-list',    props: [ 'title', 'items' ]});
登录后复制递归组件

递归组件就是指组件在模板中调用自己,由于是组件自身调用,就不能像常规组件定义一样,可以省略组件的name配置,组件的递归需要依赖于自身的name配置(name还用于遍历组件的name选项来查找组件的实例);

满足条件需要给组件设置一个name属性需要有一个明确的结束条件
<template>    <div>        <my-component :count="count + 1" v-if="count        <= 5"></my-component>    </div></template><script>export default {    name:'my-component',    props: {        count: {            type: Number,            default: 1        }    }}</script>
登录后复制动态组件

有时候我们需要根据一些条件,动态的切换/选择某个组件,在函数式组件中,没有上下文的概念,常用于程序化的在多个组件中选择一个,可以间接的解决动态切换组件的需求,缺点是基于js对象进行开发,不方便开发;Vue官方提供了一个内置组件<component>和is的属性,用来解决上述的问题

<component :is="component"></component>//component 就是js import进的组件实例,其值可以是标签名、组件名、直接绑定一个对象等
登录后复制为了使得组件具有缓存作用,可以使用的内置组件,这样只要不离开当前页面,切换到其他组件后deforeDestory不会执行,因此组件具有了缓存功能拓展components的第二种写法

常规的组件components是直接通过引用定义好的组件进行展示的,也可以直接在当前组件内定义,然后通过配置components进行渲染

//普通的组件定义<ul>    <li v-for="book in books" :key="book.id">    {{ book.name }}    </li></ul>//slot-scope组件定义<ul>    <li v-for="book in books" :key="book.id">        <slot :book="book" name="bookInfo">            <!-- 默认内容 -->            {{ book.name }}        </slot>    </li></ul>//父组件使用<book-list :books="books">    <template slot-scope="slotProps" slot="bookInfo">        <span v-if="slotProps.book.sale">限时优惠</span>        {{ slotProps.book.name }}    </template></book-list>0
登录后复制Web Component <slot> 简介

HTML的slot元素,是Web Components技术套件的一部分,是Web组件内的一个占位符,该占位符可以在后期使用自己的标记语言进行填充,这样可以创建单独的DOM树,并将其与其他的组件组合在一起 -- MDN

常见的填充Web组件的shadow DOM的模板有template和slot

模板 - Templates

需要在网页上重复的使用相同的标记结构时,为了避免CV的操作可以通过模板的方式进行实现需要注意的是模板 - Template 和其内部的内容是不会在DOM中呈现的,可以通过js进行访问并添加到DOM中,从而在界面上进行展示
//普通的组件定义<ul>    <li v-for="book in books" :key="book.id">    {{ book.name }}    </li></ul>//slot-scope组件定义<ul>    <li v-for="book in books" :key="book.id">        <slot :book="book" name="bookInfo">            <!-- 默认内容 -->            {{ book.name }}        </slot>    </li></ul>//父组件使用<book-list :books="books">    <template slot-scope="slotProps" slot="bookInfo">        <span v-if="slotProps.book.sale">限时优惠</span>        {{ slotProps.book.name }}    </template></book-list>1
登录后复制
//普通的组件定义<ul>    <li v-for="book in books" :key="book.id">    {{ book.name }}    </li></ul>//slot-scope组件定义<ul>    <li v-for="book in books" :key="book.id">        <slot :book="book" name="bookInfo">            <!-- 默认内容 -->            {{ book.name }}        </slot>    </li></ul>//父组件使用<book-list :books="books">    <template slot-scope="slotProps" slot="bookInfo">        <span v-if="slotProps.book.sale">限时优惠</span>        {{ slotProps.book.name }}    </template></book-list>2
登录后复制可以配合Web Component一起使用,实现纯js自定义的组件
//普通的组件定义<ul>    <li v-for="book in books" :key="book.id">    {{ book.name }}    </li></ul>//slot-scope组件定义<ul>    <li v-for="book in books" :key="book.id">        <slot :book="book" name="bookInfo">            <!-- 默认内容 -->            {{ book.name }}        </slot>    </li></ul>//父组件使用<book-list :books="books">    <template slot-scope="slotProps" slot="bookInfo">        <span v-if="slotProps.book.sale">限时优惠</span>        {{ slotProps.book.name }}    </template></book-list>3
登录后复制后续的样式逻辑也需要加在template中,方便通过后续的相关逻辑(如template.content获取到然后打入到指定的容器中)

Web Component简介

Web Component的一个很重要的属性就是封装 - 可以将标记结构、样式和行为影藏起来,并于界面上的其他代码隔离开来,保证代码的独立性

Web Component标准非常重要的一个特性是,使得开发者可以将HTML页面的功能封住成custom elements(自定义标签)

customElements 接口用来实现一个对象,允许开发者注册一个custom elements的信息,返回已注册的自定义标签的信息;

customElements.define方法用来注册一个custom element,接收三个参数

参数一:表明创建元素的名称,其注册的名称不能简单的单词,需要由短划线进行拼接

参数二:用于定义元素行为的类

参数三:一个包含extends属性配置的配置对象,可选,指定了所创建的自定义元素是继承于哪个内置的元素,可以继承任何内置的元素;

//普通的组件定义<ul>    <li v-for="book in books" :key="book.id">    {{ book.name }}    </li></ul>//slot-scope组件定义<ul>    <li v-for="book in books" :key="book.id">        <slot :book="book" name="bookInfo">            <!-- 默认内容 -->            {{ book.name }}        </slot>    </li></ul>//父组件使用<book-list :books="books">    <template slot-scope="slotProps" slot="bookInfo">        <span v-if="slotProps.book.sale">限时优惠</span>        {{ slotProps.book.name }}    </template></book-list>4
登录后复制

可以使用ES2015的类实现

//普通的组件定义<ul>    <li v-for="book in books" :key="book.id">    {{ book.name }}    </li></ul>//slot-scope组件定义<ul>    <li v-for="book in books" :key="book.id">        <slot :book="book" name="bookInfo">            <!-- 默认内容 -->            {{ book.name }}        </slot>    </li></ul>//父组件使用<book-list :books="books">    <template slot-scope="slotProps" slot="bookInfo">        <span v-if="slotProps.book.sale">限时优惠</span>        {{ slotProps.book.name }}    </template></book-list>5
登录后复制

自定义标签的类型

类型一:Autonomous custom elements 是独立的元素,它不继承其他内建的 HTML 元素,可以直接通过标签的方式进行HTML使用<popup-info>,也可以通过js的方式进行使用document.createElement("popup-info")类型二:Customized built-in elements 继承自基本的 HTML 元素。在创建时,你必须指定所需扩展的元素,使用时,需要先写出基本的元素标签,并通过 is属性指定 custom element 的名称;<p is="word-count">document.createElement("p", { is: "word-count" })

参考文献 - MDN

shadow DOM简介

图解Shandow DOM

Shadow host:一个常规 DOM 节点,Shadow DOM 会被附加到这个节点上。

Shadow tree:Shadow DOM 内部的 DOM 树。

Shadow boundary:Shadow DOM 结束的地方,也是常规 DOM 开始的地方。

Shadow root: Shadow tree 的根节点。

shadow DOM主要是将一个隐藏的、独立的DOM树附加到常规的DOM树上,是以shadow DOM节点为起始根节点,在这个根节点的下方,可以是任意的元素,和普通的DOM元素一致

如常见的video标签,其内部的一些控制器和按钮等都是通过Shandow DOM进行维护的,开发者可以通过这个API进行自己独立的逻辑控制

基本用法

Element.attachShadow()方法可以将一个shadow DOM添加到任何一个元素上,接收一个配置对象参数,该对象有一个mode的属性,值可以是open - 可以通过外部js获取 Shadow DOM和closed - 外部不可以通过js进行获取 Shadow DOM
//普通的组件定义<ul>    <li v-for="book in books" :key="book.id">    {{ book.name }}    </li></ul>//slot-scope组件定义<ul>    <li v-for="book in books" :key="book.id">        <slot :book="book" name="bookInfo">            <!-- 默认内容 -->            {{ book.name }}        </slot>    </li></ul>//父组件使用<book-list :books="books">    <template slot-scope="slotProps" slot="bookInfo">        <span v-if="slotProps.book.sale">限时优惠</span>        {{ slotProps.book.name }}    </template></book-list>6
登录后复制当需要将一个shadow DOM添加到自定义的标签上时,可以在自定义的构造函数中添加如下逻辑;
//普通的组件定义<ul>    <li v-for="book in books" :key="book.id">    {{ book.name }}    </li></ul>//slot-scope组件定义<ul>    <li v-for="book in books" :key="book.id">        <slot :book="book" name="bookInfo">            <!-- 默认内容 -->            {{ book.name }}        </slot>    </li></ul>//父组件使用<book-list :books="books">    <template slot-scope="slotProps" slot="bookInfo">        <span v-if="slotProps.book.sale">限时优惠</span>        {{ slotProps.book.name }}    </template></book-list>7
登录后复制

(学习视频分享:web前端开发、编程基础视频)

以上就是深入理解Vue中的插槽、内容分发、具名插槽的详细内容,更多请关注9543建站博客其它相关文章!

9543建站博客
一个专注于网站开发、微信开发的技术类纯净博客。
作者头像
admin创始人

肥猫,知名SEO博客站长,14年SEO经验。

上一篇:如何解决uniapp图片路径错误问题
下一篇:项目中jquery怎么用

发表评论

关闭广告
关闭广告