当前位置: 首页 > news >正文

顺义手机网站设计/松原新闻头条

顺义手机网站设计,松原新闻头条,江苏省建设注册中心网站,万网ip查询渲染器与响应式系统的结合 本节,我们暂时将渲染器限定在 DOM 平台。既然渲染器用来渲染真实 DOM 元素,那么严格来说,下面的函数就是一个合格的渲染器: // 渲染器: function renderer(domString, container) {container.innerHTM…

渲染器与响应式系统的结合

本节,我们暂时将渲染器限定在 DOM 平台。既然渲染器用来渲染真实 DOM 元素,那么严格来说,下面的函数就是一个合格的渲染器:

// 渲染器:
function renderer(domString, container) {container.innerHTML = domString
}

使用渲染器:

renderer('<h1>Hello</h1>', document.getElementById('app'))

如果页面中存在 id 为 app 的 DOM 元素,那么上面的代码就会将

hello

插入到该 DOM 元素内。

当然,我们不仅可以渲染静态的字符串,还可以渲染动态拼接的 HTML 内容,如下所示:

let count = 1
renderer(`<h1>${count}</h1>`, document.getElementById('app'))

这样,最终渲染出来的内容将会是

1

。注意上面这段 代码中的变量 count,如果它是一个响应式数据,会怎么样呢?这让 我们联想到副作用函数和响应式数据。 利用响应系统,我们可以让整 个渲染过程自动化:

const count = ref(1)effect(() => {renderer(`<h1>${count.value}</h1>`,document.getElementById('app'))})count.value++

在这段代码中,我们首先定义了一个响应式数据 count,它是一 个 ref,然后在副作用函数内调用 renderer 函数执行渲染。副作用 函数执行完毕后,会与响应式数据建立响应联系。当我们修改 count.value 的值时,副作用函数会重新执行,完成重新渲染。所以 上面的代码运行完毕后,最终渲染到页面的内容是 <h1>2</h1>。

这就是响应系统和渲染器之间的关系。我们利用响应系统的能 力,自动调用渲染器完成页面的渲染和更新。这个过程与渲染器的具 体实现无关,在上面给出的渲染器的实现中,仅仅设置了元素的 innerHTML 内容。

渲染器的每本概念

renderer: 渲染器
render:渲染
渲染器的作用是把虚拟 DOM 渲染为特定平台上的真实元素。在浏览器平台上,渲染器会把虚拟 DOM 渲染为真实 DOM 元素。

渲染器把虚拟 DOM 节点渲染为真实 DOM 节点的过程叫作 挂载(mount)。
Vue.js 组件中的 mounted 钩子就会在挂载完成时触发。这就意味着,在 mounted 钩子中可以访问真实DOM 元素。

那么,渲染器把真实 DOM 挂载到哪里呢?其实渲染器并不知道应该把真实 DOM 挂载到哪里因此,渲染器通常需要接收一个挂载点作为参数,用来指定具体的挂载位置。这里的“挂载点”其实就是一个DOM 元素,渲染器会把该 DOM 元素作为容器元素,并把内容渲染到其中。我们通常用英文 container 来表达容器。


// createRenderer:创建渲染器
function createRenderer() {// render:渲染函数// vnode:真实dom// container:具体的挂载位置function render(vnode, container) {}return render
}

有了渲染器,我们就可以用它来执行渲染任务了,如下面的代码所示:


// createRenderer 函数创建 一个渲染器
const renderer = createRenderer()// 首次渲染
// renderer.render 函数执行渲染
renderer.render(vnode, document.querySelector('#app'))

渲染器除了要执行挂载动作外,还要执行更新动作。例如:

const renderer = createRenderer()// 首次渲染
renderer.render(oldVNode, document.querySelector('#app'))// 第二次渲染
renderer.render(newVNode, document.querySelector('#app'))

如上面的代码所示,由于首次渲染时已经把 oldVNode 渲染到 container 内了,所以当再次调用 renderer.render 函数并尝试 渲染 newVNode 时,就不能简单地执行挂载动作了。在这种情况下, 渲染器会使用 newVNode 与上一次渲染的 oldVNode 进行比较,试图 找到并更新变更点。这个过程叫作“打补丁”(或更新),英文通常用patch来表达。但实际上,挂载动作本身也可以看作一种特殊的打补 丁,它的特殊之处在于旧的 vnode 是不存在的。所以我们不必过于纠 结“挂载”和“打补丁”这两个概念 。代码示例如下:

function createRenderer() {function render(vnode, container) {if (vnode) {// 新 vnode 存在,将其与旧 vnode 一起传递给 patch 函数,进行打补patch(container._vnode, vnode, container)} else {// 旧 vnode 存在,且新 vnode 不存在,说明是卸载(unmount)操作if (container._vnode) {unmount(container._vnode)}}// 把 vnode 存储到 container._vnode 下,即后续渲染中的旧 vnodecontainer._vnode = vnode}
}

上面这段代码给出了 render 函数的基本实现.我们可以配合下 面的代码分析其执行流程,从而更好地理解 render 函数的实现思路。假设我们连续三次调用 renderer.render 函数来执行渲染:

const renderer = createRenderer()// 首次渲染
renderer.render(vnode1, document.querySelector('#app'))// 第二次渲染
renderer.render(vnode2, document.querySelector('#app'))
// 第三次渲染
renderer.render(null, document.querySelector('#app'))
  • 在首次渲染时,渲染器会将 vnode1 渲染为真实 DOM。渲染完成 后,vnode1 会存储到容器元素的 container._vnode 属性 中,它会在后续渲染中作为旧 vnode 使用
  • 在第二次渲染时,旧 vnode 存在,此时渲染器会把 vnode2 作为 新 vnode,并将新旧 vnode 一同传递给 patch 函数进行打补 丁
  • 在第三次渲染时,新 vnode 的值为 null,即什么都不渲染。但 此时容器中渲染的是 vnode2 所描述的内容,所以渲染器需要清 空容器。从上面的代码中可以看出,我们使用unmount 卸载节点。

另外,在上面给出的代码中,我们注意到 patch 函数的签名,如 下:

patch(container._vnode, vnode, container)

patch 函数是整个渲染器的 核心入口,它承载了最重要的渲染逻辑,我们会花费大量篇幅来详细 讲解它,但这里仍有必要对它做一些初步的解释。
patch 函数至少接 收三个参数:

  • 第一个参数 n1:旧 vnode
  • 第二个参数 n2:新 vnode。
  • 第三个参数 container:容器。
function patch(n1, n2, container) {}

在首次渲染时,容器元素的 container._vnode 属性是不存在的,即 undefined。这意味着,在首次渲染时传递给 patch 函数的第一个参数 n1 也是 undefined。这时,patch 函数会执行挂载动作,它会忽略 n1,并直接将 n2 所描述的内容渲染到容器中。从这一点可以看出,patch 函数不仅可以用来完成打补丁,也可以用来执行挂载。

自定义渲染器

渲染器不仅能够把虚拟 DOM 渲染为浏览器平台上的真实 DOM。通过将渲染器设计为可配置的“通用”渲染器,即可实现渲染到任意目标平台上。本节我们将以浏览器作为渲染的目标平台,编写一个渲染器,在这个过程中,看看哪些内容是可以抽象的,然后通过抽象,将浏览器特定的 API 抽离,这样就可以使得渲染器的核心不依赖于浏览器。在此基础上,我们再为那些被抽离的 API提供可配置的接口,即可实现渲染器的跨平台能力。

案例:
对于这样一个 vnode,我们可以使用 render 函数渲染它,如下面的代码所示:

const vnode = {type: 'h1',children: 'hello'
}
// 创建一个渲染器
const renderer = createRenderer()// 调用 render 函数渲染该 vnode
renderer.render(vnode, document.querySelector('#app'))

为了完成渲染工作,我们需要补充 patch 函数:

function patch(n1, n2, container) {// 如果 n1 不存在,意味着挂载,则调用 mountElement 函数完成挂载if(!n1) {mountElement(n2, container)} else {// n1 存在,意味着打补丁,暂时省略}
}

在上面这段代码中,第一个参数 n1 代表旧 vnode,第二个参数 n2 代表新 vnode。当 n1 不存在时,意味着没有旧 vnode,此时只需 要执行挂载即可。这里我们调用 mountElement 完成挂载,它的实现 如下:

function mountElement(vnode, container) {// 创建dom元素const el = document.createElement(vnode.type)// 处理子节点,如果子节点是字符串,代表元素具有文本节点if (typeof vnode.children === 'string') {// 因此只需要设置元素的 textContent 属性即可el.textContent = vnode.children}// 将元素添加到容器中container.appendChild(el)
}

挂载一个普通标签元素的工作已经完成。接下来,我们分析这段 代码存在的问题。我们的目标是设计一个不依赖于浏览器平台的通用 渲染器,但很明显,mountElement 函数内调用了大量依赖于浏览器 的 API,例如 document.createElement、el.textContent 以 及 appendChild 等。想要设计通用渲染器,第一步要做的就是将这 些浏览器特有的 API 抽离。怎么做呢?我们可以将这些操作 DOM 的 API 作为配置项,该配置项可以作为 createRenderer 函数的参数, 如下面的代码所示:


// 在创建 renderer 时传入配置项
const renderer = createRenderer({// 用于创建元素createElement(tag) {return document.createElement(tag)},// 用于设置元素的文本节点setElementText(el.taxt) {el.textContent = text},// 用于在给定的 parent 下添加指定元素insert(el, parent, anchor = null) {parent.insertBefore(el, anchor)}
})

可以看到,我们把用于操作 DOM 的 API 封装为一个对象,并把 它传递给createRenderer 函数。这样,在 mountElement 等函数 内就可以通过配置项来取得操作 DOM 的 API 了:

 function createRenderer(options) {// 通过 options 得到操作 DOM 的 APIconst { createElement, setElementText, insert } = optionsfunction mountElement(vnode, container) {}function patch(v1, v2, container) {}function render(vnode, container) {}return {render}}

接着,我们就可以使用从配置项中取得的 API 重新实现 mountElement 函数:

function mountElement(vnode, container) {// 调用 createElement 函数创建元素const el = createElement(vnode.type)// 处理子节点,如果子节点是字符串,代表元素具有文本节点if (typeof vnode.children === 'string') {// 调用 setElementText 设置元素的文本节点setElementText(el, vnode.children)}// 调用 insert 函数将元素插入到容器内insert(el, container)
}

如上面的代码所示,重构后的 mountElement 函数在功能上没有 任何变化不同的是,它不再直接依赖于浏览器的特有 API 了。这意 味着,只要传入不同的配置项,就能够完成非浏览器环境下的渲染工 作。为了展示这一点,我们可以实现一个用来打印渲染器操作流程的 自定义渲染器,如下面的代码所示:

// 在创建 renderer 时传入配置项
const renderer = createRenderer({// 用于创建元素createElement(tag) {console.log(`创建元素 ${tag}`)return document.createElement(tag)},// 用于设置元素的文本节点setElementText(el.taxt) {console.log(`设置${JSON.stringify(el)}的文本内容:${text}`)el.textContent = text},// 用于在给定的 parent 下添加指定元素insert(el, parent, anchor = null) {console.log(`${JSON.stringify(el)}添加到:${JSON.stringify(parent)}`)parent.children = el}
})

这样,我们就实现了一个自定义渲染器,可以用下面这段代码来检测它的能力:

const vnode = {type: 'h1',children: 'hello'
}const container = { type: 'root' }
renderer.render(vnode, container)

在浏览器中的运行结果如下:
请添加图片描述

现在,我们对自定义渲染器有了更深刻的认识了。自定义渲染器并不是“黑魔法”,它只是通过抽象的手段,让核心代码不再依赖平台特有的 API,再通过支持个性化配置的能力来实现跨平台。

相关文章:

vuejs 设计与实现 - 渲染器的设计

渲染器与响应式系统的结合 本节&#xff0c;我们暂时将渲染器限定在 DOM 平台。既然渲染器用来渲染真实 DOM 元素&#xff0c;那么严格来说&#xff0c;下面的函数就是一个合格的渲染器: // 渲染器&#xff1a; function renderer(domString, container) {container.innerHTM…...

openCV 图像对象的创建和赋值

文章目录 一、赋值二、克隆三、拷贝四、初始化 一、赋值 赋值操作是将一个cv::Mat对象的数据复制到另一个对象中。赋值操作使用的是浅拷贝&#xff08;shallow copy&#xff09;&#xff0c;即两个对象共享相同的数据内存。这意味着对一个对象的修改会影响到另一个对象 cv::M…...

idea - 刷新 Git 分支数据 / 命令刷新 Git 分支数据

一、idea - 刷新 Git 分支数据 idea 找到 fetch 选项&#xff0c;重新获取分支数据 二、命令刷新 Git 分支数据 git fetch参考链接 1. 远程Gitlab新建的分支在IDEA里不显示...

线上电影购票选座H5小程序源码开发

搭建一个线上电影购票选座H5小程序源码需要一些基本的技术和步骤。以下是一个大致的搭建过程&#xff0c;可以参考&#xff1a; 1. 确定需求和功能&#xff1a;首先要明确你想要的电影购票选座H5小程序的需求和功能&#xff0c;例如用户登录注册、电影列表展示、选座购票、订单…...

QT正则校验

文章目录 前言一、Qt正则校验1.对输入框进行校验&#xff0c;不允许输入其他字符2.直接校验字符串 二、常用正则校验表达式 前言 项目中会经常遇到需要对字符串进行校验的情况&#xff0c;需要用到正则表达式&#xff08;Regular Expression&#xff0c;通常简写为RegExp、RE等…...

ChatGPT“侵入”校园,教学评价体制受冲击,需作出调整

北密歇根大学的教授奥曼在学生作业中发现了一篇关于世界宗教的“完美论文”。“这篇文章写得比大多数学生都要好......好到不符合我对学生的预期&#xff01;”他去问ChatGPT&#xff1a;“这是你写的吗&#xff1f;”ChatGPT回答&#xff1a;“99.9%的概率是的。” ChatGPT“侵…...

函数的声明和定义

1、函数声明 //告诉编译器有一个函数叫什么&#xff0c;参数是什么&#xff0c;返回类型是什么。但是具体是不是存在&#xff0c;函数声明决定不了。 //函数的声明一般出现在函数的使用之前。要满足先声明后使用。 //函数的声明一般要放在头文件中的。 2、函数的定义 //函数…...

06微服务间的通信方式

一句话导读 微服务设计的一个挑战就是服务间的通信问题&#xff0c;服务间通信理论上可以归结为进程间通信&#xff0c;进程可以是同一个机器上的&#xff0c;也可以是不同机器的。服务可以使用同步请求响应机制通信&#xff0c;也可以使用异步的基于消息中间件间的通信机制。同…...

研发工程师玩转Kubernetes——local型PV和PVC绑定过程中的状态变化

PV全称是PersistentVolume&#xff0c;即持久卷&#xff0c;是由管理员事先准备好的资源。它可以是本地磁盘&#xff0c;也可以是网络磁盘。 PVC全称是PersistentVolumeClaim&#xff0c;即持久卷申领。它表示卷的使用者&#xff0c;对PV的申请。即我们可以认为&#xff0c;PV是…...

HTTP——十一、Web的攻击技术

HTTP 一、针对Web的攻击技术1、HTTP 不具备必要的安全功能2、在客户端即可篡改请求3、针对Web应用的攻击模式 二、因输出值转义不完全引发的安全漏洞1、跨站脚本攻击2、SQL 注入攻击3、OS命令注入攻击4、HTTP首部注入攻击5、邮件首部注入攻击6、目录遍历攻击7、远程文件包含漏洞…...

Python-OpenCV中的图像处理-图像金字塔

Python-OpenCV中的图像处理-图像金字塔 图像金字塔高斯金字塔拉普拉斯金字塔 金字塔图像融合 图像金字塔 同一图像的不同分辨率的子图集合&#xff0c;如果把最大的图像放在底部&#xff0c;最小的放在顶部&#xff0c;看起来像一座金字塔&#xff0c;故而得名图像金字塔。cv2…...

ArcGIS、ENVI、InVEST、FRAGSTATS技术教程

专题一 空间数据获取与制图 1.1 软件安装与应用讲解 1.2 空间数据介绍 1.3海量空间数据下载 1.4 ArcGIS软件快速入门 1.5 Geodatabase地理数据库 专题二 ArcGIS专题地图制作 2.1专题地图制作规范 2.2 空间数据的准备与处理 2.3 空间数据可视化&#xff1a;地图符号与注…...

Unity-Linux部署WebGL项目MIME类型添加

在以往的文章中有提到过使用IIS部署WebGL添加MIME类型使WebGL项目在浏览器中能够正常加载&#xff0c;那么如果咱们做的是商业项目&#xff0c;往往是需要部署在学校或者云服务器上面的&#xff0c;大部分情况下如果项目有接口或者后台管理系统&#xff0c;后台基本都会使用Lin…...

MySQL:表的约束和基本查询

表的约束 表的约束——为了让插入的数据符合预期。 表的约束很多&#xff0c;这里主要介绍如下几个&#xff1a; null/not null,default, comment, zerofill&#xff0c;primary key&#xff0c;auto_increment&#xff0c;unique key 。 空属性 两个值&#xff1a;null&am…...

mysql统计近7天数据量,,按时间戳分组

可以使用以下 SQL 语句来统计近7天的数据量&#xff0c;并按时间戳分组。如果某一天没有数据&#xff0c;则将其填充为0。 SELECT DATE_FORMAT(FROM_UNIXTIME(timestamp), %Y-%m-%d) AS date,COUNT(*) AS count FROM table_name WHERE timestamp > UNIX_TIMESTAMP(DATE_SUB…...

无涯教程-Perl - endnetent函数

描述 此功能告诉系统您不再希望使用getnetent从网络列表中读取条目。 语法 以下是此函数的简单语法- endnetent返回值 此函数不返回任何值。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perluse Socket;while ( ($name, $aliases, $addrtype, $net) getnetent() )…...

Selenium的xpath高级写法-实用篇

系列文章目录 提示&#xff1a;阅读本章之前&#xff0c;请先阅读目录 文章目录 系列文章目录前言获取父级获取前一个兄弟级获取后一个兄弟级获取内容包含某些内容获取内容是空 前言 获取父级 //div[text()‘我是子级’]/parent::div[text()‘我是父级’] 获取前一个兄弟级 //d…...

阿里云官方关于数据安全保护的声明

“阿里云监控用户的数据流量&#xff1f;”“真的假的&#xff1f;”随着近日早晨 朱峰肥鹅旅行 对阿里云的一条朋友圈截图传遍了整个IT圈。 对于网络上的各种传播&#xff0c;以下是阿里云的官方答复&#xff0c;原文如下&#xff1a; 关于数据安全保护的声明 今天有客户反映…...

【神经网络手写数字识别-最全源码(pytorch)】

Torch安装的方法 学习方法 1.边用边学&#xff0c;torch只是一个工具&#xff0c;真正用&#xff0c;查的过程才是学习的过程2.直接就上案例就行&#xff0c;先来跑&#xff0c;遇到什么来解决什么 Mnist分类任务&#xff1a; 网络基本构建与训练方法&#xff0c;常用函数解析…...

React、Vue和Angular的优缺点

React React 是一个用于构建用户界面的 JAVASCRIPT 库。React 主要用于构建 UI&#xff0c;很多人认为 React 是 MVC 中的 V&#xff08;视图&#xff09;。React 起源于 Facebook 的内部项目&#xff0c;用来架设 Instagram 的网站&#xff0c;并于 2013 年 5 月开源。React …...

ArcGIS Pro根据不同条件显示不同标注

在某些情况下&#xff0c;我们需要根据不同的条件在地图上进行标注&#xff0c;比如我们想要在地图上显示广东省人口从2005年到2010年的变化情况&#xff0c;可以使用ArcGIS Pro的标注类功能实现&#xff0c;这里为大家介绍一下制作方法&#xff0c;希望能对你有所帮助。 标注分…...

DynamicsCRM专栏导览

不知不觉,专栏已经有5个订阅了。很高兴,自己的付出有了回报。很感谢大家的信任。 大家的订阅给了我很好的正反馈,也让我有了更强的动力,更大的责任感,去把这个专栏做好。 于是就有了这篇导览。这篇导览是我根据过往的开发经验总结出来的一个学习的框架。有些部分可能还没…...

Vue自定义指令使用

本篇文章讲述使用Vue自定义指令&#xff0c;并在项目中完成相应功能。 在平常Vue脚手架项目中&#xff0c;使用到 自定义指令较少&#xff0c;一般都是使用的自带指令&#xff0c;比如 v-show 、v-if 、 v-for 、 v-bind 之类的。这些已经能够满足大多数项目使用。更多的可能也…...

python爬虫之scrapy框架介绍

一、Scrapy框架简介 Scrapy 是一个开源的 Python 库和框架&#xff0c;用于从网站上提取数据。它为自从网站爬取数据而设计&#xff0c;也可以用于数据挖掘和信息处理。Scrapy 可以从互联网上自动爬取数据&#xff0c;并将其存储在本地或在 Internet 上进行处理。Scrapy 的目标…...

winform中嵌入cefsharp, 并使用selenium控制

正常说&#xff0c; 需要安装的包 下面是所有的包 全部代码 using OpenQA.Selenium.Chrome; using OpenQA.Selenium; using System; using System.Windows.Forms; using CefSharp.WinForms; using CefSharp;namespace WindowsFormsApp2 {public partial class Form1 : Form{//…...

【leetcode】349. 两个数组的交集(easy)

给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 思路&#xff1a; 先遍历nums1将其元素不重复地添加到哈希表a中&#xff1b;建立哈希表dup用于存储b和a重复的元素&#xff1b;遍历nums2…...

leetcode 2616. 最小化数对的最大差值

在数组nums中找到p个数对&#xff0c;使差值绝对值的和最小。 思路&#xff1a; 最小差值应该是数值相近的一对数之间产生&#xff0c;让数值相近的数字尽量靠在一起方便计算&#xff0c;所以需要排序。 这里不去直接考虑一对对的数字&#xff0c;而是直接考虑差值的取值。 …...

npm install 安装慢的问题处理

原因 npm install 默认使用的安装镜像时国外的镜像&#xff0c;国内使用会受到网络的限制。 解决方案 更换网络更换npm的安装镜像为国内&#xff0c;比如&#xff1a; npm config set registry https://registry.npm.taobao.org...

【JAVA】七大排序算法(图解)

稳定性&#xff1a; 待排序的序列中若存在值相同的元素&#xff0c;经过排序之后&#xff0c;相等元素的先后顺序不发生改变&#xff0c;称为排序的稳定性。 思维导图&#xff1a; &#xff08;排序名称后面蓝色字体为时间复杂度和稳定性&#xff09; 1.直接插入排序 核心思…...

UNIX 系统概要

UNIX 家族UNIX 家谱家族后起之秀 LinuxUNIX vs LinuxUNIX/Linux 应用领域 UNIX 操作系统诞生与发展UNIX 操作系统概要内核常驻模块shell虚拟计算机特性 其他操作系统 LinuxRichard StallmanGNU 项目FSF 组织GPL 协议Linus Torvalds UNIX 家族 有人说&#xff0c;这个世界上只有…...