VUE render 函数中使用插槽、具名插槽与作用域插槽 |
您所在的位置:网站首页 › 渲染函数的作用 › VUE render 函数中使用插槽、具名插槽与作用域插槽 |
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 |