我们在构建页面过程中一般会把用的比较多的公共的部分抽取出来作为一个单独的组件,但是在实际使用这个组件的时候却又不能完全的满足需求,我希望在这个组件中添加一点东西,这时候我们就需要用到插槽来分发内容。

以下文章来自掘金 作者:JH30K 链接:https://juejin.im/post/5ed61cd86fb9a047a43444d6

文章目录

  • 一、前言
  • 二、插槽是什么
  • 三、插槽的作用
  • 四、插槽的分类
    • 1. 默认插槽
    • 2. 具名插槽
    • 3. 作用域插槽

一、前言

vue官方文档中在"组件基础"内容中提到组件可以通过插槽分发内容,那插槽是怎么使用的呢?它要解决什么场景的问题呢? 我们在构建页面过程中一般会把用的比较多的公共的部分抽取出来作为一个单独的组件,但是在实际使用这个组件的时候却又不能完全的满足需求,我希望在这个组件中添加一点东西,这时候我们就需要用到插槽来分发内容。 注意:以下的所有内容是基于vue版本 2.6.0 起

二、插槽是什么

下面看一个例子 写一个父组件: test.vue

<template><div><div>大家好我是父组件</div><myslot><p>测试一下吧内容写在这里了能否显示</p></myslot></div>
</template><script>import myslot from './myslot';export default {components: {myslot}}
</script><style>
</style>

写一个子组件:myslot.vue

<template><div><div>我是子组件</div></div>
</template><script>
</script><style>
</style>

运行代码,发现,最终渲染的效果是

大家好我是父组件
我是子组件

那如果我想实现显示父组件中p标签的内容怎么办 修改子组件:myslot.vue

<template><div><div>我是子组件</div><p>现在测试一下slot</p><slot></slot></div>
</template><script>
</script><style>
</style>

运行代码,可以看到以下效果

大家好我是父组件
我是子组件
现在测试一下slot
测试一下吧内容写在这里了能否显示

官方文档对于插槽的应用场景是这样描述的: 我们经常需要向一个组件传递内容 Vue 自定义的 <slot> 元素让这变得非常简单 只要在需要的地方加入插槽就行了——就这么简单! 结合上面的例子来理解就是这样的:

  1. 父组件在引用子组件时希望向子组价传递模板内容<p>测试一下吧内容写在这里了能否显示</p>
  2. 子组件让父组件传过来的模板内容在所在的位置显示
  3. 子组件中的<slot>就是一个槽,可以接收父组件传过来的模板内容,<slot> 元素自身将被替换
  4. <myslot></myslot>组件没有包含一个 <slot> 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃

三、插槽的作用

让用户可以拓展组件,去更好地复用组件和对其做定制化处理

四、插槽的分类

1. 默认插槽

在一个 <submit-button> 组件中:

<button type="submit"><slot></slot>
</button>

我们可能希望这个 <button> 内绝大多数情况下都渲染文本“Submit”,但是有时候却希望渲染文本为别的东西,那怎么实现呢? 我们可以将“Submit”作为后备内容,我们可以将它放在 <slot> 标签内:

<button type="submit"><slot>Submit</slot>
</button>

现在当我在一个父级组件中使用 <submit-button> 并且不提供任何插槽内容时:

<submit-button></submit-button>

后备内容“Submit”将会被渲染:

<button type="submit">Submit
</button>

但是如果我们提供内容:

<submit-button>Save
</submit-button>

则这个提供的内容将会被渲染从而取代后备内容:

<button type="submit">Save
</button>

2. 具名插槽

有时我们写了一个子组件,我们希望

<template><div class="container"><header><!-- 我们希望把页头放这里 --></header><main><!-- 我们希望把主要内容放这里 --></main><footer><!-- 我们希望把页脚放这里 --></footer></div>
</template>

对于这样的情况,<slot> 元素有一个特殊的 attribute:name。这个 attribute 可以用来定义额外的插槽:

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

一个不带 name 的 <slot> 出口会带有隐含的名字“default”。 父组件在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称:

<template><myslot><div>大家好我是父组件</div><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 footer info</p></template></myslot>
</template><script>import myslot from './myslot';export default {components: {myslot}}
</script>
<style>
</style>

最终的渲染结果可以看到

Here might be a page title
大家好我是父组件
A paragraph for the main content.And another one.Here's footer info

父组件中会向子组件中具名传递对应的模板内容,而没有指定名字的模板内容会传递给子组件中不带 name 的 <slot> 当然,如果父组件中

<template v-slot:default><p>A paragraph for the main content.</p><p>And another one.</p>
</template>

同样是传递给子组件中不带 name 的 <slot> 注意: v-slot 只能添加在
<template> 上 具名插槽在书写的时候可以使用缩写,v-slot用#来代替

<template><myslot><div>大家好我是父组件</div><template #header><h1>Here might be a page title</h1></template><p>A paragraph for the main content.</p><p>And another one.</p><template #footer><p>Here's footer info</p></template></myslot>
</template><script>import myslot from './myslot';export default {components: {myslot}}
</script>

3. 作用域插槽

这里主要解决的是父组件在向子组件插槽传递模板内容时存在访问子组件数据的问题 还记得默认插槽吗?如果子组件中写在 <slot> 标签内后备内容是与 该组件的data属性双向数据绑定的

<template><div><span><slot>{{user.firstName}}</slot></span></div>
</template><script>export default {data () {return {user:{firstName:'gerace',lastName:'haLi'}}}}
</script>
<style>
</style>

父组件在引用子组件时,希望能够换掉备用内容

<template><myslot>{{ user.firstName }}</myslot>
</template><script>import myslot from './myslot';export default {components: {myslot}}
</script>
<style>
</style>

运行代码这时你会发现提示报错

Property or method "user" is not defined on the instance but referenced during render.
TypeError: Cannot read property 'firstName' of undefined

这里为什么?vue官方文档给出了答案 父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的 那应该怎么解决这个问题? 为了让 user 在父级的插槽内容中可用,我们可以将 user 作为 <slot> 元素的一个 attribute 绑定上去:

<span><slot v-bind:user="user">{{ user.lastName }}</slot>
</span>

绑定在 <slot> 元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字:

<template><myslot><template v-slot:default="slotProps">{{ slotProps.user.firstName }}</template></myslot>
</template><script>import myslot from './myslot';export default {components: {myslot}
</script>
<style>
</style>

上面例子,我们选择将包含所有插槽 prop 的对象命名为 slotProps,但你也可以使用任意你喜欢的名字。 针对上面只给默认插槽传递模板内容的例子,在写法上可以采用默认插槽的缩写语法

<template><myslot v-slot:default="slotProps">{{ slotProps.user.firstName }}</myslot>
</template><script>import myslot from './myslot';export default {components: {myslot}
</script>
<style>
</style>

上面代码也可以直接改为

<template><myslot v-slot="slotProps">{{ slotProps.user.firstName }}</myslot>
</template>

注意: 默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确:

<template><myslot v-slot="slotProps">{{ slotProps.user.firstName }}<template v-slot:other="otherSlotProps">slotProps is NOT available here</template></myslot>
</template>

下面再看一下多个插槽的情况 子组件


```c
<template><div><span><slot v-bind:userData="user" name="header">{{ user.msg }}</slot><slot v-bind:hobbyData="hobby" name="footer">{{ hobby.fruit }}</slot></span></div>
</template><script>export default {data () {return {user:{firstName: 'gerace',lastName: 'haLi',},hobby:{fruit: "apple",color: "blue"}}}}
</script>
<style>
</style>

``

父组件

<template><myslot><template v-slot:header="slotProps">{{ slotProps.userData.firstName }}</template><template v-slot:footer="slotProps">{{ slotProps.hobbyData.fruit }}</template></myslot>
</template><script>import myslot from './myslot';export default {components: {myslot}
</script>
<style>
</style>

针对多个插槽的情况,在写法上可以解构插槽prop,父组件的写法如下

<template><myslot><template v-slot:header="{userData}">{{ userData.firstName }}</template><template v-slot:footer="{hobbyData}">{{ hobbyData.fruit }}</template></myslot>
</template><script>import myslot from './myslot';export default {components: {myslot}}
</script>
<style>
</style>

在具名插槽的介绍部分有讲过,具名插槽可以使用缩写,v-slot可以使用#来代替,所以以上代码可以写成:

<template><myslot><template #header="{userData}">{{ userData.firstName }}</template><template #footer="{hobbyData}">{{ hobbyData.fruit }}</template></myslot>
</template><script>import myslot from './myslot';export default {components: {myslot}}
</script>
<style>
</style>

但是需要注意的是该缩写只在其有参数的时候才可用。这意味着以下语法是无效的:

<!-- 这样会触发警告 -->
<template><myslot><template #="{userData}">{{ userData.firstName }}</template><template #="{hobbyData}">{{ hobbyData.fruit }}</template></myslot>
</template>

vue源码学习第六篇--插槽(slot)相关推荐

  1. RT-Thread源码学习第六篇,线程调度器(1)

    2019独角兽企业重金招聘Python工程师标准>>> 调度器是操作系统的核心,其主要功能就是实现线程的切换,即从就绪列表里面找到优先级最高的线程,然后去执行该线程. 要实现线程调度 ...

  2. VUE源码学习第一篇--前言

    一.目的 前端技术的发展,现在以vue,react,angular为代表的MVVM模式以成为主流,这三个框架大有三分天下之势.react和angular有facebook与谷歌背书,而vue是以一己之 ...

  3. vue源码学习--vue源码学习入门

    本文为开始学习vue源码的思路整理.在拿到vue项目源码的之后看到那些项目中的文件夹,会很困惑,不知道每个文件夹内的世界,怎么变换,怎样的魔力,最后产生了vue框架.学习源码也无从学起.我解决了这些困 ...

  4. Vue源码学习之Computed与Watcher原理

    前言  computed与watch是我们在vue中常用的操作,computed是一个惰性求值观察者,具有缓存性,只有当依赖发生变化,第一次访问computed属性,才会计算新的值.而watch则是当 ...

  5. Vue源码学习 - 组件化(三) 合并配置

    Vue源码学习 - 组件化(三) 合并配置 合并配置 外部调用场景 组件场景 总结 学习内容和文章内容来自 黄轶老师 黄轶老师的慕课网视频教程地址:<Vue.js2.0 源码揭秘>. 黄轶 ...

  6. Vue源码学习 - 组件化一 createComponent

    Vue源码学习 - 组件化一 createComponent 组件化 createComponent 构造子类构造函数 安装组件钩子函数 实例化 VNode 总结 学习内容和文章内容来自 黄轶老师 黄 ...

  7. Vue源码解读(六):update和patch

    Vue 的 _update 是实例上的一个私有方法,主要的作用就是把 VNode 渲染成真实的 DOM ,它在首次渲染和数据更新的时候被调用.在数据更新的时候会发生新 VNode 和 旧 VNode ...

  8. Vue源码学习 - 准备工作

    Vue源码学习 - 准备工作 准备工作 认识Flow 为什么用 Flow Flow 的工作方式 类型推断 类型注释 数组 类和对象 null Flow 在 Vue.js 源码中的应用 flow实践 总 ...

  9. Vue源码学习之initInjections和initProvide

    Vue源码学习之initInjections和initProvide 在进行源码阅读之前先让我们了解一个概念:provide/inject,这个是Vue在2.2.0版本新增的一个属性,按照Vue官网的 ...

最新文章

  1. HGOI 20190709 题解
  2. stdio.h头文件中申明的基本函数
  3. Apache - AH00526 – server.crt
  4. 提供推荐——协作型过滤
  5. 用Node.JS+MongoDB搭建个人博客(成品展示)
  6. 从零开始学习docker(十九)Swarm mode 集群服务间通信--RoutingMesh
  7. 【Boost】boost库asio详解2——strand与io_service区别
  8. 交叉编译指定运行时库路径_运行时vs编译时类路径
  9. Netlink 内核实现分析(二):通信
  10. React router 路由 入门安装
  11. 机顶盒网络包获取方式
  12. 吴伯凡-认知方法论-认知是一个长期修炼的过程
  13. 飞猪平台用户行为分析—python
  14. Maven POM介绍
  15. 通过Vue+flvjs在HTML5中播放flv格式视频文件—demo及api
  16. 抽奖随机滚动_仅需2分钟,使用excel制作一个抽奖小工具,再也不用为抽奖发愁了...
  17. Java数据爬取——爬取携程酒店数据(二)
  18. 【python数据分析】数据建模之 PCA主成分分析
  19. VUE中的pug使用
  20. Android编写一个视频监控App

热门文章

  1. 软件的设计原则,设计模式以及软件的质量属性
  2. 安装ios beta版
  3. java计算机毕业设计基于安卓Android的天文观星系统app uniapp 小程序
  4. 网站运营推广:网站取名与做好定位很关健
  5. 电气设备安装技术交底
  6. 华为4G移动路由器管理后台加密算法
  7. Android捷径接口,捷径接口
  8. 台式计算机如何设置三道密码,给win7电脑设置三级密码的详细步骤
  9. java 调用controller_java调用controller方法
  10. 黑马程序员 骑士飞行棋源码