松鼠乐园 松鼠乐园
  • 注册
  • 登录
  • 首页
  • 快捷入口
    • Vue
    • Tensorflow
    • Springboot
    • 语言类
      • CSS
      • ES5
      • ES6
      • Go
      • Java
      • Javascript
    • 工具类
      • Git
      • 工具推荐
    • 服务器&运维
      • Centos
      • Docker
      • Linux
      • Mac
      • MySQL
      • Nginx
      • Redis
      • Windows
    • 资源类
      • 论文
      • 书籍推荐
      • 后端资源
      • 前端资源
      • html网页模板
      • 代码
    • 性能优化
    • 测试
  • 重大新闻
  • 人工智能
  • 开源项目
  • Vue2.0从零开始
  • 广场
首页 › Vue › vue 深度长文之slot 篇

vue 深度长文之slot 篇

迦娜王
1年前Vue
377 0 1
vue 深度长文之slot 篇

今天我们将分析我们经常使用的 vue 功能 slot 是如何设计和实现的,本文将围绕 普通插槽 和 作用域插槽 以及 vue 2.6.x 版本的 v-slot 展开对该话题的讨论。当然还不懂用法的同学建议官网先看看相关 API 先。接下来,我们直接进入正文吧

普通插槽

首先我们看一个我们对于 slot 最常用的例子

vue 深度长文之slot 篇

然后我们直接使用,页面则正常显示一下内容

vue 深度长文之slot 篇

然后,这个时候我们使用的时候,对 slot 内容进行覆盖

this is slot custom content.

内容则变成下图所示

vue 深度长文之slot 篇

对于此,大家可能都能清楚的知道会是这种情况。今天我就将带领大家直接看看 vue 底层对 slot 插槽的具体实现。

vm.$slots

我们开始前,先看看 vue 的 Component 接口上对 $slots 属性的定义

$slots: { [key: string]: Array }; 

多的咱不说,咱直接 console 一下上面例子中的 $slots

vue 深度长文之slot 篇

剩下的篇幅将讲解 slot 内容如何进行渲染以及如何转换成上图内容

renderSlot

看完了具体实例中 slot 渲染后的 vm.$slots 对象,这一小篇我们直接看看 renderSlot 这块的逻辑,首先我们先看看 renderSlot 函数的几个参数都有哪些

vue 深度长文之slot 篇

这里我们先不看 scoped-slot 的逻辑,我们只看普通 slot 的逻辑。

const slotNodes = this.$slots[name]
nodes = slotNodes || fallback
return nodes

这里直接先取值 this.$slots[name] ,若存在则直接返回其对其的 vnode 数组,否则返回 fallback。看到这,很多人可能不知道 this.$slots 在哪定义的。解释这个之前我们直接往后看另外一个方法

vue 深度长文之slot 篇

看完 resolveSlots 的参数后我们接着往后过其中具体的逻辑。如果 children 参数不存在,直接返回一个空对象

const slots = {}
if (!children) {
 return slots
}

如果存在,则直接对 children 进行遍历操作

vue 深度长文之slot 篇

slots 获取到值后,则进行一些过滤操作,然后直接返回有用的 slots

vue 深度长文之slot 篇

我们从上面已经知道了 vue 对 slots 是如何进行赋值保存数据的。而在 src/core/instance/render.js 的 initRender 方法中则是对 vm.$slots 进行了初始化的赋值。

vue 深度长文之slot 篇

了解了是 vm.$slots 这块逻辑后,肯定有人会问:你这不就只是拿到了一个对象么,怎么把其中的内容给搞出来呢?别急,我们接着就来讲一下对于 slot 这块 vue 是如何进行编译的。这里咱就把 slot generate 相关逻辑过上一过,话不多说,咱直接上代码

vue 深度长文之slot 篇

注:上面的 slotName 在 src/compiler/parser/index.js 的 processSlot() 函数中进行了赋值,并且 父组件编译阶段用到的 slotTarget 也在这里进行了处理

vue 深度长文之slot 篇

随即在 genData() 中使用 slotTarget 进行 data 的数据拼接

if (el.slotTarget && !el.slotScope) {
 data  = `slot:${el.slotTarget},`
}

此时父组件将生成以下代码

vue 深度长文之slot 篇

然后当 el.tag 为 slot 的情况,则直接执行 genSlot()

else if (el.tag === \'slot\') {
 return genSlot(el, state)
}

按照我们举出的例子,则子组件最终会生成以下代码

vue 深度长文之slot 篇

作用域插槽

上面我们已经了解到 vue 对于普通的 slot 标签是如何进行处理和转换的。接下来我们来分析下作用域插槽的实现逻辑。

1、vm.$scopedSlots

了解之前还是老规矩,先看看 vue 的 Component 接口上对 $scopedSlots 属性的定义

$scopedSlots: { [key: string]: () => VNodeChildren };

其中的 VNodeChildren 定义如下:

declare type VNodeChildren = Array | string;

先来个相关的例子

vue 深度长文之slot 篇

然后进行使用

vue 深度长文之slot 篇

效果如下

vue 深度长文之slot 篇

从使用层面我们能看出来,子组件的 slot 标签上绑定了一个 text 以及 :msg 属性。然后父组件在使用插槽使用了 slot-scope 属性去读取插槽带的属性对应的值

注:提及一下 processSlot() 对于 slot-scope 的处理逻辑

vue 深度长文之slot 篇

从上面的代码我们能看出,vue 对于这块直接读取 slot-scope 属性并赋值给 AST 抽象语法树的 slotScope 属性上。而拥有 slotScope 属性的节点,会直接以 **插槽名称 name 为 key、本身为 value **的对象形式挂载在父节点的 scopedSlots 属性上

然后在 src/core/instance/render.js 的 renderMixin 方法中对 vm.$scopedSlots 则是进行了如下赋值:

if (_parentVnode) {
 vm.$scopedSlots = _parentVnode.data.scopedSlots || emptyObject
}

然后 genData() 里会进行以下逻辑处理

if (el.scopedSlots) {
 data  = `${genScopedSlots(el, el.scopedSlots, state)},`
}

紧接着我们来看看 genScopedSlots 中的逻辑

vue 深度长文之slot 篇

然后我们再来看看 genScopedSlot 是如何生成 render function 字符串的

vue 深度长文之slot 篇

我们把上面例子的 $scopedSlots 打印一下,结果如下

vue 深度长文之slot 篇

然后上面例子中父组件最终会生成如下代码

vue 深度长文之slot 篇

renderSlot(slot-scope)

上面我们提及对于插槽 render 逻辑的时候忽略了 slot-scope 的相关逻辑,这里我们来看看这部分内容

vue 深度长文之slot 篇

这里我们看看 renderHelps 里面的 _u ,即 resolveScopedSlots,其逻辑如下

vue 深度长文之slot 篇

这块会对 attrs 和 v-bind 进行,对于这块内容上面我已经提过了,要看请往上翻阅。结合我们的例子,子组件则会生成以下代码

vue 深度长文之slot 篇

v-slot

1、基本用法

vue 2.6.x 已经出来有一段时间了,其中对于插槽这块则是放弃了 slot-scope 作用域插槽推荐写法,直接改成了 v-slot 指令形式的推荐写法(当然这只是个语法糖而已)。下面我们将仔细谈谈 v-slot 这块的内容。

在看具体实现逻辑前,我们先通过一个例子来先了解下其基本用法

vue 深度长文之slot 篇

然后进行使用

vue 深度长文之slot 篇

页面展示效果如下

vue 深度长文之slot 篇

相同与区别

接下来,咱来会会这个新特性

round 1. $slots & $scopedSlots

$slots 这块逻辑没变,还是沿用的以前的代码

// $slots
const options = vm.$options
const parentVnode = vm.$vnode = options._parentVnode
const renderContext = parentVnode && parentVnode.context
vm.$slots = resolveSlots(options._renderChildren, renderContext)

$scopedSlots 这块则进行了改造,执行了 normalizeScopedSlots() 并接收其返回值为 $scopedSlots 的值

vue 深度长文之slot 篇

接着,我们来会一会 normalizeScopedSlots ,首先我们先看看它的几个参数

vue 深度长文之slot 篇

  • 首先,如果 slots 参数不存在,则直接返回一个空对象 {}
if (!slots) {
 res = {}
}
  • 若 prevSlots 存在,且满足系列条件的情况,则直接返回 prevSlots
vue 深度长文之slot 篇

注:这里的 $key , $hasNormal , $stable 是直接使用 vue 内部对 Object.defineProperty 封装好的 def() 方法进行赋值的

def(res, \'$stable\', isStable)
def(res, \'$key\', key)
def(res, \'$hasNormal\', hasNormalSlots)
复制代码
  • 否则,则对 slots 对象进行遍历,操作 normalSlots ,赋值给 key 为 key,value 为 normalizeScopedSlot 返回的函数 的对象 res
vue 深度长文之slot 篇

  • 随后再次对 normalSlots 进行遍历,若 normalSlots 中的 key 在 res 找不到对应的 key,则直接进行 proxyNormalSlot 代理操作,将 normalSlots 中的 slot 挂载到 res对象上
  • 接着,我们看看 normalizeScopedSlot() 都做了些什么事情。该方法接收三个参数,第一个参数为 normalSlots,第二个参数为 key,第三个参数为 fn
vue 深度长文之slot 篇

参考文章:

https://juejin.im/post/5cced0096fb9a032426510ad

1
「干货」实现一个简单的Vue
上一篇
基于Vue.js实现的项目管理系统
下一篇
评论 (0)

请登录以参与评论。

现在登录
聚合文章
在Gitee收获近 5k Star,更新后的Vue版RuoYi有哪些新变化?
2月前
vue3.x reactive、effect、computed、watch依赖关系及实现原理
2月前
Vue 3 新特性:在 Composition API 中使用 CSS Modules
2月前
新手必看的前端项目去中心化和模块化思想
2月前
标签
AI AI项目 css docker Drone Elaticsearch es5 es6 Geometry Go gru java Javascript jenkins lstm mysql mysql优化 mysql地理位置索引 mysql索引 mysql规范 mysql设计 mysql配置文件 mysql面试题 mysql高可用 nginx Redis redis性能 rnn SpringBoot Tensorflow tensorflow2.0 UI设计 vue vue3.0 vue原理 whistle ZooKeeper 开源项目 抓包工具 日志输出 机器学习 深度学习 神经网络 论文 面试题
1
相关文章
在Gitee收获近 5k Star,更新后的Vue版RuoYi有哪些新变化?
vue3.x reactive、effect、computed、watch依赖关系及实现原理
Vue 3 新特性:在 Composition API 中使用 CSS Modules
新手必看的前端项目去中心化和模块化思想
松鼠乐园

资源整合,创造价值

小伙伴
墨魇博客 无同创意
目录
重大新闻 Centos CSS Docker ES5 ES6 Go Java Javascript Linux Mac MySQL Nginx Redis Springboot Tensorflow Vue Vue2.x从零开始 Windows 书籍推荐 人工智能 前端资源 后端资源 壁纸 开源项目 测试 论文
Copyright © 2018-2021 松鼠乐园. Designed by nicetheme. 浙ICP备15039601号-4
  • 重大新闻
  • Centos
  • CSS
  • Docker
  • ES5
  • ES6
  • Go
  • Java
  • Javascript
  • Linux
  • Mac
  • MySQL
  • Nginx
  • Redis
  • Springboot
  • Tensorflow
  • Vue
  • Vue2.x从零开始
  • Windows
  • 书籍推荐
  • 人工智能
  • 前端资源
  • 后端资源
  • 壁纸
  • 开源项目
  • 测试
  • 论文
热门搜索
  • jetson nano
  • vue
  • java
  • mysql
  • 人工智能
  • 人脸识别
迦娜王
坚持才有希望
1224 文章
33 评论
235 喜欢
  • 1
  • 0
  • Top