vue3 中的 render 函数
vue3 较 vue2,render 函数有很大的变化,现在使用 vue3 的 render 把 vue2 中使用 render 定义的组件都实现一遍,比较着学习,印象会更深刻。
基本用法
h 函数参数的变化
-
参数更加扁平了。
-
使用时需要显示导入
2.x 会自动注入 h,3.x 需要手动引入。
以前 2.x 的语法,再使用 3.x 语法写一遍
MyButton.vue
jsx 写法:
-
在 setup 中返回渲染函数
需要返回渲染函数,直接返回 vnode,不会渲染。
如何显示文本
返回
span
-
使用 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
关于组件的引入:
-
通过 import
MyButton2.jsx
, 再通过 h 渲染,如上。
-
全局注册的组件,可用解析函数引入。
改写
ParentButton.js
resolveComponent 找到组件,返回组件对象,否则返回参数。
attrs 属性包含非 props 属性和事件
在模板中使用组件,使用
v-bind
绑定属性和事件:
v-bind="attrs"
attrs 的问题:
-
想要在组件内部取出事件和 dom 属性,比较棘手。
为何要取出来呢? 希望手动绑定 dom 的属性和 html 的特性。
可依次判断 key 是否以
on
开头且值为非函数。
-
第一种方法还是不能很好区分 dom 属性。
当组件绑定一个
onName="func"
时,无法知道这是绑定事件还是传递方法。
比如
attrs 里有一个 onProp 属性,乍一看,以为是事件。
解决办法
使用
emits: ['my-click']
声明组件的事件,attrs 里就不再有
onMyClick
属性了。
处理 v-model
-
在 html 表单元素上
MyInputOne.vue
h 函数实现
MyInputTow.js
使用 jsx + vModel:
3.x 不再支持 vModel 。
value + input + jsx, 可行:
-
自定义组件上的 v-model
多行文本 textarea 比较特殊,没有 value 、checked 等表单属性。只能使用 v-model,其他表单可以使用 v-model 直接绑定,或者使用 DOM 属性比如 checked + change 、value + input 等,在事件处理函数中触发 update:modelValue 。
在模板中使用
MyTextarea
:
在渲染函数中使用:
在 jsx 中使用
二次封装 MyTextarea,对外提供 v-model,常见二次封装开源的表单组件。
-
用模板封装
两种方案:
①.
v-model
+
watch
,在 watch 中触发
update:modelValue
②.
modelValue
+
update:modelValue
,在事件中触发
update:modelValue
-
用 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 语法:
-
删除
functional
-
props --> $props, attrs --> $attrs (包含事件和非 props 属性,listeners 被移除)
使用 3.x 写函数组件的最佳方式:
写函数
MyTitleFun.jsx