Vue | Vue深入浅出——Vue中的render函数详解

1.render函数

在编写vue单文件的大多数情况下,我们都是使用template模板来创建HTML。然而在一些条件判断比较复杂的场景下,使用JavaScript去描绘HTML的生成逻辑会显得更加的简洁直观。

使用Vue官网的例子来简单说明:

如果自己在开发的时候,编写的每个标题(包括h1~h6)都需要带锚点,如下所示:

<h1><a name="hello-world" href="#hello-world">Hello world!</a>
</h1>

如果用template模板进行编写,会如下所示:

<template><h1 v-if="level === 1"><anchor :name="name" :content="content"></anchor></h1><h2 v-else-if="level === 2"><anchor :name="name" :content="content"></anchor></h2><h3 v-else-if="level === 3"><anchor :name="name" :content="content"></anchor></h3><h4 v-else-if="level === 4"><anchor :name="name" :content="content"></anchor></h4><h5 v-else-if="level === 5"><anchor :name="name" :content="content"></anchor></h5><h6 v-else-if="level === 6"><anchor :name="name" :content="content"></anchor></h6>
</template>
<script>
export default {name:'anchor-header',props:{level:Number,name:String,content:String},components:{'anchor':{props:{content:String,name:String},template:'<a :id="name" :href="`#${name}`"> {{content}}</a>'}}
}
</script>

显然代码冗长累赘。但如果用render函数来编写则如下所示:

<script>
export default {name:'anchor-header',props:{level:Number,name:String,content:String},render:function(createElement){const anchor={props:{content:String,name:String},template:'<a :id="name" :href="`#${name}`"> {{content}}</a>'}const anchorEl=createElement(anchor,{props:{content:this.content,name:this.name}})const el=createElement(`h${this.level}`,[anchorEl])return el}
}
</script>

可见通过render函数编写出的逻辑更加简洁且可读性更高。

每一个render函数都要return一个VNode类型的变量,是Vue中自定义的虚拟节点(virtual node),用于替换挂载元素$el。

Vue 选项中的 render 函数若存在,则 Vue 构造函数不会从 template 选项或通过 el 选项指定的挂载元素中提取出的 HTML 模板编译渲染函数。

但自己实践在vue单文件实践后发现,如果同时存在templaterender,生成的html会以template的逻辑为主,奇怪。

上述例子的代码可以知道,render函数使用的场景是,要根据不同条件切换不同HTML标签,可以使用render函数。或者条件判断较多的template中,用渲染函数编写会让代码的可读性更高的情况下,也推荐使用render函数。

下面分析上面代码中出现的createElement函数。

2.createElement

createElement用于创建且return一个VNode类型的变量(虚拟节点),以下是该函数的传入参数:

(1)一个 HTML 标签名、组件选项对象或者resolve前面两种之一类型的async函数。必填。

例如,传入'div'表示想创建一个html标签为div的VNode;如果传入'transition'代表创建transition组件。

上面作为粒子的代码就是根据传入的类型为Number的参数level,用模板字符串拼接成标签名称。传入level为1则拼接出来的HTML标签名称为h1。代表要创建html标签为h1的VNode。

(2)所创建的VNode中所需参数为属性的数据对象。可选。

{class,style,attrs,props,domProps,on,nativeOn,directives:[{name,value,expression,arg,modifiers}],scopedSlots:{default:props=>createElement()},slot,key,ref,refInFor
}

大部分属性和vue组件中存在的属性的作用一样,我就只挑几个比较特殊的属性来说明:

**nativeOn:**用于监听原生事件,而不是组件内使用。例如:

nativeOn: {click: this.nativeClickHandler}

相当于@click.native="nativeClickHandler"

scopedSlots:定义作用域插槽的内部的内容:

格式为:{ name: props => VNode | Array<VNode> }

举一个例子:

<script>
export default {render (createElement) {var component = {template: `<div><slot></slot><slot name="foo"></slot></div>`}return createElement(component, {scopedSlots: {default: props => createElement('span', '456'),foo: props => createElement('span', '789')},})}
}
</script>

最后渲染出来的html效果如下:

<div><span>456</span><span>789</span>
</div>

scope:如果要生成的组件要插入到,需为插槽指定名称。

举个例子

<script>
export default {render (createElement) {var component = {template: `<div><slot></slot><slot name="foo"></slot></div>`}const childrenEl = createElement('span', { slot: 'foo' }, '123')return createElement(component, {scopedSlots: {default: props => createElement('span', '456')// foo: props => createElement('span', '789')      },}, [childrenEl])}
}
</script>

最后渲染出来的html效果如下:

<div><span>456</span><span>123</span>
</div>

注意:如果去掉上面例子的代码中// foo: props => createElement('span', '789')的注释,则slot="foo"插槽中显示内容依然为<span>789</span>

**  refInFor:**如果你在渲染函数中给多个元素都应用了相同的 ref 名,那么 `$refs.myRef` 会变成一个数组。

(3)子级虚拟节点 (VNodes)。如果传入的是VNode则要用列Array传入,另外也可以使用字符串来生成“文本虚拟节点”。可选。

3.函数式组件

函数式组件相比于一般的vue组件而言,最大的区别是非响应式的它不会监听任何数据,也没有实例(因此没有状态,意味着不存在诸如created,mounted的生命周期)。好处是因只是函数,故渲染开销也低很多。

把开头的例子改成函数式组件,代码如下:

<script>
export default {name:'anchor-header',functional:true, // 以functional:true声明该组件为函数式组件props:{level:Number,name:String,content:String},// 对于函数式组件,render函数会额外传入一个context参数用来表示上下文,即替代this。函数式组件没有实例,故不存在thisrender:function(createElement,context){ const anchor={props:{content:String,name:String},template:'<a :id="name" :href="`#${name}`"> {{content}}</a>'}const anchorEl=createElement(anchor,{props:{content:context.props.content, //通过context.props调用props传入的变量name:context.props.name}})const el=createElement(`h${context.props.level}`,[anchorEl])return el}
}
</script>

渲染函数 & JSX — Vue.js:更多关于函数式组件内容请看官网函数式组件

4.element-ui的el-row组件

最后以el-row组件的源码来分析,该源码的渲染逻辑在render函数上,非常简洁明了:

export default {name: 'ElRow',componentName: 'ElRow',props: {tag: {type: String,default: 'div'},gutter: Number,type: String,justify: {type: String,default: 'start'},align: {type: String,default: 'top'}},computed: {style() {const ret = {};if (this.gutter) {ret.marginLeft = `-${this.gutter / 2}px`;ret.marginRight = ret.marginLeft;}return ret;}},render(h) {return h(this.tag, {class: ['el-row',this.justify !== 'start' ? `is-justify-${this.justify}` : '',this.align !== 'top' ? `is-align-${this.align}` : '',{ 'el-row--flex': this.type === 'flex' }],style: this.style}, this.$slots.default);}
};

对着el-row组件传入参数的说明图来解释:

直接从render函数处进行分析,

1.传入第一个参数为this.tag,用于根据参数生成对应的html标签。

2.第二个参数中传入classstyle是根据props中的type,gutter,justify,align生成的。

3.第三个参数传入子节点。此处通过this.$slots.default拿到传入的子节点。例如:

<el-row><div>123</div>
</el-row>

此时,this.$slots.default 获取的数据则是一个包含上面<div>123</div>的VNode的数组。

以下内容来自官网:

拓展:slots() 和 children 对比

你可能想知道为什么同时需要 slots() childrenslots().default 不是和 children 类似的吗?在一些场景中,是这样——但如果是如下的带有子节点的函数式组件呢?

<my-functional-component><p v-slot:foo>first</p><p>second</p>
</my-functional-component>

对于这个组件,children 会给你两个段落标签,而 slots().default 只会传递第二个匿名段落标签,slots().foo 会传递第一个具名段落标签。同时拥有 children slots(),因此你可以选择让组件感知某个插槽机制,还是简单地通过传递 children,移交给其它组件去处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/422130.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

部署Apache网站

简易部署自己的apache网站 写在前面&#xff1a;先安装好mysql&#xff0c;再来搭建站点 1.安装php [rootlocalhost ~]# yum install php -y ##安装了php&#xff0c;默认会和apache结合工作2.创建文件编写php网页代码 [rootlocalhost ~]# vim /var/www/html/index.php ##创…

linux入门到实操-1 Linux概述、诞生过程、发行版本,如何安装?

教程来源&#xff1a;B站视频BV1WY4y1H7d3 3天搞定Linux&#xff0c;1天搞定Shell&#xff0c;清华学神带你通关_哔哩哔哩_bilibili 整理汇总的课程内容笔记和课程资料&#xff0c;供大家学习交流下载&#xff1a;夸克网盘分享 本文内容为完整笔记的入门篇 概述部分历史内容…

Day9 | Java框架 | SpringBoot

Day9 | Java框架 | SpringBoot SpringBoot简介入门程序概述起步依赖 基础配置配置文件格式&#xff1a;3种yaml语法规则yaml数据读取三种格式 多环境启动配置文件参数命令行参数多环境开发控制&#xff1a;Maven & SpringBoot 多环境兼容 配置文件分类&#xff1a;4种 整合…

【JUC】15-ThreadLocal线程局部变量

1. ThreadLocal ThreadLocal提供线程局部变量。每个线程在访问ThreadLocal实例的时候都有自己的、独立的变量副本。ThreadLocal实例通常是类中的私有静态字段&#xff0c;使用它的目的是希望将状态(用户ID或事务ID)与线程关联起来。 class Saler {ThreadLocal<Integer> …

MATLAB实现Dijkstra算法和Floyd算法

目录 1、文件功能介绍 2、代码执行效果展示 3、Dijkstra算法求图的单源最短路径 4、Dijkstra fullPath的更新逻辑 5、DIjkstra算法流程图 6、Floyd算法实现图的任意两点间最短路径 7、Floyd算法流程图 8、Floyd fullPath的更新逻辑&#xff08;非递归算法&#xff09; …

labview串口大数据量报错的一种解决思路(通过tcp进行写入和读取串口数据)

因为项目要求&#xff0c;用labview给客户开发了一个上位机&#xff0c;在现场给客户调试上位机时&#xff0c;发现了几种奇怪的现象 1&#xff1a;客户样件有两路串口&#xff0c;一路串口可以多字节进行发送数据&#xff0c;一路只能单字节发送数据&#xff0c;每次单字节数据…

Pygame中获取鼠标按键状态的方法

在《Pygame中获取鼠标位置的方法》中提到&#xff0c;可以通过鼠标事件和mouse模块中的函数获取鼠标位置&#xff0c;这两种方法同样适用于获取鼠标按键状态。 1 通过鼠标点击事件获取鼠标按键状态 通过鼠标点击事件获取鼠标按键状态的代码如图1所示。 图1 鼠标点击事件获取鼠…

Gin-封装自动路由

O.0 思路一、API二、控制层三、自动路由核心四、分组路由外加中间件使用 思路 由于Java转Go直接使用的goframe框架&#xff0c;然学习Gin时觉得一个接口一个路由太麻烦&#xff0c;于是有了...1、在请求结构体中采用标签的形式&#xff0c;直接给出路由和请求方式 2、在控制层…

QXml 使用方法

VS2019 QT 编译工具链问题解决 使用winqtdeploy.exe 打包环境就可以正常运行&#xff0c;缺少某一个运行库引起的 简易使用python脚本编译运行 Python3 中的 slots 和 QT 中的 slots 宏定义重复, 放在不同的文件中进行调用可以避免 还是比较习惯从源码包引入&#xff08;方便定…

【区块链通用服务平台及组件】信息数据流转验真技术研究项目 | FISCO BCOS应用案例

在日常工作中&#xff0c;相关系统每天会产生大量数据&#xff0c;系统之间有多种模式数据交互方式&#xff0c;数据监管工作量巨大&#xff0c;急需 数据追溯定位工具来辅助监管&#xff1b;数据在生产过程中经常会出现采集、提交、修改、删除等操作&#xff0c;需要对数据变更…

Vue(9)——.sync修饰符、ref和$refs、$nextTick

.sync 作用:可以实现子组件与父组件数据的双向绑定&#xff0c;简化代码。 特点&#xff1a;prop属性名&#xff0c;可以自定义&#xff0c;非固定位value 场景&#xff1a;封装弹框类的基础组件&#xff0c;visible属性 true显示&#xff0c;false隐藏 本质&#xff1a;就是 …

鸿蒙界面开发——组件(7):组件导航 页面路由

组件导航 (Navigation)(推荐) Navigation() Navigation(pathInfos: NavPathStack)Navigation是路由容器组件&#xff0c;一般作为首页的根容器&#xff0c;包括单栏(Stack)、分栏(Split)和自适应(Auto)三种显示模式。Navigation组件适用于模块内和跨模块的路由切换&#xff0c…

2024年金九银十最新版Java面试题及答案整理(持续更新)

2024年金九银十到了&#xff0c;发现网上很多Java面试题都没有答案&#xff0c;所以花了很长时间搜集整理出来了这套Java面试题大全~这套互联网 Java 工程师面试题包括了&#xff1a;MyBatis、ZK、Dubbo、EL、Redis、MySQL、并发编程、Java面试、Spring、微服务、Linux、Spring…

文件加密最简单的方法有哪些?十个电脑文件加密方法【超详细】

在当今数字化和信息化的时代&#xff0c;数据已成为企业最重要的资产之一。内部数据外泄不仅可能导致商业秘密的丧失&#xff0c;还可能对企业的声誉和财务健康造成严重影响。为了有效防止内部数据外泄&#xff0c;企业需要实施综合的防泄密解决方案。以下是十大最佳防泄密解决…

内网安全-横向移动【3】

1.域横向移动-内网服务-Exchange探针 Exchange是一个电子右键服务组件&#xff0c;由微软公司开发。它不仅是一个邮件系统&#xff0c;还是一个消息与协作系统。Exchange可以用来构建企业、学校的邮件系统&#xff0c;同时也是一个协作平台&#xff0c;可以基于此开发工作流、…

19:I2C一:程序模拟I2C通信时序

I2C 1、什么是I2C2、I2C的通信时序2.1&#xff1a;起始信号2.2&#xff1a;停止信号2.3&#xff1a;主机向从机发送一个字节数据2.4&#xff1a;主机向从机读取一个字节数据2.5&#xff1a;主机接收应答2.6&#xff1a;主机发送应答 3、程序模拟I2C的通信时序3.1&#xff1a;指…

NX1872三维电气布线

电气部件审核与定义

Windows系统介绍

文章目录 1、Windows启动过程1.1 启动过程BIOS1.2 启动过程MBR1.3 启动过程 GPT1.4 启动过程BootMgr1.5 启动过程Winload.exe1.6 启动过程1.7 explorer.exe 2、Windows重要进程及组件2.1 注册表Services注册表服务管理器Services.mscsc.exe计划任务taskschd.msc计划任务schtask…

区块链学习笔记1--比特币

区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。 从狭义上来说&#xff1a;区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构&#xff0c;并以密码学的方式保证的不可篡改和不可伪造的分布式账本。 意思就是…

第67期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…