h 函数 & JSX
# h 函数 & JSX
# h 函数 🔥
# 介绍
返回一个”虚拟节点“,通常缩写为 VNode:一个普通对象,其中包含向 Vue 描述它应在页面上渲染哪种节点的信息,包括所有子节点的描述。它的目的是用于手动编写的渲染函数 (opens new window):
Vue推荐在绝大数情况下使用模板来创建你的HTML,然后一些特殊的场景,你真的需要JavaScript的完全编程的能力,这个时候你可以使用 h 渲染函数 ,它比模板更接近编译器;
前面我们讲解过VNode和VDOM的改变:Vue在生成真实的DOM之前,会将我们的节点转换成VNode,而VNode组合在一起形成一颗树结构,就是虚拟DOM(VDOM);
事实上,我们之前编写的 template 中的HTML 最终也是使用渲染函数生成对应的VNode;
那么,如果你想充分的利用JavaScript的编程能力,我们可以自己来编写 createVNode 函数,生成对应的VNode;
那么我们应该怎么来做呢?使用 h()函数:
- h() 函数是一个用于创建 VNode 的一个函数;
- 其实更准备的命名是 createVNode() 函数,但是为了简便在Vue将之简化为 h() 函数;
render() {
return h('h1', {}, 'Some title')
}
2
3
# 参数 🔥
接收三个参数:type,props 和 children
# type
类型:
String | Object | Function详细:
HTML 标签名、组件、异步组件或函数式组件。使用返回 null 的函数将渲染一个注释。此参数是必需的。
# props
类型:
Object详细:
一个对象,与我们将在模板中使用的 attribute、prop 和事件相对应。可选。
# children
类型:
String | Array | Object详细:
子代 VNode,使用
h()生成,或者使用字符串来获取“文本 VNode”,或带有插槽的对象。可选。h('div', {}, [ 'Some text comes first.', h('h1', 'A headline'), h(MyComponent, { someProp: 'foobar' }) ])1
2
3
4
5
6
7
# h 函数的基本使用
h函数可以在两个地方使用:
render函数选项中;
<script> import { h } from 'vue'; export default { render() { return h("h2", {class: "title"}, "Hello Render") } } </script>1
2
3
4
5
6
7
8
9setup函数选项中(setup本身需要是一个函数类型,函数再返回h函数创建的VNode);
<script> import { h } from 'vue'; export default { setup() { return () => h("h2", {class: "title"}, "Hello Render") } } </script>1
2
3
4
5
6
7
8
9
# render 函数实现计数器
<script>
import { h } from 'vue';
export default {
data() {
return {
counter: 0
}
},
render() {
return h("div", {class: "app"}, [
h("h2", null, `当前计数: ${this.counter}`),
h("button", {
onClick: () => this.counter++
}, "+1"),
h("button", {
onClick: () => this.counter--
}, "-1"),
])
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
太麻烦了,可以使用JSX替代。
# setup 函数实现计数器
<script>
import { ref, h } from 'vue';
export default {
setup() {
const counter = ref(0);
return () => {
return h("div", {class: "app"}, [
h("h2", null, `当前计数: ${counter.value}`),
h("button", {
onClick: () => counter.value++
}, "+1"),
h("button", {
onClick: () => counter.value--
}, "-1"),
])
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 组件和插槽的使用
App.vue
<script>
import { h } from 'vue'
import HelloWorld from './HelloWorld.vue'
export default {
render() {
return h('div', null, [
h(HelloWorld, null, {
// default 插槽;作用域插槽
default: (props) =>
h('span', null, `app传入到HelloWorld中的内容: ${props.name}`),
}),
])
},
}
</script>
<style scoped></style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
HelloWorld.vue
<script>
import { h } from 'vue'
export default {
render() {
return h('div', null, [
h('h2', null, 'Hello World'),
// default 插槽;
this.$slots.default
? this.$slots.default({ name: 'coderwhy' })
: h('span', null, '我是HelloWorld的插槽默认值'),
])
},
}
</script>
<style lang="scss" scoped></style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# JSX 🔥
# 入门
如果我们希望在项目中使用jsx,那么我们需要添加对jsx的支持:
- jsx我们通常会通过Babel来进行转换(React编写的jsx就是通过babel转换的);
- 对于Vue来说,我们只需要在Babel中配置对应的插件即可(当前版本无需配置);
(根据是否需要配置)安装Babel支持Vue的jsx插件:
npm install @vue/babel-plugin-jsx -D
(根据是否需要配置)在babel.config.js配置文件中配置插件
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
2
3
4
5
6
# JSX 计数器案例
App.vue
<script>
import HelloWorld from './HelloWorld.vue';
export default {
data() {
return {
counter: 0
}
},
render() {
const increment = () => this.counter++;
const decrement = () => this.counter--;
return (
<div>
<h2>当前计数: {this.counter}</h2>
<button onClick={increment}>+1</button>
<button onClick={decrement}>-1</button>
<HelloWorld>
</HelloWorld>
</div>
)
}
}
</script>
<style lang="scss" scoped>
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
HelloWorld.vue
<script>
export default {
render() {
return (
<div>
<h2>HelloWorld</h2>
{this.$slots.default ? this.$slots.default(): <span>哈哈哈</span>}
</div>
)
}
}
</script>
<style scoped>
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16