热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

何时/使用Vue3render函数的教程详解_vue.js

这篇文章主要介绍了何时使用Vue3render函数的教程详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,

什么是 DOM?

如果我们把这个 HTML 加载到浏览器中,浏览器创建这些节点,用来显示网页。所以这个HTML映射到一系列DOM节点,然后我们可以使用Javascript进行操作。例如:

let item = document.getElementByTagName('h1')[0]
item.textCOntent= "New Heading"

VDOM

网页可以有很多DOM节点,这意味着DOM树可以有数千个节点。这就是为什么我们有像Vue这样的框架,帮我们干这些重活儿,并进行大量的Javascript调用。

然而,搜索和更新数千个DOM节点很明显会变慢。这就是Vue和其他类似框架有一种叫做虚拟DOM的东西。虚拟DOM是表示DOM的一种方式。例如,这个HTML也可以通过一个虚拟节点来表示,看起来像这样。如您所见,它只是一个Javascript对象。

Hello
{
 tag: 'div',
 children: [
 {
 text: 'Hello'
 }
 ]
}

Vue知道如何使用此虚拟节点并挂载到DOM上,它会更新我们在浏览器中看到的内容。实际上还有一个步骤其中,Vue基于我们的模板创建一个渲染函数,返回一个虚拟DOM节点。

渲染函数可以是这样的:

render(h) {
 return h('div', 'hello')
}

当组件更改时,Render函数将重新运行,它将创建另一个虚拟节点。然后发送旧的 VNode 和新的 VNode 到Vue中进行比较并以最高效的方式在我们的网页上更新。

我们可以将虚拟DOM和实际DOM的关系类比为蓝图和实际建筑的关系。假设我更改了29楼的一些数据。我改变了家具的布局还加了一些橱柜。我有两种方法可以改变。首先,我可以拆除29楼的一切从头开始重建。或者我可以创造新的蓝图,比较新旧蓝图并进行更新以尽可能减少工作量。这就是虚拟DOM的工作原理。Vue 3让这些更新更快并且更高效。

核心模块

Vue 的三个核心模块:

  • Reactivity Module 响应式模块
  • Compiler Module 编译器模块
  • Renderer Module 渲染模块

响应式模块允许我们创建 Javascript 响应对象并可以观察其变化。当使用这些对象的代码运行时,它们会被跟踪,因此,它们可以在响应对象发生变化后运行。

编译器模块获取 HTML 模板并将它们编译成渲染函数。这可能在运行时在浏览器中发生,但在构建 Vue 项目时更常见。这样浏览器就可以只接收渲染函数。

渲染模块的代码包含在网页上渲染组件的三个不同阶段:

  • 渲染阶段
  • 挂载阶段
  • 补丁阶段

在渲染阶段,将调用 render 函数,它返回一个虚拟 DOM 节点。
在挂载阶段,使用虚拟DOM节点并调用 DOM API 来创建网页。
在补丁阶段,渲染器将旧的虚拟节点和新的虚拟节点进行比较并只更新网页变化的部分。

现在让我们来看一个例子,一个简单组件的执行。它有一个模板,以及在模板内部使用的响应对象。首先,模板编译器将 HTML 转换为一个渲染函数。然后初始化响应对象,使用响应式模块。接下来,在渲染模块中,我们进入渲染阶段。这将调用 render 函数,它引用了响应对象。我们现在监听这个响应对象的变化,render 函数返回一个虚拟 DOM 节点。接下来,在挂载阶段,调用 mount 函数使用虚拟 DOM 节点创建 web 页面。最后,如果我们的响应对象发生任何变化,正在被监视,渲染器再次调用render函数,创建一个新的虚拟DOM节点。新的和旧的虚拟DOM节点,发送到补丁函数中,然后根据需要更新我们的网页。

渲染器机制

拥有虚拟DOM层有一些好处,最重要的是它让组件的渲染逻辑完全从真实DOM中解耦,并让它更直接地重用框架的运行时在其他环境中。例如,Vue允许第三方开发人员创建自定义渲染解决方案目标,不仅仅是浏览器也包括IOS和Android等原生环境,也可以使用API创建自定义渲染器直接渲染到WebGL而不是DOM节点。在Vue 2中我们实际上已经有了这种能力但是,我们在Vue 2中提供的API没有正式记录并且需要分叉源代码。所以这给维护带来了很大的负担,对开发这些定制解决方案的开发人员在Vue 3中,我们让自定义渲染器API成为一等公民。因此开发人员可以直接拉取Vue运行时核心作为依赖项,然后利用自定义渲染器API构建自己的自定义渲染器。事实上,我们已经有了早期用户报告他们已经成功地构建了一个使用Vue 3 API关于虚拟DOM的WebGL渲染器。

另一个重要方面,它提供了能力以编程方式构造、检查、克隆以及操作所需的DOM结构,在实际返回渲染引擎之前你可以利用Javascript的全部能力做到这些。这个能力很重要,因为总会有某些情况在UI编程中使用模板语法会有一些限制,你只需要一种有充分灵活性的合适的编程语言来表达潜在的逻辑。现在,这种情况实际上是相当罕见的在日常UI开发中。但当你在创作一个库的时候,这种情况更常见或编写UI组件套件,你打算上传供第三方开发者使用。让我们想象一下一个,像复杂类型的顶部框这样的组件或者一个与一堆文本相关联的输入框,这些类型的组件通常包含很少的标记,但它们将包含很多交互逻辑在这些情况下,模板语法有时候会限制你更容易地表达潜在的逻辑,或者有时候你会发现自己在模板中加入了很多逻辑,但你还是有很多逻辑在Javascript 中而 render 函数允许你把这些逻辑组合在一个地方你通常不需要想太多关于这些情况下的标记。

所以我理解是模板会完成你要做的事在99%的情况下你只需要写出HTML就好了,但偶尔可能想做些更可控的事情在,你需要编写一个渲染函数。Vue 2中的渲染函数如下所示,

render(h) {
 return h (
 'div', {
 attrs: {
 id: foo
 },
 on: {
 click: this.onClick
 },
 'hello'
 })
}

所以这是组件定义中的一个选项,相对于提供一个 template 选项,在 Vue 2 中你可以为组件提供一个渲染函数,你会得到 h 参数,直接作为渲染函数的参数。你可以用它来创造我们称之为虚拟DOM节点,简称 vnode。

vnode 接受三个参数:

  • 第一个参数是类型,所以我们在这里创建一个 div。
  • 第二个参数是一个对象包含 vnode 上的所有数据或属性,API有点冗长从某种意义上说,你必须指明传递给节点的绑定类型。例如,如果要绑定属性你必须把它嵌套在attrs对象下如果要绑定事件侦听器你得把它列在 on 下面。
  • 第三个参数是这个 vnode 的子节点。所以直接传递一个字符串是一个方便的 API,表明此节点只包含文本子节点,但它也可以是包含更多子节点的数组。所以你可以在这里有一个数组并且嵌套了更多的嵌套 h 调用。

在Vue 3中我们改变了API,目标是简化它。

import { h } from 'vue'
 
render () {
 return h(
 'div', 
 {
 id: 'foo',
 onClick: this.onClick
 },
 'hello'
 })
}

第一个显著的变化是我们现在有了一个扁平的 props 结构。当你调用 h 时,第二个参数现在总是一个扁平的对象。你可以直接给它传递一个属性,这里我们只是给它一个 ID。按惯例监听器以 on 开头,所以任何带 on 的都会自动绑定为一个监听器所以你不必考虑太多嵌套的问题。

在大多数情况下,你也不需要思考是应将其作为 attribute 绑定还是DOM属性绑定,因为 Vue 将智能地找出为你做这件事的最好方法。我们检查这个 key 是否作为属性存在在原生 DOM 中。如果存在,我们会将其设置为 property,如果它不存在,我们将它设置为一个attribute。

render API 的另一项改动是 h helper 现在是直接从 Vue 本身全局导入的。一些用户在 Vue 2 中因为 h 在这里传递而在这里面 h 又很特别,因为它绑定到当前组件实例。当你想拆分一个大的渲染函数时,你必须把这个 h 函数一路传递给这些分割函数。所以,这有点困难,但有了全局引入的 h 你导入一次就可以分割你的渲染函数,在同一个文件里分割多少个都行。

渲染函数不再有 h 参数了,在内部它确实接收参数,但这只是编译器使用的用来生成代码。当用户直接使用时,他们不需要这个参数。所以,如果你用 TypeScript 使用定义的组件 API 你也会得到 this 的完整类型推断。

Q&A

1.我知道原始的那种虚拟 Dom 的实现得到了启发来自其他项目对吗?

是的有一个库叫snabbdomVue 2基本上就是从这个库中分离出来的。

2.好的然后是Vue 3,你在这里的编码方式只是改进了Vue 2的模式吗?

好吧,Vue 3是一个彻底的重写,几乎从头开始一切都是定制的显然,有现有的算法看起来像没有变化,因为这些是我们看到社区在做广泛研究的领域所以这是建立在所有这些以前的实现的基础上的但代码本身现在是从头开始。

3.都是用TypeScript写的,对吧?

是的,都是 TypeScript 写的。

何时/如何使用 render 函数

看看渲染函数在 Vue 中是什么样子。在 Vue 2 中,一个传统的 Vue 组件,有一个 template 选项,但是为了重用渲染函数我们可以用一个名为 render 的函数来代替它,我们会通过参数得到这个称为 h(hyperscript)。但在这里,我们只是示范一下我们如何在 Vue 3 中使用它。我们会从 vue 导入 h,我们可以用它来返回 h。

import { h } from 'vue'
 
const App = {
 render () {
 return h('div') 
 }
}
 
// 等效模板中的普通 div

1.所以它返回 div 的 Javascript 对象表示?

完全正确。

2.那么,你的虚拟dom就像…编译器?是编译器接收它吗?

是渲染器,渲染器接收它。

3.然后它实际上进行 dom 调用将其带入浏览器?

完全正确。

所以我们可以给这个虚拟节点一些 props,

import { h } from 'vue'
 
const App = {
 render () {
 return h(
 'div',
 {
 id: 'hello'
 },
 [
 h('span','world')
 ]
 ) 
 }
}
 
// 
world

现在,我们知道如何生成静态结构。但是当人们第一次使用 render 函数会问 “我该怎么写,比如说,v-if 或者 v-for”?我们没有像 v-if 或者类似的东西。相反,您可以直接使用 Javascript。

import { h } from 'vue'
 
const App = {
 render () {
 return this.ok
 ? h('div',{ id: 'hello' },[h('span','world')]
 : h('p', 'other branch')
 ) 
 }
}

如果 ok 的值为 true,它将呈现 div,反之,它将呈现 p。同样,如果你想做 v-else-if 你需要嵌套这个三元表达式:

import { h } from 'vue'
 
const App = {
 render () {
 return this.ok
 ? h('div',{ id: 'hello' },[h('span','world')]
 : this.otherCondition
 ? h('p', 'other branch')
 : h('span')
 ) 
 }
}

我想你可能会喜欢创建一个变量,将不同的节点添加到该变量。所以当你不得不将这整个东西嵌套在一个表达式调用中这会很有用,但你不必这么做。

import { h } from 'vue'
 
let nodeToReturn
if(this.ok) {
 nodeToReturn = ...
} else if () {
 
}
 
const App = {
 render () {
 return this.ok
 ? h('div',{ id: 'hello' },[h('span','world')]
 : this.otherCondition
 ? h('p', 'other branch')
 : h('span')
 ) 
 }
}

这就是 Javascript 灵活的地方,这看起来更像普通的 Javascript。当你的代码变得更加复杂时您可以使用普通的 Javascript 重构技巧使它们更容易理解。

我们讨论了 v-if, 接下来看看 v-for。 类似的,你也可以给它们加上 key,这是渲染函数中的渲染列表。

import { h } from 'vue'
 
const App = {
 render () {
 return this.list.map(item => {
 return h('div', {key: item.id}, item.text)
 })) 
 }
}

在渲染函数中,您可能要处理插槽。当你写一个重标记组件(markup heavy component),或者我更喜欢称之为特性组件(feature component),它与你的应用程序的外观布局结构有关,将实际的 HTML 显示给用户。对于那些类型的组件,我更喜欢始终使用模板。只有在我必须使用渲染函数的时候,比如我在写一些功能型的组件,有时会期望获取一些插槽内容,将其打包或者以某种方式操纵他们。在 Vue 3 里默认插槽将暴露在这个 this.$slot.default。如果对于组件什么都没有提供,这将是 undefined,所以你得先检查一下它的存在。如果它存在,它将永远是一个数组。有了作用域槽,我们可以将 props 传递给作用域槽,所以把数据传递到作用域槽只是通过传递一个参数到这个函数调用中。因为这是一个数组你可以将它直接放在 children 位置。

import { h } from 'vue'
 
const App = {
 render () {
 const slot = this.$slot.default
 ? this.$slot.default()
 : []
 
 return h('div', slot)
 }
}

你可以在 render 函数中用插槽做一件很强大的事,比如以某种方式操纵插槽,因为它只是一个 Javascript 对象数组,你可以用 map 遍历它。

import { h } from 'vue'
 
const App = {
 render () {
 const slot = this.$slot.default
 ? this.$slot.default()
 : []
 
 slot.map(vnode => {
 return h('div', [vnode])
 })
 }
}

这里有一个例子,截住并更改插槽数据。假设我们有一个堆栈组件(tack component),在一些用户界面库(UI libraries)中很常见。你可以传递很多属性给它,得到嵌套的堆栈渲染结果,有点像 HTML 中 ulol 的默认样式。


 
hello
hello
hello

渲染成这样:

hello
hello

这里有一个普通的基于模板的语法,在同一个插槽内它们都是默认插槽,你能做的只有渲染这个部分,在模板很难实现。但是你可以用渲染函数来实现,程序化的遍历插槽内的每个项目然后把它们变成别的东西。

import { h } from 'vue'
 
const Stack = {
 render () {
 const slot = this.$slots.default
 ? this.$slots.default()
 : []
 
 return h(
 'div',
 {class: 'stack'},
 slot.map(child => {
 return h(
  'div', 
  {class: `mt-${this.$props.size}`},
  [child]
  )
 })
 )
 }
}

我们用 slot.map 生成新的 vnode 列表,原来的子插槽被包装在里面。有了这个,我们把它放到一个 stack.html 文件里。

stack.html



 
 

当你创作这些底层的公用设施组件,有时真的会遇到麻烦,这时渲染函数更有效。但话说回来,也需要了解每种方法的利弊,这些是为了让你更好地理解在什么情况下应该使用模板或使用渲染函数。基本上是当你用一个模板时遇到限制时,比如你就像我们刚才看到的那样,可能改为使用渲染函数会更有效。当你意识到想表达的逻辑用 Javascript 更容易而不是使用模板语法时就使用它。从我的经验来看,这种情况在您创作可重用的功能组件,要跨多个应用程序共享或者在组织内部共享时更常见。在日常开发中你主要是在编写特性组件,模板通常是有效的方式,模板的好处是更简单,当你有很多标记的时候会通过编译器优化,它的另一个好处是它更容易让设计师接管组件并用CSS设计样式。因此,Vue 提供了这两个选项,当情况出现的时候以便您可以选择合适的方式。


推荐阅读
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • Java和JavaScript是什么关系?java跟javaScript都是编程语言,只是java跟javaScript没有什么太大关系,一个是脚本语言(前端语言),一个是面向对象 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
  • React基础篇一 - JSX语法扩展与使用
    本文介绍了React基础篇一中的JSX语法扩展与使用。JSX是一种JavaScript的语法扩展,用于描述React中的用户界面。文章详细介绍了在JSX中使用表达式的方法,并给出了一个示例代码。最后,提到了JSX在编译后会被转化为普通的JavaScript对象。 ... [详细]
  • macOS Big Sur全新设计大版本更新,10+个值得关注的新功能
    本文介绍了Apple发布的新一代操作系统macOS Big Sur,该系统采用全新的界面设计,包括图标、应用界面、程序坞和菜单栏等方面的变化。新系统还增加了通知中心、桌面小组件、强化的Safari浏览器以及隐私保护等多项功能。文章指出,macOS Big Sur的设计与iPadOS越来越接近,结合了去年iPadOS对鼠标的完善等功能。 ... [详细]
  • 如何实现JDK版本的切换功能,解决开发环境冲突问题
    本文介绍了在开发过程中遇到JDK版本冲突的情况,以及如何通过修改环境变量实现JDK版本的切换功能,解决开发环境冲突的问题。通过合理的切换环境,可以更好地进行项目开发。同时,提醒读者注意不仅限于1.7和1.8版本的转换,还要适应不同项目和个人开发习惯的需求。 ... [详细]
author-avatar
Era_zhou
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有