1. vue2.x的 h 函数(createElement)

  1. 使用方法及介绍:(参考官网提取)
  2. h函数第一个是标签名字 或者是组件名字,第二个参数是配置项,第三个参数是 innerText ,不会帮你转换节点,如果需要转换成节点(v-html)请去第二个参数中的 domProps 配置 innerHTML
  3. 当第二个参数是字符串的时候则会直接当 innerText 渲染(相当于配置项参数为空对象)【h(‘span’, ‘姓名’)】
  4. 第三个参数如果为字符串的时候可以理解为默认值!(innerText的默认值)如果同时设置了这两个则配置中的权重更高
  5. 第三个参数也是该元素的子集合、插槽设置的地方。
  6. 温馨提示:vue2.x的h函数跟vue3.x的有点不一样,第二个参数配置项格式变了,第三个参数为函数返回,具体情况看本文第二要点
  7. 以下为常见的常规配置
import SelectEdit from './SelectEdit'
export default {data() {return {name: ''}},render(h) {// 如果使用原生的则// return h('div', {// 这个是挂载组件return h(SelectEdit, {// 此处是给 SelectEdit 组件传值的(props传值)props: {value: 1,type: 'on'},// class可以数组的形式也可以对象的形式// class: ['speci-class'],class: {'speci-class': true},// 样式有-的注意小驼峰 或者使用 string 模式style: {color: 'red',fontSize: '14px',// 或者这样'font-size': '14px'},// 普通的 HTML attributeattrs: {placeholder: '这是给原生html赋值placeholder属性'},// DOM propertydomProps: {innerHTML: 'DOM property',// 这个参数等同于h函数的第三个参数innerText: 'xxxxxxx'},// 这里是挂载方法的但不再支持如 `v-on:keyup.enter` 这样的修饰器on: {// 方法名可以自定义(组件内 $emit('xxxchange', {name: 'zs'}))'xxxchange': val => {this.name = val.name;},'click': val => {this.name = val.name;},},// 仅用于组件,用于监听原生事件,而不是组件内部使用// `vm.$emit` 触发的事件。nativeOn: {click: this.nativeClickHandler},// 自定义指令。注意,你无法对 `binding` 中的 `oldValue`directives: [{name: 'my-custom-directive',value: '2',expression: '1 + 1',arg: 'foo',modifiers: {bar: true}}],// 作用域插槽的格式为scopedSlots: {default: props => createElement('span', props.text)},// 如果组件是其它组件的子组件,需为插槽指定名称slot: 'name-of-slot',// 其它特殊顶层 propertykey: 'myKey',ref: 'myRef',// 如果你在渲染函数中给多个元素都应用了相同的 ref 名,// 那么 `$refs.myRef` 会变成一个数组。refInFor: true}, '这里是显示文本')}
}
  1. 举例子了:如果你想要实现以下效果(v-model)
 <div class="row zs active info" name="zs"><span style="background-color: red;font-size: 16px;" @click="handleName">姓名:</span><i >{{ name }}</i><input v-model="name" /></div>

目测没问题

 data() {return {name: ''}},render(h) {return h('div', {class: ['row zs', 'active', 'info'],attrs: {name: 'zs'}}, [h('span', {style: {backgroundColor: red,'font-size': '16px'},on: {click: handleName}}, '姓名:'),h('i', '张三'),h('input', {domProps: {value: this.name},on: {input: function (event) {this.$emit('input', event.target.value)}}})])}

2. vue3 h函数配置项

  1. 与2.x相比,第一个参数格式没有更变,第二个参数格式更变了,第三个参数变为建议使用函数返回了
  2. 第三个参数如果为字符串的时候可以理解为默认值!(innerText的默认值)如果同时设置了这两个则配置中的权重更高
  3. 第三个参数也是该元素的子集合、插槽设置的地方。
  4. 第三个参数不使用函数会有一个vue警告(所以说直接函数吧)
  5. 具体使用如下:
import { h } from 'vue';
import { ElButton } from 'element-plus'
h(ElButton,{type: 'primary',innerText: '修改11',onClick: () => {console.log(11);}},() => '修改'
)

2.1 v-model实现(以下开始为官网实现)

props: ['modelValue'],
emits: ['update:modelValue'],
render() {return h(SomeComponent, {modelValue: this.modelValue,'onUpdate:modelValue': value => this.$emit('update:modelValue', value)})
}

自己搞忘记后重新弄的踩坑记录:

  1. 双向绑定实现:2.x中是value,但是到了3.x中不是value了而是modelValue
  2. onUpdate:modelValue 相当于就是 v-model,只不过这个变成了函数,在这个函数里面需要你自己给绑定元素赋值。不赋值则会出现双向绑定失效的问题!

2.2 v-on

给定有效的事件名称,例如(onClick, onChange)或自定义的名称

render() {return h('div', {onClick: $event => console.log('clicked', $event.target)})
}

2.3 事件修饰符

对于 .passive 、.capture 和 .once 事件修饰符,可以使用驼峰写法将他们拼接在事件名后面:

render() {return h('input', {onClickCapture: this.doThisInCapturingMode,onKeyupOnce: this.doThisOnce,onMouseoverOnceCapture: this.doThisOnceInCapturingMode})
}

对于所有其它的修饰符,私有前缀都不是必须的,因为你可以在事件处理函数中使用事件方法:

这里是一个使用所有修饰符的例子:

render() {return h('input', {onKeyUp: event => {// 如果触发事件的元素不是事件绑定的元素// 则返回if (event.target !== event.currentTarget) return// 如果向上键不是回车键,则终止// 没有同时按下按键 (13) 和 shift 键if (!event.shiftKey || event.keyCode !== 13) return// 停止事件传播event.stopPropagation()// 阻止该元素默认的 keyup 事件event.preventDefault()// ...}})
}

2.4 插槽

你可以通过 this.$slots 访问静态插槽的内容,每个插槽都是一个 VNode 数组:

render() {// `<div><slot></slot></div>`return h('div', {}, this.$slots.default())
}
props: ['message'],
render() {// `<div><slot :text="message"></slot></div>`return h('div', {}, this.$slots.default({text: this.message}))
}

渲染函数将插槽传递给子组件

render() {// `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>`return h('div', [h(resolveComponent('child'),{},// 将 `slots` 以 { name: props => VNode | Array<VNode> } 的形式传递给子对象。{default: (props) => h('span', props.text)})])
}

插槽以函数的形式传递,允许子组件控制每个插槽内容的创建。任何响应式数据都应该在插槽函数内访问,以确保它被注册为子组件的依赖关系,而不是父组件。相反,对 resolveComponent 的调用应该在插槽函数之外进行,否则它们会相对于错误的组件进行解析。

// `<MyButton><MyIcon :name="icon" />{{ text }}</MyButton>`
render() {// 应该是在插槽函数外面调用 resolveComponent。const Button = resolveComponent('MyButton')const Icon = resolveComponent('MyIcon')return h(Button,null,{// 使用箭头函数保存 `this` 的值default: (props) => {// 响应式 property 应该在插槽函数内部读取,// 这样它们就会成为 children 渲染的依赖。return [h(Icon, { name: this.icon }),this.text]}})
}

如果一个组件从它的父组件中接收到插槽,它们可以直接传递给子组件。

render() {return h(Panel, null, this.$slots)
}

也可以根据情况单独传递或包裹住。

render() {return h(Panel,null,{// 如果我们想传递一个槽函数,我们可以通过header: this.$slots.header,// 如果我们需要以某种方式对插槽进行操作,// 那么我们需要用一个新的函数来包裹它default: (props) => {const children = this.$slots.default ? this.$slots.default(props) : []return children.concat(h('div', 'Extra child'))}})
}

2.5 component 和 is

在底层实现里,模板使用 resolveDynamicComponent 来实现 is attribute。如果我们在 render 函数中需要 is 提供的所有灵活性,我们可以使用同样的函数:

const { h, resolveDynamicComponent } = Vue// ...// `<component :is="name"></component>`
render() {const Component = resolveDynamicComponent(this.name)return h(Component)
}

就像 is, resolveDynamicComponent 支持传递一个组件名称、一个 HTML 元素名称或一个组件选项对象。

通常这种程度的灵活性是不需要的。通常 resolveDynamicComponent 可以被换做一个更直接的替代方案。

例如,如果我们只需要支持组件名称,那么可以使用 resolveComponent 来代替。

如果 VNode 始终是一个 HTML 元素,那么我们可以直接把它的名字传递给 h:

// `<component :is="bold ? 'strong' : 'em'"></component>`
render() {return h(this.bold ? 'strong' : 'em')
}

同样,如果传递给 is 的值是一个组件选项对象,那么不需要解析什么,可以直接作为 h 的第一个参数传递。

与 < template > 标签一样,< component > 标签仅在模板中作为语法占位符需要,当迁移到 render 函数时,应被丢弃。

2.6 自定义指令

可以使用 withDirectives 将自定义指令应用于 VNode:

const { h, resolveDirective, withDirectives } = Vue// ...// <div v-pin:top.animate="200"></div>
render () {const pin = resolveDirective('pin')return withDirectives(h('div'), [[pin, 200, 'top', { animate: true }]])
}

resolveDirective 是模板内部用来解析指令名称的同一个函数。只有当你还没有直接访问指令的定义对象时,才需要这样做

2.7 内置组件

诸如 < keep-alive >、< transition >、< transition-group > 和 < teleport > 等内置组件默认并没有被全局注册。这使得打包工具可以 tree-shake,因此这些组件只会在被用到的时候被引入构建。不过这也意味着我们无法通过 resolveComponent 或 resolveDynamicComponent 访问它们。

在模板中这些组件会被特殊处理,即在它们被用到的时候自动导入。当我们编写自己的 render 函数时,需要自行导入它们:

const { h, KeepAlive, Teleport, Transition, TransitionGroup } = Vue
// ...
render () {return h(Transition, { mode: 'out-in' }, /* ... */)
}

2.8 渲染函数的返回值

在我们目前看过的所有示例中,render 函数返回的是单个根 VNode。但其实也有别的选项。

返回一个字符串时会创建一个文本 VNode,而不被包裹任何元素:

render() {return 'Hello world!'
}

我们也可以返回一个子元素数组,而不把它们包裹在一个根结点里。这会创建一个片段 (fragment):

// 相当于模板 `Hello<br>world!`
render() {return ['Hello',h('br'),'world!']
}

可能是因为数据依然在加载中的关系,组件不需要渲染,这时它可以返回 null。这样我们在 DOM 中会渲染一个注释节点

2.9 JSX

如果你写了很多渲染函数,可能会觉得下面这样的代码写起来很痛苦:

h('anchored-heading',{level: 1},{default: () => [h('span', 'Hello'), ' world!']}
)

特别是对应的模板如此简单的情况下:

<anchored-heading :level="1"> <span>Hello</span> world! </anchored-heading>

这就是为什么会有一个 Babel 插件,用于在 Vue 中使用 JSX 语法,它可以让我们回到更接近于模板的语法上。

import AnchoredHeading from './AnchoredHeading.vue'const app = createApp({render() {return (<AnchoredHeading level={1}><span>Hello</span> world!</AnchoredHeading>)}
})app.mount('#demo')

有关 JSX 如何映射到 JavaScript 的更多信息,请参阅使用文档 。

参考链接

  1. vue2.x官网渲染函数
  2. vue3.x官网dom-树
  3. vue3.x官网渲染函数
  4. 本文仅做于笔记

vue2.x的h函数(createElement)与vue3中的h函数相关推荐

  1. python自带的sum()函数和numpy库中的sum()函数的区别

    在学习<机器学习实战>一书的第十章时,对 return np.sqrt(sum(np.power(vecA - vecB, 2))) 这样一条语句输出的结果老是不对,明明想要输出的是对两个 ...

  2. java中函数的调用,java中如何调用函数

    java动态调用函数,Java 中使用动态代码,java函数调用,java中如何调用函数 如何在 Java 中调用 C 函数 宗薇 [期刊名称]<网络新媒体技术> [年(卷),期]2000 ...

  3. python中lambda函数if用法-Python中关于Lambda函数的使用总结

    lambda表达式是一种匿名函数,对应python中的自定义函数def,是定义某个函数时比较高级的一种写法.作为python初学者,本文整理了lambda的一些基本用法和特点. lambda和def的 ...

  4. vue3中的setup函数

    一.概念: setup是vue3中的一个新的配置项,值为一个函数,我们在组件中用到的数据.方法等等,都要配置在setup中. 二.详解: setup函数的返回值有两种 1.返回一个渲染函数,可以自定义 ...

  5. Vue在渲染函数createELement和JSX中使用插槽slot

    Vue对于插槽有两个专门的APIvm.$slots和vm.$scopedSlots,分别是普通插槽和作用域插槽,使用JSX语法或渲染函数的时候,定义插槽将使用上述两个API. 渲染函数createEl ...

  6. C语言中比较大小的函数模板,C语言中实现模板函数小结 : 不敢流泪

    --by boluor 2009/5/20 如果要写个函数支持多种数据类型,首先想到的就是C++的模板了,但是有时候只能用C语言,比如在linux内核开发中,为了减少代码量,或者是某面试官的要求- 考 ...

  7. matlab中bwmorph函数的作用,Matlab中的bwmorph函数解释

    Matlab中的bwmorph函数解释 bwmorph:对二值图像的形态学操作. BW2 = bwmorph(BW,operation) BW2 =bwmorph(BW,operation,n) BW ...

  8. MATLAB解决线性规划问题,学会使用linprog函数,在一个实例中演示linprog函数各参数的用法

    最近接触到了一个线性规划的题目,尝试用MATLAB解决,动手前想了很多思路,上网搜索了一下发现MATLAB中有专门的linprog函数专门解决线性规划问题,了解学习后果然十分方便.事实上,绝大部分的线 ...

  9. c语言random函数在vc,C++ 中随机函数random函数的使用方法

    C++ 中随机函数random函数的使用方法 一.random函数不是ANSI C标准,不能在gcc,vc等编译器下编译通过. 可改用C++下的rand函数来实现. 1.C++标准函数库提供一随机数生 ...

最新文章

  1. python操作mongodb数据库
  2. MYSQL 练习题
  3. gtp怎么安装系统_UEFI+GTP模式下使用GHO文件安装WIN7或WIN8系统图文教程详解
  4. JDK10的新特性:本地变量类型var
  5. Gallery with Video
  6. es6判断对象key是否存在,ES6中获取对象的key
  7. 流程DEMO-合同会审表
  8. 选择多级分类_② 供应商管理(分类、评估、选择、绩效、集成、供应商过多的对策、多级供应商管理)...
  9. SAP云解决方案和企业本地部署(On-Premise)混合架构下的安全认证权限管理
  10. 【回顾】推荐系统的十二大评价指标总结
  11. CMU Database Systems - Concurrency Control Theory
  12. 【HDOJ】2809 God of War
  13. Android项目持续集成之Jenkins的使用
  14. 医疗NLP相关数据集整理
  15. ListView乱谈之ListView的布局
  16. Hello,CNDS!(第一次博客)
  17. java正则表达式校验车牌号_车牌号校验正则表达式
  18. SpringBoot整合freemarker模板导出word文件
  19. python人力成本数据测算_人工成本数据统计
  20. windows系统VS code coderunner 运行shell脚本

热门文章

  1. 目标检测论文解读复现之十五:基于YOLOv5的光学遥感图像舰船 目标检测算法
  2. 极好的搜索引擎: Goolgle 本网站和www搜索插件
  3. android国外网站
  4. jeecgboot初学习疑问与总结--2021-05-11
  5. 2022-06-06 FUSE用户态文件系统
  6. 查看Windows凭据存储密码的方法 2022亲测有效
  7. js 人民币小写金额转换为大写
  8. TCP/IP四层模型与OSI七层参考模型(网络协议)
  9. RichView TextBox Items 文本框
  10. 计算机网络学习 :互联网与万维网的区别