VUE render 函数中使用插槽、具名插槽与作用域插槽

您所在的位置:网站首页 渲染函数的作用 VUE render 函数中使用插槽、具名插槽与作用域插槽

VUE render 函数中使用插槽、具名插槽与作用域插槽

2023-11-26 15:06| 来源: 网络整理| 查看: 265

1、Vue render

Vue render是Vue在编译模板时的必经之路,通过 template 形式写出的模板最终会经由 render 函数渲染到dom上,正如 render 介绍所说的

然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器

如果你还不了解 render 函数的作用以及能力,建议你现在官网了解一下 :) Vue官网 render函数介绍

2、slots

如果你还不了解 slot 的作用以及能力,建议你现在官网了解一下 :) Vue官网 插槽、具名插槽、作用域插槽介绍

slot(插槽)是 父组件 向 子组件 提供内容的一种方式,下面贴出代码

// 父组件使用 child 组件 // 子组件内容 我是子组件! 我是默认插槽的后备内容 我是具名插槽 content 的后备内容 我是具名插槽 other 的后备内容

这样对应的结果是

我是子组件! 我是默认插槽的后备内容 我是具名插槽 content 的后备内容 我是具名插槽 other 的后备内容

我们先来看看子组件对应的 $slots ==> {} 是一个空对象,这是由于 现在父组件部分还没有为子组件提供插槽的内容

如果父组件形如

我是父组件提供的默认内容 我是父组件提供的 content 我是父组件提供的 other

则渲染结果为

我是子组件! 我是父组件提供的默认内容 我是父组件提供的 content 我是父组件提供的 other

子组件对应的 $slots为

{ content: [VNode {tag: undefined, data: undefined, children: undefined, text: " 我是父组件提供的 content ", elm: undefined, …}] default: [VNode {tag: undefined, data: undefined, children: undefined, text: " 我是父组件提供的默认插槽 ", elm: undefined, …}] other: [VNode {tag: undefined, data: undefined, children: undefined, text: " 我是父组件提供的 other ", elm: undefined, …}] }

可以看到, 子组件中的 $slot 将父组件提供的内容传了过来, $slot 对象中的每个属性名对应一个插槽的name(默认的名称为 default),它的内容则是父组件提供的模板经由编译之后的 VNode 数组,这个VNode数组后续会渲染为对应的内容

3、scopedSlots

同样使用上面的组件,这次稍微修改些内容

我是子组件! 我是默认插槽的后备内容 我是具名插槽 content 的后备内容 我是具名插槽 other 的后备内容

父组件通过作用域插槽获取到子组件暴露的内容

{{ prop }} {{ prop }} {{ prop }}

这是的效果是

我是子组件! { "text": "我是默认插槽" } { "text": "我是具名插槽content" } { "text": "我是具名插槽other" }

子组件中的 $scopedSlots 的内容是

{ content: ƒ () default: ƒ () other: ƒ () $hasNormal: false $key: undefined $stable: true }

可以看到,这个对象中出现了和具名插槽名称一致的三个函数 content default 和 other 这三个函数可以接收一个参数作为要给父组件使用的对象,并返回[VNode] 换句话说,v-slot:content="prop" 中的 prop 就是 $scopedSlots.content(prop)这个参数给的

注意! 父组件再没有书写 v-slot 时子组件的 $scopedSlots 没有上述函数!因此再编写子组件渲染函数的时候注意检查

在 Vue API 中了解更多

4、在 render 函数中的使用 $slots/$scopedSlots

有了上面内容的铺垫,可以看到,不论是 $slots 还是 $scopedSlots ,它们的属性都是父组件向子组件注入的内容决定的,只不过 $scopedSlots可以再向父组件抛出数据

它们是在模板上编写 后 Vue 替你进行的下一步操作。 现在我们在 render 上自己执行它们

就第一个 slots 的例子来改,可以改为

我是子组件! 我是默认插槽的后备内容 我是具名插槽 content 的后备内容 我是具名插槽 other 的后备内容 --------------------------------------------变为了------------------------------------------- render(_c) { let def = this.$slots.default; def || (def = "我是默认插槽的后备内容"); let con = this.$slots.content; con || (con = "我是具名插槽 content 的后备内容"); let oth = this.$slots.other; oth || (oth = "我是具名插槽 other 的后备内容"); return _c("div", [ "我是子组件!", _c("br"), def, _c("br"), con, _c("br"), oth, ]); },

父组件提供内容、父组件不提供内容的效果依次为:

我是子组件! 我是父组件提供的默认内容 我是父组件提供的 content 我是父组件提供的 other 我是子组件! 我是默认插槽的后备内容 我是具名插槽 content 的后备内容 我是具名插槽 other 的后备内容

对于 $scopedSlots,使用起来也大同小异

我是子组件! --------------------------------------------变为了------------------------------------------- ---------------注意! 示例没有进行类型检查,但是开发时无法保证所有的插槽正确、完整书写,--------- ---------------需要类型检查或提供默认值,见下方注释-------------------------------------------- render(_c) { // 如果要提供后备内容可以通过 判断 this.$scopedSlots.xxx 不为函数后渲染默认内容等方式 // 这里省略 let def = this.$scopedSlots.default({ text: "我是默认插槽", }); let con = this.$scopedSlots.content({ text: "我是具名插槽content", }); let oth = this.$scopedSlots.other({ text: "我是具名插槽other", }); return _c("div", [ "我是子组件!", _c("br"), def, _c("br"), con, _c("br"), oth, ]); },

效果和 $scopedSlots 部分的结果一致

我是子组件! { "text": "我是默认插槽" } { "text": "我是具名插槽content" } { "text": "我是具名插槽other" } 5、使用 scopedSlots

它不同于 $scopedSlots,它是存在于 render数据对象 中的一个对象 效果是获取 子组件向父组件 抛出的内容而不是抛出内容给父组件

就以刚刚的父组件为例!

{{ prop }} {{ prop }} {{ prop }} --------------------------------------------变为了------------------------------------------- ---------------注意! 示例没有进行类型检查,但是开发时无法保证所有的插槽正确、完整书写,----------- render(_c) { return _c("child", { scopedSlots: { default(prop) { // 对应 v-slot:default="prop" return prop; }, content(prop) { // 对应 v-slot:default="prop" return prop; }, other(prop) { // 对应 v-slot:default="prop" return prop; }, }, }); },

结果一致:

我是子组件! { "text": "我是默认插槽" } { "text": "我是具名插槽content" } { "text": "我是具名插槽other" } 6、总结

简单来说: v-slot:name ====> 子组件 this.$slots.name v-slot 或者单纯的标签 ====> 子组件 this.$slots.default v-slot="xxx" ====> 子组件抛出this.$scopedSlots.default(xxx)/ 父组件使用scoepdSlots: { default(xxx){ return VNode } } v-slot:name="xxx" ====> 子组件抛出this.$scopedSlots.name(xxx)/ 父组件使用scoepdSlots: { name(xxx){ return VNode } }

7、实践

实践是检验真理的唯一标准,准备冻手!都说啦准备冻手啦!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3