在Vue中,关于如何在Render函数或JSX中使用具名插槽与作用域插槽

写在开头

插槽Vue 中的一个重要特性,主要有三大部分:默认插槽(基本使用)、具名插槽、作用域插槽。

插槽的基础应用咱们就不扯了,主要来看看在 Render 函数中,是如何使用具名插槽和作用域插槽的,并且有些什么坑呢?👻

基本使用

Child.vue 文件:

javascript 复制代码
<template>
  <div>
    <h1>子组件</h1>
    <slot></slot>
    <slot name="content"></slot>
  </div>
</template>

Parent.vue 文件:

javascript 复制代码
<template>
  <div>
    <h1>父组件</h1>
    <child>
      <div>这是默认插槽内容</div>
      <template v-slot:content>
        <div>这是具名插槽内容</div>
      </template>
    </child>
  </div>
</template>

<script>
import Child from "./Child.vue";

export default {
  components: { Child },
};
</script>

以上是具名插槽的基本应用,接下来看看它们如果转成 Render 函数形式是怎么样的。

Render-JSX

Child.vue 文件:

javascript 复制代码
<script>
export default {
  render() {
    return (
      <div>
        <h1>子组件</h1>
        {this.$slots.default}
        {this.$slots.content}
      </div>
    );
  },
};
</script>

Parent.vue 文件:

javascript 复制代码
<script>
import Child from "./Child.vue";

export default {
  render() {
    return (
      <div>
        <h1>父组件</h1>
        <Child>
          <div>这是默认插槽内容</div>
          <template slot="content">
            <div>这是具名插槽内容</div>
          </template>
        </Child>
      </div>
    );
  },
};
</script>

这里不知道你发现问题没有?

小编使用了一个弃用属性 slot ,从 Vue2.6 版本之后,官方推荐使用 v-slot 替换了旧的 slotslot-scope 属性,虽然它们在 Vue2 中还可以继续使用,但在 Vue3 中将被完整移除,具体可以上官网查看。(这里本来想放个地址的,结果官网又挂了😤)

那么为什么要这么写呢?那肯定是因为,无论我们这样:

javascript 复制代码
<template v-slot:content>
  <div>这是具名插槽内容</div>
</template>

还是这样(GPT 说的一种写法):

xml 复制代码
<Child>
 {{
   content: () => <div>这是具名插槽内容</div>
 }}
</Child>

以上在 JSX 都不行!❌

说明 JSX 中并不支持基本的具名插槽写法,如你知道另外的写法,望评论区告知,感谢。😉

那么,这就完了吗?当然还没,使用弃用属性等于埋下隐患,这里我们可以通过另外的方式来解决,也就是作用域插槽

Child.vue 文件:

javascript 复制代码
<script>
export default {
  render() {
    return (
      <div>
        <h1>子组件</h1>
        {this.$scopedSlots.default()}
        {this.$scopedSlots.content()}
      </div>
    );
  },
};
</script>

Parent.vue 文件:

javascript 复制代码
<script>
import Child from "./Child.vue";

export default {
  render() {
    return (
      <div>
        <h1>父组件</h1>
        <Child
          scopedSlots={{
            default: () => <div>这是默认插槽内容</div>,
            content: () => <div>这是具名插槽内容</div>,
          }}
        />
      </div>
    );
  },
};
</script>

当然,你也可以默认插槽和具名插槽在 JSX 中混着使用,虽然不建议。👻

$slots$scopedSlots 的内容都是由父组件向子组件注入的内容来决定的,它们之间的区别在于 $scopedSlots 可以向上传递数据。

Render-h

以上是关于 Render 函数中 JSX 的插槽内容,但提到 Render 函数肯定就不能不提及 h 函数了,也得来探索一下插槽在其中的使用情况。

Child.vue 文件:

javascript 复制代码
<script>
export default {
  render(h) {
    return h("div", null, [
      h("h1", null, "子组件"),
      this.$scopedSlots.default(),
      this.$scopedSlots.content(),
    ]);
  },
};
</script>

Parent.vue 文件:

javascript 复制代码
<script>
import Child from "./Child.vue";

export default {
  components: { Child },
  render(h) {
    return h("div", null, [
      h("h1", null, "父组件"),
      h(
        "Child",
        {
          scopedSlots: {
            default: () => h("div", null, "这是默认插槽内容"),
            content: () => h("div", null, "这是具名插槽内容"),
          },
        },
      ),
    ]);
  },
};
</script>

折腾一下,你会发现在其中一样不能使用具名插槽,只能通过作用域插槽来实现具名插槽的应用。

不过 h 函数是允许使用默认插槽的,但这其中有一些坑坑洼洼需要注意。

例如:

Child.vue 文件:

javascript 复制代码
<script>
export default {
  render(h) {
    return h("div", null, [
      h("h1", null, "子组件"),
      this.$slots.default,
    ]);
  },
};
</script>

Parent.vue 文件:

javascript 复制代码
<script>
import Child from "./Child.vue";

export default {
  components: { Child },
  render(h) {
    return h("div", null, [
      h("h1", null, "父组件"),
      h("Child", null, "这是默认插槽内容"),
    ]);
  },
};
</script>

// 或者

<script>
import Child from "./Child.vue";

export default {
  components: { Child },
  render(h) {
    return h("div", null, [
      h("h1", null, "父组件"),
      h("Child", null, ["这是默认插槽内容"]), // 数值可以多个
    ]);
  },
};
</script>

// 或者

<script>
import Child from "./Child.vue";

export default {
  components: { Child },
  render(h) {
    return h("div", null, [
      h("h1", null, "父组件"),
      h("Child", null, [h("div", null, "这是默认插槽内容")]),
    ]);
  },
};
</script>

以上写法都可以✔,但是一定不能这样子写:

Parent.vue 文件:

javascript 复制代码
<script>
import Child from "./Child.vue";

export default {
  components: { Child },
  render(h) {
    return h("div", null, [
      h("h1", null, "父组件"),
      h("Child", null, h("div", null, "这是默认插槽内容")),
    ]);
  },
};
</script>

虽然这样子看起来就很合理的,但实际上不行❗

这个问题其实是探究 h 函数第三个参数,那些值能作为默认插槽的内容,具体可以看看源码的判断过程。

源码位置:vue/src/core/vdom/create-element


至此,本篇文章就写完啦,撒花撒花。

希望本文对你有所帮助,如有任何疑问,期待你的留言哦。

老样子,点赞+评论=你会了,收藏=你精通了。

相关推荐
LUwantAC7 分钟前
CSS(四)display和float
前端·css
cwtlw11 分钟前
CSS学习记录20
前端·css·笔记·学习
界面开发小八哥15 分钟前
「Java EE开发指南」如何用MyEclipse构建一个Web项目?(一)
java·前端·ide·java-ee·myeclipse
谢道韫66623 分钟前
今日总结 2024-12-24
javascript·vue.js·elementui
米奇妙妙wuu30 分钟前
react使用sse流实现chat大模型问答,补充css样式
前端·css·react.js
傻小胖35 分钟前
React 生命周期完整指南
前端·react.js
梦境之冢1 小时前
axios 常见的content-type、responseType有哪些?
前端·javascript·http
racerun1 小时前
vue VueResource & axios
前端·javascript·vue.js
m0_548514772 小时前
前端Pako.js 压缩解压库 与 Java 的 zlib 压缩与解压 的互通实现
java·前端·javascript
AndrewPerfect2 小时前
xss csrf怎么预防?
前端·xss·csrf