声明式和命令式的区别
h 函数
就是一个辅助创建虚拟 DOM 的工具函数,仅此而已。
组件的渲染函数:一个组件要渲染的内容是通过渲染函数来描述的,也就是 render 函数,Vue.js 会根据组件的 render 函数的返回值拿到虚拟 DOM,然后就可以把组件的内容渲染出来了。
Vue.js 3 是一个声明式的 UI 框架,意思是说用户在使用 Vue.js 3 开发页面时是声明式地描述 UI 的。
首先我们先来看编写前端页面都涉及哪些内容,具体如下:
- DOM 元素:例如是 div 标签还是 a 标签。
- 属性:如 a 标签的 href 属性,再如 id、class 等通用属性。
- 事件:如 click、keydown 等。
- 元素的层级结构:DOM 树的层级结构,既有子节点,又有父节点。
如何声明式地描述上述内容呢?其实方案有很多。拿 Vue.js 3 来说,相应的解决方案是:
- 使用与 HTML 标签一致的方式来描述 DOM 元素,例如描述一个 div 标签时可以使用 <div></div>;
- 使用与 HTML 标签一致的方式来描述属性,例如 <div id="app"></div>;
- 使用 : 或 v-bind 来描述动态绑定的属性,例如 <div :id="dynamicId"></div>;
- 使用 @ 或 v-on 来描述事件,例如点击事件 <div @click="handler"></div>;
- 使用与 HTML 标签一致的方式来描述层级结构,例如一个具有 span 子节点的 div 标签 <div><span></span></div>。
可以看到,在 Vue.js 中,哪怕是事件,都有与之对应的描述方式。用户不需要手写任何命令式代码,这就是所谓的声明式地描述 UI。
除了上面这种使用模板来声明式地描述 UI 之外,我们还可以用 JavaScript 对象来描述,代码如下所示:
const title = {
// 标签名称
tag: "h1",
// 标签属性
props: {
onClick: handler,
},
// 子节点
children: [{ tag: "span" }],
};
对应到 Vue.js 模板,其实就是:
<h1 @click="handler"><span></span></h1>
使用模板和 JavaScript 对象描述 UI 有何不同呢?答案是:使用 JavaScript 对象描述 UI 更加灵活。举个例子,假如我们要表示一个标题,根据标题级别的不同,会分别采用 h1~h6 这几个标签,如果用 JavaScript 对象来描述,我们只需要使用一个变量来代表 h 标签即可:
// h 标签的级别
let level = 3;
const title = {
tag: `h$ {level}`, // h3 标 签
};
可以看到,当变量 level 值改变,对应的标签名字也会在 h1 和 h6 之间变化。但是如果使用模板来描述,就不得不穷举:
<h1 v-if="level === 1"></h1>
<h2 v-else-if="level === 2"></h2>
<h3 v-else-if="level === 3"></h3>
<h4 v-else-if="level === 4"></h4>
<h5 v-else-if="level === 5"></h5>
<h6 v-else-if="level === 6"></h6>
这远没有 JavaScript 对象灵活。
**而使用 JavaScript 对象来描述 UI 的方式,其实就是所谓的虚拟 DOM。**现在大家应该觉得虚拟 DOM 其实也没有那么神秘。正是因为虚拟 DOM 的这种灵活性,Vue.js 3 除了支持使用模板描述 UI 外,还支持使用虚拟 DOM 描述 UI。
其实我们在 Vue.js 组件中手写的渲染函数就是使用虚拟 DOM 来描述 UI 的,如以下代码所示:
import { h } from "vue";
export default {
render() {
// 虚拟 DOM
return h("h1", { onClick: handler });
},
};
这里会调用一个 h 函数
,其实 h 函数
的返回值就是一个对象,其作用是让我们编写虚拟 DOM 变得更加轻松。如果把上面 h 函数
调用的代码改成 JavaScript 对象,就需要写更多内容:
export default {
render() {
return {
tag: "h1",
props: { onClick: handler },
};
},
};
如果还有子节点,那么需要编写的内容就会更多,所以 h 函数
就是一个辅助创建虚拟 DOM 的工具函数,仅此而已。
另外,这里有必要解释一下什么是组件的渲染函数。一个组件要渲染的内容是通过渲染函数来描述的,也就是上面代码中的 render 函数,Vue.js 会根据组件的 render 函数的返回值拿到虚拟 DOM,然后就可以把组件的内容渲染出来了。