Vue 渲染函数 render 函数,h() 创建 VNode 虚拟节点 | js 实现模板功能 | 函数式组件
相较于模板,应用于更加灵活的场景预备知识实例 property 的 api
参考教程
相较于模板,应用于更加灵活的场景 – 渲染函数
预备知识实例 property 的 api
{
rander() {
return h('h1',xxx) // return h('h1',{},xxx)
}
}
// 相当于
template: `
<h1>
xxx
</h1>
`
h() 与 VNode
h() ==> createNodeDescription 创建节点描述 返回VNode
应该命名为 createVNode() 但由于频繁使用故 简化为 h()
-
第一个参数用于
确定tag
必需对于全局组件 需要解析(resolveComponent),局部注册可以跳过
参数类型: 字符串、对象、函数
一个 HTML 标签名 字符串、一个组件、一个异步组件、或 一个函数式组件。 -
第二个参数
与 attribute、prop 和事件相对应的对象对象
可选参数类型: 对象
prop 可以在组件 props选项 中定义,其他同理;
当第二参数为空时,可以省去
例如 class attribute 的对象:
// css
.btn{
width: 80px;
line-height: 40px;
text-align: center;
color:#fff;
border-radius: 5px;
background-color: #ccc;
}
.success{background-color: green;}
.error{background-color: red;}
.info{background-color: pink;}
h (
// 第一个参数
'my-btn',
// 第二个参数
{
class:{
btn:true,
success:this.type=="success", // 通过 type 配置 class
error:this.type=="error",
info:this.type=="info"
}
},
// 第三个参数
this.$slots.default
)
props:{
type:{
type:String,
defalut:''
}
}
等价于:
<template>
<div :class=ClassObj>
</div>
</tempalte>
<script>
export default {
name: 'MyBtn',
props:{
type: {
type:String,
defalut:''
}
},
data() {
return {
ClassObj: {
btn: true,
success: this.type=="success", // 通过 type 配置 class
error: this.type=="error",
info: this.type=="info"
}
}
}
}
</script>
<style>
.btn{
width: 80px;
line-height: 40px;
text-align: center;
color:#fff;
border-radius: 5px;
background-color: #ccc;
}
.success{background-color: green;}
.error{background-color: red;}
.info{background-color: pink;}
</style>
- 第三个参数 可以
控制插值
{数组 内容按元素顺序渲染} 可选参数类型: 字符串、对象、函数
可以是文本,也可以是 VNode 理解成 children
使用渲染函数编写一个组件时,访问 this.$slots 会很有帮助 可以规定命名插槽
// @returns {VNode}
h(
'div',
{}, // 可省略
[
'Some text comes first.', //字符串
h('h1', 'A headline'), //通过h()
h(MyComponent, { // 第二个参数对象中 定义了 someProp
someProp: 'foobar' //prop 对象
})
]
)
如果没有 prop,那么通常可以将 children 作为第二个参数传入。如果会产生歧义,可以将 null 作为第二个参数传入,将 children 作为第三个参数传入。
使用原生 JS 代替模板功能
v-for 和 v-if 的嵌套
props: ['items'],
render() {
if (this.items.length) { //v-if="this.items.length"
return h('ul', this.items.map((item) => { //v-for="item in items"
return h('li', item.name)
}))
} else { //v-else
return h('p', 'No items found.')
}
}
v-model
必须自己提供prop: modelValue
和 onUpdate:modelValue
props: ['modelValue'],
emits: ['update:modelValue'],
render() {
return h(SomeComponent, {
modelValue: this.modelValue,
'onUpdate:modelValue': value => this.$emit('update:modelValue', value)
})
}
v-on
注意 on前缀 和 驼峰命名
render() {
return h('div', {
onClick: $event => console.log('clicked', $event.target)
})
}
事件修饰符
对于 .capture、.passive 和 .once 事件修饰符,使用驼峰写法将他们拼接在事件名后面
render() {
return h('input', {
onClickCapture: xxx,
onKeyUp: event => {
// 如果触发事件的元素不是事件绑定的元素
// 则返回
if (event.target !== event.currentTarget) return
// 如果向上键不是回车键,则终止
// 没有同时按下按键 (13) 和 shift 键
if (!event.shiftKey || event.keyCode !== 13) return
// 停止事件传播
event.stopPropagation()
// 阻止该元素默认的 keyup 事件
event.preventDefault()
// ...
}
})
}
修饰符 | 处理函数中的等价操作 |
---|---|
.stop | event.stopPropagation() |
.prevent | event.preventDefault() |
.self | if (event.target !== event.currentTarget) return |
按键:.enter, .13 | if (event.keyCode !== 13) return (对于别的按键修饰符来说,可将 13 改为另一个按键码 |
修饰键:.ctrl, .alt, .shift, .meta | if (!event.ctrlKey) return (将 ctrlKey 分别修改为 altKey, shiftKey, 或 metaKey) |
插槽
this.$slots 可以向VNode中添加插槽
render() {
// `<div><slot :text="message"></slot></div>`
return h('div', {}, this.$slots.default({
text: this.message
}))
// 函数式 插槽
// 模板 `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>`
// 将插槽以 { name: props => VNode | Array<VNode> } 的形式传递给子对象。
//{
// default: (props) => Vue.h('span', props.text)
//}
}
<component>
和 is
在底层实现里,模板使用 resolveDynamicComponent 来实现 is attribute
// `<component :is="name"></component>`
render() {
const Component = resolveDynamicComponent(this.name)
return h(Component)
}
与 标签一样, 标签仅在模板中作为语法占位符需要,当迁移到 render 函数时,应被丢弃。
自定义指令
使用 withDirectives 将自定义指令应用于 VNode
内置组件
无法通过 resolveComponent 或 resolveDynamicComponent 访问它们
需要显式引入
render 渲染函数的返回值
- 单个根 VNode
return h()
- 一个字符串时会创建一个文本 VNode
return str
- 一个子元素数组
return ['Hello', h('br'), 'world!']
这会创建一个片段 - 返回 null,因为数据依然在加载中的关系,组件不需要渲染 会渲染一个注释节点
函数式组件
自身没有任何状态的组件的另一种形式。
它们在渲染过程中不会创建组件实例,并跳过常规的组件生命周期。
使用的是一个简单函数,而不是一个选项对象,来创建函数式组件
该函数实际上就是该组件的 render 函数。
const FunctionalComponent = (props, context) => {
// ...
}
函数式组件里没有 this 引用,Vue 会把 props 当作第一个参数传入
第二个参数 context 包含三个 property:attrs、emit 和 slots。
还是可以把 props 和 emits 作为对象属性加入FunctionalComponent.props = ['value']
将一个函数作为第一个参数传入 h(),它将会被当作一个函数式组件来对待。
更多推荐
所有评论(0)