1、前言:
为什么vue
中已经有 template
模板语法,以及JSX
了,还要使用 h()
渲染函数;
vue
中选择默认使用template 静态模板分析
,有利于DMO
性能的提升,而且更接近真实的HTML
,便于开发设计人员理解修改,特别是对于熟练使用 HTML、CSS、JS
的前端人员来说,更容易上手;
而 vue
中使用 h()
函数,可以更加方便的处理高度动态复杂渲染逻辑
,相比而言比使用 template
模板 更加方便;但是由于渲染函数的性能消耗较大,所以一般不建议在开发中直接使用 h() 函数;并且在里面标签 属性 class 事件等杂糅一起,会难以理解;
2、定义:
h() 是一种能生成HTML的JavaScript
h() 函数 用于创建Vnodes 节点
用法:
接收三个参数
h(type, propsOrChildren, children)
type
: 节点类型 字符串、对象、函数
propsOrChildren
: 属性或子节点
children
: 子节点
如:
// 除类型之外的所有参数都是可选的
h('div')
h('div', { id: 'foo' })
//属性和属性都可以在道具中使用
//Vue会自动选择正确的分配方式
h('div', { class: 'bar', innerHTML: 'hello' })
// props modifiers such as .prop and .attr can be added
// with '.' and `^' prefixes respectively
h('div', { '.name': 'some-name', '^width': '100' })
// class 和 style 可以是对象或者数组
h('div', { class: [foo, { bar }], style: { color: 'red' } })
// 定义事件需要加on 如 onXxx
h('div', { onClick: () => {} })
// 子集可以字符串
h('div', { id: 'foo' }, 'hello')
//如果没有props是可以省略props 的
h('div', 'hello')
h('div', [h('span', 'hello')])
// 子数组可以包含混合的VNode和字符串
h('div', ['hello', h('span', 'hello')])
const Vnode = h('div', { class: 'my-div' }, 'h() 渲染内容')
渲染之后得到
<div class="my-div">h() 渲染内容</div>
具体如下:
<template>
<div class="my-h">
This is a h() demo .
<hr></hr>
<vnodeDiv></vnodeDiv>
</div>
</template>
<script setup>
import { ref, h } from 'vue'
const vnodeDiv = () => {
return h('div', { class: 'my-div' }, 'h() 渲染内容')
}
</script>
3、h() 函数 渲染多层DOM
const vnodeDiv = () => {
return h('div', { class: 'my-div', dataType:"ces" }, [
h('p', [h('span', 'h()1 渲染内容')]),
h('p', 'h()2 渲染内容'),
h('p', 'h()3 渲染内容'),
])
}
4、h() 函数 接收 props
中数据
<template>
<div class="my-h">
This is a h() demo .
<hr></hr>
<vnodeDiv :name="name"></vnodeDiv>
</div>
</template>
<script setup>
import { ref, h } from 'vue'
const name = ref('Andy')
// 这里与 setup() {} 一样,可以接收 props, context
// context.attrs, context.emit, context.slots
const vnodeDiv = (props, {attrs, emit, slots}) => {
console.log('---props-', props)
return h('div', { class: 'my-div', dataType:"ces" }, [
h('p', [h('span', props.name)]), // Andy
h('p', 'h()2 渲染内容'),
h('p', 'h()3 渲染内容'),
])
}
</script>
5、h() 函数 接收emit
事件
事件以驼峰方式命名onXxx
如:onClick: ()=>{}
<template>
<div class="my-h">
This is a h() demo .
<hr></hr>
<vnodeDiv :name="name" @click="handleClick"></vnodeDiv>
</div>
</template>
<script setup>
import { ref, h } from 'vue'
const name = ref('Andy')
const handleClick = (data) => {
console.log('====', data) // 这里得到子组件 触发事件 的参数
}
const vnodeDiv = (props, {attrs, emit, slots}) => {
console.log('---props-', props)
return h('div', { class: 'my-div', dataType:"ces" }, [
h('p', {
onClick: () => {
// 使用emit 触发父组件事件
emit('click', props.name)
}}, 'h()2 渲染内容')
])
}
</script>
6、h() 函数 定义插槽 slots
通过 slots.xxx
语法定义插槽
如:匿名插槽 slots.default
;具名插槽 slots.footer
<div class="my-h">
This is a h() demo .
<hr></hr>
<vnodeDiv :name="name" @click="handleClick">
<template #default>
<div class="default-">
这是默认插槽
</div>
</template>
<template #footer>
<div class="default-footer">
这是具名插槽 footer
</div>
</template>
</vnodeDiv>
</div>
</template>
<script setup>
import { ref, h } from 'vue'
const name = ref('Andy')
const handleClick = (data) => {
console.log('====', data) // 这里得到子组件 触发事件 的参数
}
const vnodeDiv = (props, {attrs, emit, slots}) => {
console.log('---props-', props)
return h('div', { class: 'my-div', dataType:"ces" }, [
h('p', [h('span', props.name)]),
h('p', {
onClick: () => {
emit('click', props.name)
}}, 'h()2 渲染内容'),
h('p', 'h()3 渲染内容'),
// 定义默认插槽 // 具名插槽 footer 这里可以定义多个插槽名称
], slots.default(), slots.footer())
}
</script>
7、h() 函数 渲染列表
<template>
<div class="my-h">
This is a h() demo .
<hr></hr>
<vnodeDiv :name="name" @click="handleClick">
<template #default>
<div class="default-">
这是默认插槽
</div>
</template>
<template #footer>
<div class="default-footer">
这是具名插槽 footer
</div>
</template>
</vnodeDiv>
</div>
</template>
<script setup>
import { ref, h } from 'vue'
const name = ref('Andy')
const lists = ref([
{ name: 'Andy1', age: 18 },
{ name: 'Andy2', age: 19 },
{ name: 'Andy3', age: 22 },
])
const handleClick = (data) => {
console.log('====', data) // 这里得到子组件 触发事件 的参数
}
const vnodeDiv = (props, {attrs, emit, slots}) => {
console.log('---props-', props)
return h('div', { class: 'my-div', dataType:"ces" }, [
// 接收 props 中的数据
h('p', [h('span', props.name)]),
h('p', {
onClick: () => {
emit('click', props.name)
}
}, 'h()2 渲染内容'),
// 循环渲染列表
h('p', lists.value && lists.value.length && lists.value.map(itm => {
return h('p', [h('span', itm.name), '~', h('span', itm.age)])
})),
// 定义默认插槽
], slots.default(), slots.footer())
}
</script>
运行结果如下:
对于 h() 函数 与 JSX 语法的使用,个人感觉 JSX 语法更灵活方便。