Skip to content
Jack Chou's blog
On this page

vue3 中的 render 函数

vue3 较 vue2,render 函数有很大的变化,现在使用 vue3 的 render 把 vue2 中使用 render 定义的组件都实现一遍,比较着学习,印象会更深刻。

基本用法

h 函数参数的变化

  1. 参数更加扁平了。
  1. 使用时需要显示导入

2.x 会自动注入 h,3.x 需要手动引入。

以前 2.x 的语法,再使用 3.x 语法写一遍 MyButton.vue

jsx 写法:

  1. 在 setup 中返回渲染函数

需要返回渲染函数,直接返回 vnode,不会渲染。

如何显示文本

返回 span

  1. 使用 render 函数, 在 setup 中返回 data

在 render 函数中获取 props、slots,从组件实例中获取

更多实例属性

在 setup 返回渲染函数,render 也返回 vnode,会怎样?

setup 函数优先,render 像不存在一样。

使用 render + setup 函数,和 2.x 的 data + render 类似。

这种写法需要了解组件的 实例属性 ,和 3.x 去 this 的理念背道而驰。

这种写法,render 参数和 2.x 的参数不同,也和文档里说的参数不同,难以理解,让人费解。

具体可看这个 issue:

why props slots and attrs are not same in render and setup function? what's the best practice to use they?

render 函数变更

基于以上原因,不推荐 setup + render 的写法。

使用 jsx 定义一个按钮

setup 函数有两个参数,第一个为 props,第二个为 slots、emit、attrs 的合并对象。

定义一个按钮:

在模板中使用 MyButton2:

在 setup 中使用 MyButton2:

ParentButton.js

关于组件的引入:

  1. 通过 import MyButton2.jsx , 再通过 h 渲染,如上。

  2. 全局注册的组件,可用解析函数引入。

改写 ParentButton.js

resolveComponent 找到组件,返回组件对象,否则返回参数。

attrs 属性包含非 props 属性和事件

在模板中使用组件,使用 v-bind 绑定属性和事件: v-bind="attrs"

attrs 的问题:

  1. 想要在组件内部取出事件和 dom 属性,比较棘手。

为何要取出来呢? 希望手动绑定 dom 的属性和 html 的特性。

可依次判断 key 是否以 on 开头且值为非函数。

  1. 第一种方法还是不能很好区分 dom 属性。

当组件绑定一个 onName="func" 时,无法知道这是绑定事件还是传递方法。

比如

attrs 里有一个 onProp 属性,乍一看,以为是事件。

解决办法

使用 emits: ['my-click'] 声明组件的事件,attrs 里就不再有 onMyClick 属性了。

处理 v-model

  1. 在 html 表单元素上

MyInputOne.vue

h 函数实现 MyInputTow.js

使用 jsx + vModel:

3.x 不再支持 vModel 。

value + input + jsx, 可行:

  1. 自定义组件上的 v-model

多行文本 textarea 比较特殊,没有 value 、checked 等表单属性。只能使用 v-model,其他表单可以使用 v-model 直接绑定,或者使用 DOM 属性比如 checked + change 、value + input 等,在事件处理函数中触发 update:modelValue 。

在模板中使用 MyTextarea

在渲染函数中使用:

在 jsx 中使用

二次封装 MyTextarea,对外提供 v-model,常见二次封装开源的表单组件。

  1. 用模板封装

两种方案:

①. v-model + watch ,在 watch 中触发 update:modelValue

②. modelValue + update:modelValue ,在事件中触发 update:modelValue

  1. 用 jsx 或者 js 封装

只能使用

modelValue + update:modelValue , 在事件中触发 update:modelValue

2.x 中的 model 属性不再支持。

或者:

处理插槽

setup 函数中从第二个参数中解构 slots

render 函数使用 this.$slots

在 h 函数中作为第三个参数传递,这和 2.x 第二个参数中使用插槽不同。

jsx 模板的中插槽

2.x 在用 slot 指定插槽,2.x 作用域插槽如何写?

3.x 不再支持 slot 属性,目前只能在第三个参数里传递插槽。

@vue/babel-plugin-jsx 插件提供了插槽的便捷 写法,但是文档太粗陋了,不知道如何用,先写 h。

参考

更多关于插槽的文档

What’s the proper way to use Vue 3 JSX Function Component with Slots?

component 组件 和 is

模板中使用 component 组件和 is 属性动态渲染组件。

render 函数可直接进行 JS 条件判断,选择渲染的组件。

还可以使用 resolveDynamicComponent 不建议这样写 ,条件判断已经足够清楚。

处理指令

可导出解析指令的方法,可直接使用指令对象。

文档说明

不推荐在 render 中使用指令语法,直接使用 jsx,或者把指令逻辑封装成函数,h 函数中写指令,可读性极差。

keep-alive 等内置组件的处理

在 render 函数中可使用 vue 的内置组件,需从 vue 引入,这么设计是为了便于摇树优化。

文档说明

显示文本

2.x 的 h 不能返回文本,返回文本需要使用 return this._v('someText')

3.x 支持直接返回文本或者字符串数组,会在文本前面渲染一个注释节点。

函数组件

3.x 已经把状态组件的性能提升到和函数组件几乎没有差别,vue 推荐使用状态组件。

但是学会使用函数组件,可以极大地让组件更易扩展和维护,并且让组件实现真正的数据驱动(数据变化了不要去修改模板,比如添加插槽等)。

数据驱动 是 vue、react、angular 等前端框架的灵魂,正是数据驱动,前端才告别手动操作 DOM 的脏活累活。

数据驱动模板 数据驱动函数执行 (watch、computed),函数执行修改数据又引起页面更新,都是因为数据变化。

3.x 中删除 functional 选项,函数组件就是 普通函数 ,参数和 setup 的参数一致,需要添加 props emits 属性,就像普通函数添加属性一样。

2.x 的模板中的函数组件

改成 3.x 语法:

  1. 删除 functional

  2. props --> $props, attrs --> $attrs (包含事件和非 props 属性,listeners 被移除)

使用 3.x 写函数组件的最佳方式: 写函数

MyTitleFun.jsx