vue组件插槽

组件的插槽

组件本身就是一个容器,也可以是一个vue对象,也是一个虚拟DOM

普通插槽

组件本身是一个容器,这个容器本身是空的,当我们把需要封装的html结构装进去之后,我们可以认为这个容器被塞满了,那就意味着,我们无法想组件内部添加新的html结构进去,但是我们想在每次调用组件的时候需要渲染一些个性化的东西,这个时候我们就需要给组件做一个预留空间,这个预留空间就是插槽

html 复制代码
<body>
    <div id="app">
        <one>
            <p>我是子标题</p>
        </one>
    </div>
    <template id="temp1">
        <div>
            <h2>我是标题</h2>
        </div>
    </template>
</body>
<script src="js/vue.js"></script>
<script>
    let one = {
        template:"#temp1"
    }
    new Vue({
        el:"#app",
        components:{
            one
        }
    })
</script>

代码分析:

以上的代码渲染之后,我们在虚拟DOM中写入了一个p标签,着就是所谓的插入,但是并没有效果,因为我们并没有在one组件中预留空间,也就是插槽

如果想在组件内部预留插槽,使用 <slot></slot>

html 复制代码
<body>
    <div id="app">
        <one>
            <p>我是子标题</p>
            <p>我是子标题</p>
            <p>我是子标题</p>
            <p>我是子标题</p>
            <p>我是子标题</p>
            <p>我是子标题</p>
        </one>
    </div>
    <template id="temp1">
        <div>
            <h2>我是标题</h2>
            <slot>
            	<!-- 组件内预留给插槽的空间 -->
            </slot>
        </div>
    </template>
</body>
<script src="js/vue.js"></script>
<script>
    let one = {
        template:"#temp1"
    }
    new Vue({
        el:"#app",
        components:{
            one
        }
    })
</script>
一个插入点插入多个插槽

现在我们想让刚才的代码中前3个p标签出现在标题的上方,后面3个出现在标题的下方

html 复制代码
<body>
    <div id="app">
        <one>
            <p>我是子标题</p>
            <p>我是子标题</p>
            <p>我是子标题</p>
            <p>我是子标题</p>
            <p>我是子标题</p>
            <p>我是子标题</p>
        </one>
    </div>
    <template id="temp1">
        <div>
            <slot></slot>
            <h2>我是标题</h2>
            <slot></slot>
        </div>
    </template>
</body>
<script src="js/vue.js"></script>
<script>
    let one = {
        template:"#temp1"
    }
    new Vue({
        el:"#app",
        components:{
            one
        }
    })
</script>

代码分析:

上面的代码中,我们发现,在模板中的标题上方也制作了一个插槽slot,但是,从效果上来看只是单纯把插入的内容复制了一份,分别插入不同的插槽里面

其实我们上面写的都是默认插槽,把插槽语法写完成如下

html 复制代码
<div id="app">
    <one>
        <p slot="default">我是子标题</p>
        <p slot="default">我是子标题</p>
        <p slot="default">我是子标题</p>
        <p slot="default">我是子标题</p>
        <p slot="default">我是子标题</p>
        <p slot="default">我是子标题</p>
    </one>
</div>
<template id="temp1">
    <div>
        <slot name="default"></slot>
        <h2>我是标题</h2>
        <slot name="default"></slot>
    </div>
</template>

默认情况下,所有的slot都必须要指定一个name,只是如果我们不自己指定的话,系统会给我们指定一个默认的名称default

具名插槽

在上面的插槽中,我们所有的slot如果在不指定name的情况下全都是default,但是这个name属性可以设置的,如果设置一些其他的值,我们就把这个插槽叫做具名插槽

html 复制代码
<div id="app">
    <one>
        <p slot="top">我是子标题</p>
        <p slot="top">我是子标题</p>
        <p slot="top">我是子标题</p>
        <p slot="bottom">我是子标题</p>
        <p slot="bottom">我是子标题</p>
        <p slot="bottom">我是子标题</p>
    </one>
</div>
<template id="temp1">
    <div>
        <slot name="top"></slot>
        <h2>我是标题</h2>
        <slot name="bottom"></slot>
    </div>
</template>

代码分析:

在上面的代码中,我们可以为插槽取一个名字,从而实现一对多,或者多对一的插入,当插槽有了名字之后,我们就可以在插入的时候指定插入到某一个插槽中

  • 我们组件里面定义插槽的时候使用slot标签,并且这个标签上面定义name属性,成为具名插槽
  • 在调用组件的时候,我们可以向指定的插槽插入内容,只需要在这个插入的元素上面添加一个slot="插槽名"即可
  • 具名插槽是可以多次使用的,所以我们可以把上面的top复制一份放到bottom的下面,这样上面三个p标签也会出现在下面的插槽里面

插槽作用域

html 复制代码
<body>
    <div id="app">
        <one>
            <p>我想要拿到组件内部的userName</p>
        </one>
    </div>
    <template id="temp1">
        <div>
            <h2>我是一个组件</h2>
            <slot>
                <!-- 组件的预留空间 -->
            </slot>
        </div>
    </template>
</body>
<script src="js/vue.js"></script>
<script>
    let one = {
        template:"#temp1",
        data(){
            return {
                userName:"zhangsan"
            }
        }
    }
    new Vue({
        el:"#app",
        components:{
            one
        }
    })
</script>

之前我们一直都是外部的数据传递给内部,如果要把组件内部的数据传递给外部,我们可以:

1、利用对象的堆栈原理

2、自定义事件

注意:

我们现在要做一个区分,我们是可以把数据渲染在组件里面的,也可以渲染在插槽里面,但是这两种方式在向组件外部传值的时候是有区别的,我们上面说的这两种方法,只针对在组件内渲染的,如果是渲染在组件的插槽内部的,我们可以通过插槽作用域取拿

比如我们现在要userName的值传递到外面,我们可以在插入的标签上面添加一个slot-scope="scope"

html 复制代码
<body>
    <div id="app">
        <one>
            <div slot-scope="scope">
                <p>{{scope.userName}}</p>
                <p>{{scope.age}}</p>
            </div>            
        </one>
    </div>
    <template id="temp1">
        <div>
            <h2>我是一个组件</h2>
            <slot :user-name="userName" :age="18">
                <!-- 组件的预留空间 -->
            </slot>
        </div>
    </template>
</body>
<script src="js/vue.js"></script>
<script>
    let one = {
        template:"#temp1",
        data(){
            return {
                userName:"zhangsan"
            }
        }
    }
    new Vue({
        el:"#app",
        components:{
            one
        }
    })
</script>

插槽作用域旧版本语法

html 复制代码
<div id="app">
        <one>
            <div slot="footer" slot-scope="scope">
                <p>{{scope.userName}}</p>
                <p>{{scope.age}}</p>
            </div>            
        </one>
    </div>
    <template id="temp1">
        <div>
            <h2>我是一个组件</h2>
            <slot name="footer" :user-name="userName" :age="18">
                <!-- 组件的预留空间 -->
            </slot>
        </div>
    </template>

新版本语法

html 复制代码
<one>
    <template v-slot:footer="scope">
        <p>{{scope.userName}}</p>
        <p>{{scope.age}}</p>
    </template>            
</one>

最新语法

html 复制代码
<one>
    <template #footer="{userName,age}">
        <p>{{userName}}</p>"
        <p>{{age}}</p>
    </template>            
</one>

代码分析:

最新语法可以直接解构获取,并且v-slot这个指令也直接使用#来替代,简化代码

相关推荐
问道飞鱼5 分钟前
【前端知识】强大的js动画组件anime.js
开发语言·前端·javascript·anime.js
k09336 分钟前
vue中proxy代理配置(测试一)
前端·javascript·vue.js
傻小胖8 分钟前
React 脚手架使用指南
前端·react.js·前端框架
程序员海军20 分钟前
2024 Nuxt3 年度生态总结
前端·nuxt.js
m0_7482567830 分钟前
SpringBoot 依赖之Spring Web
前端·spring boot·spring
web135085886351 小时前
前端node.js
前端·node.js·vim
m0_512744641 小时前
极客大挑战2024-web-wp(详细)
android·前端
若川1 小时前
Taro 源码揭秘:10. Taro 到底是怎样转换成小程序文件的?
前端·javascript·react.js
潜意识起点1 小时前
精通 CSS 阴影效果:从基础到高级应用
前端·css
奋斗吧程序媛1 小时前
删除VSCode上 origin/分支名,但GitLab上实际上不存在的分支
前端·vscode