文章目录
Vue3 h函数
概述
Vue 推荐使用模版创建 HTML,在一些特殊场景,可以使用 JavaScript 创建 HTML。
- VNode:在 template 中编写的 HTML 最终通过渲染函数生成对应的 VNode。
- VDOM:VNode 组合在一起形成一棵树结构,也就是虚拟 DOM(VDOM)。
- h():h 是 "hyperscript" 的缩写,表示为生成 HTML 结构的 JavaScript。h 函数是 createVNode 函数的别名,用于创建 VNode 的核心函数。
template工作流程
- 编译阶段:
- 将模板转换为抽象语法树(AST)
- 对 AST 进行优化
- 将优化后的 AST 转换为渲染函数代码(通常是h函数调用或render函数)
- 运行阶段:
- 执行渲染函数生成虚拟 DOM 节点(VNode)
- 通过 patch 函数将 VNode 转换为真实 DOM
- 响应式联动:当数据变化时,触发重新渲染,重复执行运行阶段
语法
h(type, props, children)
- type:节点类型,可以是字符串、组件、异步组件等。
- props:属性对象,可选。
- children:子节点,可选。
使用
选项式
vue
<script>
import {h, ref} from "vue"
import HelloWorld from "./components/HelloWorld.vue";
export default {
data() {
return {
counter: 100
}
},
// 使用 render 函数
render() {
return h("div", {class: "counter"}, [
h("h2", {class: "title"}, `counter: ${this.counter}`),
h("button", {onclick: this.increment}, "+1"),
h("button", {onclick: this.decrement}, "-1"),
h(HelloWorld),
])
},
methods: {
increment() {
this.counter++
},
decrement() {
this.counter--
},
}
}
</script>
<style scoped>
.counter {
text-align: center;
background-color: gray;
}
.title {
color: red;
}
</style>
组合式
vue
<script>
import {h, ref} from "vue"
import HelloWorld from "./components/HelloWorld.vue";
export default {
setup() {
const counter = ref(200)
const increment = () => {
counter.value++
}
const decrement = () => {
counter.value--
}
// 返回渲染函数
return () => h("div", {class: "counter"}, [
h("h2", {class: "title"}, `counter: ${counter.value}`),
h("button", {onclick: increment}, "+1"),
h("button", {onclick: decrement}, "-1"),
h(HelloWorld),
])
}
}
</script>
<style scoped>
.counter {
text-align: center;
background-color: gray;
}
.title {
color: red;
}
</style>
setup语法糖
vue
<script setup>
import {h, ref, getCurrentInstance} from "vue"
import HelloWorld from "./components/HelloWorld.vue";
const instance = getCurrentInstance()
const scopeId = instance.type.__scopeId
const counter = ref(300)
const increment = () => {
counter.value++
}
const decrement = () => {
counter.value--
}
// 定义渲染函数
const render = () => h("div", {class: "counter", [scopeId]: ""}, [
h("h2", {class: "title", [scopeId]: ""}, `counter: ${counter.value}`),
h("button", {onclick: increment}, "+1"),
h("button", {onclick: decrement}, "-1"),
h(HelloWorld),
])
</script>
<template>
<component :is="render"/>
</template>
<style scoped>
.counter {
text-align: center;
background-color: gray;
}
.title {
color: red;
}
</style>