Vue3高级之render函数、jsx、自定义指令、插件及nextTick和新内置组件(十五)

3,910 阅读5分钟

1.render和h函数

Vue推荐在绝大数情况下使用模板来创建你的HTML,然后一些特殊的场景,你真的需要JavaScript的完全编程的能力,这个时候你可以使用 渲染函数 ,它比模板更接近编译器

前面我们知道Vue在生成真实的DOM之前,会将我们的节点转换成VNode,而VNode组合在一起形成一颗树结构,就是虚拟DOM(VDOM)

事实上,我们之前编写的 template 中的HTML 最终也是使用渲染函数生成对应的VNode

如果实在有需求我们可以自己来编写 createVNode 函数,生成对应的 VNode

我们可以使用h函数创建 vnode,其实更准确应该叫 createVNode() 函数,将其简化成了h函数

h函数接受三个参数:

image-20220204235123031

注意:

  • 如果没有props,那么通常可以将children作为第二个参数传入,但是会产生歧义,所以如果不传递的话可以将第二个参数传入null,第三个传入children

h函数可以在两个地方使用:

  1. render函数

image-20220204234401025

  1. setup函数

image-20220204235715277

render函数实现计数器:

image-20220204235008877

setup函数实现计数器:

image-20220204235958697

reder函数中插槽的使用

image-20220205183053389

2.Vue中编写jsx

如果Vue中不支持jsx,就可以添加对jsx的支持

jsx我们通常会通过Babel来进行转换

对于Vue来说,我们只需要在Babel中配置对应的插件即可

安装Babel支持Vue的jsx插件:

npm install @vue/babel-plugin-jsx -D

在babel.config.js配置文件中配置插件:

image-20220205183508059

基础使用:

image-20220205183738484

jsx计数器案例:

image-20220205184128456

jsx组件的使用:

image-20220205184827745

3.自定义指令

Vue有很多的内置组件可以帮助我们完成很多功能,例如v-show、v-for、v-model

Vue同样允许我们自定义自己的指令,

当我们需要对DOM元素进行底层操作的时候建议考虑自定义指令

但是代码的复用抽象主要还是组件

自定义指令分两种

  1. 自定义局部指令:组件中通过 directives 选项,只能在当前组件中使用
  2. 自定义全局指令:app的 directive 方法,可以在任意组件中被使用

我们用三种方式做一个元素挂载完成自动获取焦点:

  1. 默认实现方式
image-20220205190248366
  1. 局部自定义指令,自定义局部v-focus指令,只需要在组件选项使用directives对象声明即可
image-20220205190544509
  1. 自定义全局v-focus指令
image-20220205190712973

指令的生命周期

一个指令定义的对象,Vue提供了如下的几个钩子函数:

  • created:在绑定元素的 attribute 或事件监听器被应用之前调用
  • beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用
  • mounted:在绑定元素的父组件被挂载后调用
  • beforeUpdate:在更新包含组件的 VNode 之前调用
  • updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用
  • beforeUnmount:在卸载绑定元素的父组件之前调用
  • unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次

指令的参数和修饰符

通过使用指令可以传入一些参数和修饰符

下面info是参数名称,aaa和bbb是修饰符名称,最后面则是传入的具体值

我们可以通过生命周期的bindings参数获取

image-20220205191634585

自定义指令练习

时间戳的显示需求:

从服务器获取时间戳转换成具体格式化时间展示

Vue2我们一般通过过滤器实现

Vue3可以通过计算属性(computed)或者方法(methods)实现

这里我们通过自定义v-format-time指令完成

封装对应函数,后续调用这个函数传入app即可:

image-20220205200903412

4.Vue插件

通常向Vue全局添加一些功能时,会采用插件的模式,它有两种编写方式:

  • 对象类型:一个对象,但是必须包含一个 install 的函数,该函数会在安装插件时执行
  • 函数类型:一个function,这个函数会在安装插件时自动执行

插件完成的功能没有限制,以下几种都可以实现:

  1. 添加全局方法或者属性,通过把它们添加到 config.globalProperties 上实现
  2. 添加全局资源:指令/过滤器/过渡等
  3. 通过全局 mixin 来添加一些组件选项
  4. 一个库,提供自己的 API,同时提供上面提到的一个或多个功能

image-20220205202615096

5.Vue3新内置组件

1.Fragment

  • 在Vue2中: 组件必须有一个根标签
  • 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
  • 好处: 减少标签层级, 减小内存占用

2.Teleport

Teleport 能够将我们的组件html结构移动到指定位置,比如移动到body元素上

如果多个Teleport移动到同一位置,内部内容会进行合并

它有两个属性:

  • to:指定将其中的内容移动到的目标元素,可以使用选择器
  • disabled:是否禁用 teleport 的功能
image-20220205203314332

3.Suspense

等待异步组件时渲染一些额外内容,让应用有更好的用户体验

该组件有两个插槽

  • default:如果default可以显示,那么显示default的内容
  • fallback:如果default无法显示,那么会显示fallback插槽的内容
image-20220201204210492

6.nextTick

在下一次 DOM 更新结束后执行其指定的回调

当我们改变数据DOM更新后,基于新DOM进行某些操作,要在nextTick的回调函数里操作

源码实际是将nextTick回调放在Promise的then回调当做微任务最后执行

实现案例:当我们点击按钮,修改h2中显示的内容,获取其修改后高度

如果我们直接点击按钮获取高度会错误,在updated钩子里能正确获取,但其他数据更新也会触发

正确的做法是使用nextTick(回调函数),vue2则可以使用this.$nextTick(回调函数)

image-20220205210006468