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

国内网站建设阿里云/seo的实现方式

国内网站建设阿里云,seo的实现方式,成都网站建设公司创新互联,个人网站的搭建Vue.js 2 所采用的双端 Diff 算法。既然快速 Diff 算法如此高效,我们有必要了解它的思路。接下来,我们就着重讨论快速 Diff 算法的实现原理。 相同的前置元素和后置元素 快速 Diff 算法借鉴了纯文本 Diff 算法中预处理的步骤。 案例: 旧的…

Vue.js 2 所采用的双端 Diff 算法。既然快速 Diff 算法如此高效,我们有必要了解它的思路。接下来,我们就着重讨论快速 Diff 算法的实现原理。

相同的前置元素和后置元素

快速 Diff 算法借鉴了纯文本 Diff 算法中预处理的步骤。

案例:

旧的一组子节点:p-1、p-2、p-3。
新的一组子节点:p-1、p-4、p-2、p-3。

通过观察可以发现,两组子节点具有相同的前置节点 p-1,以及相同的后置节点 p-2 和 p-3,如图 下图 所示:
对于相同的前置节点和后置节点,由于它们在新旧两组子节点中的相对位置不变,所以我们无须移动它们,但仍然需要在它们之间打补丁。
请添加图片描述

处理前置节点

对于前置节点,我们可以建立索引 j,其初始值为 0,用来指向两组子节点的开头,如图 下图所示:
请添加图片描述

然后开启一个 while 循环,让索引 j 递增,直到遇到不相同的节点为止,如下面 patchKeyedChildren 函数的代码所示:

 function patchKeyedChildren(n1, n2, container) {const newChildren = n2.childrenconst oldChildren = n1.children// 处理相同的前置节点// 索引 j 指向新旧两组子节点的开头let j = 0let oldVNode = oldChildren[j]let newVNode = newChildren[j]// while 循环向后遍历,直到遇到拥有不同 key 值的节点为止while(oldVNode.key === newVNode.key) {// 调用 patch 函数进行更新patch(oldVNode, newVNode, container)// 更新索引 j,让其递增j++oldVNode = oldChildren[j]newVNode = newChildren[j]}}

在上面这段代码中,我们使用 while 循环查找所有相同的前置节点,并调用 patch 函数进行打补丁,直到遇到 key 值不同的节点为
止。这样,我们就完成了对前置节点的更新。在这一步更新操作过后,新旧两组子节点的状态如图 下图 所示:
请添加图片描述

处理后置节点:

这里需要注意的是,当 while 循环终止时,索引 j 的值为 1。接下来,我们需要处理相同的后置节点。由于新旧两组子节点的数量可
能不同,所以我们需要两个索引 newEnd 和 oldEnd,分别指向新旧两组子节点中的最后一个节点,如图 下图 所示:
请添加图片描述
然后,再开启一个 while 循环,并从后向前遍历这两组子节点,直到遇到 key 值不同的节点为止,如下面的代码所示:

function patchKeyedChildren(n1, n2, container) {const newChildren = n2.childrenconst oldChildren = n1.children// 处理相同的前置节点// 索引 j 指向新旧两组子节点的开头let j = 0let oldVNode = oldChildren[j]let newVNode = newChildren[j]// while 循环向后遍历,直到遇到拥有不同 key 值的节点为止while(oldVNode.key === newVNode.key) {// 调用 patch 函数进行更新patch(oldVNode, newVNode, container)// 更新索引 j,让其递增j++oldVNode = oldChildren[j]newVNode = newChildren[j]}+           // 处理后置节点:// 索引 oldEnd 指向旧的一组子节点的最后一个节点+           let oldEnd = oldChildren.length - 1// 索引 newEnd 指向新的一组子节点的最后一个节点+           let newEnd = newChildren.length - 1+           oldVNode = oldChildren[oldEnd]+           newVNode = newChildren[newEnd]// while 循环从后向前遍历,直到遇到拥有不同 key 值的节点为止+           while(oldVNode.key === newVNode.key) {// 调用 patch 函数进行更新+               patch(oldVNode, newVNode, container)// 递减 oldEnd 和 nextEnd+              oldEnd --+              newEnd--+              oldVNode = oldChildren[oldEnd]+              newVNode = newChildren[newEnd]}}

与处理相同的前置节点一样,在 while 循环内,需要调用 patch函数进行打补丁,然后递减两个索引 oldEnd、newEnd 的值。在这一步更新操作过后,新旧两组子节点的状态如图 下图 所示:
请添加图片描述

新增:

观察上图:当相同的前置节点和后置节点被处理完毕后,旧的一组子节点已经全部被处理了,而在新的一组子节点中,还遗留了一个未被处理的节点 p-4。其实不难发现,节点 p-4 是一个新增节点。那么,如何用程序得出“节点 p-4 是新增节点”这个结论呢?这需要我们观察三个索引 j、newEnd 和 oldEnd 之间的关系。

  • 条件一: oldEnd < j成立:说明在预处理过程中,所有旧子节点都处理完毕了。
  • 条件二:newEnd >= j成立:说明在预处理过后,在新的一组子 节点中,仍然有未被处理的节点,而这些遗留的节点将被视作新增节点。
    如果条件一和条件二同时成立,说明在新的一组子节点中,存在遗留节点,且这些节点都是新增节点。因此我们需要将它们挂载到正确的位置,如下图 所示:
    请添加图片描述
    在新的一组子节点中,索引值处于 j 和 newEnd 之间的任何节点都需要作为新的子节点进行挂载。那么,应该怎样将这些节点挂载到正确位置呢?这就要求我们必须找到正确的锚点元素。观察图 上图 中新的一组子节点可知,新增节点应该挂载到节点 p-2 所对应的真实DOM 前面。所以,节点 p-2 对应的真实 DOM 节点就是挂载操作的锚点元素。有了这些信息,我们就可以给出具体的代码实现了,如下所示:
function patchKeyedChildren(n1, n2, container) {const newChildren = n2.childrenconst oldChildren = n1.children// 处理相同的前置节点// 索引 j 指向新旧两组子节点的开头let j = 0let oldVNode = oldChildren[j]let newVNode = newChildren[j]// while 循环向后遍历,直到遇到拥有不同 key 值的节点为止while(oldVNode.key === newVNode.key) {// 调用 patch 函数进行更新patch(oldVNode, newVNode, container)// 更新索引 j,让其递增j++oldVNode = oldChildren[j]newVNode = newChildren[j]}// 处理后置节点:// 索引 oldEnd 指向旧的一组子节点的最后一个节点let oldEnd = oldChildren.length - 1// 索引 newEnd 指向新的一组子节点的最后一个节点let newEnd = newChildren.length - 1oldVNode = oldChildren[oldEnd]newVNode = newChildren[newEnd]// while 循环从后向前遍历,直到遇到拥有不同 key 值的节点为止while(oldVNode.key === newVNode.key) {// 调用 patch 函数进行更新patch(oldVNode, newVNode, container)// 递减 oldEnd 和 nextEndoldEnd --newEnd--oldVNode = oldChildren[oldEnd]newVNode = newChildren[newEnd]}// 新增// 预处理完毕后,如果满足如下条件,则说明从 j --> newEnd 之间的节点应作 为新节点插入+          if(j > oldEnd && j <= newEnd) {// 锚点索引+              const anchorIndex = newEnd + 1// 锚点元素+              const anchor = anchorIndex < newChildren.length ? newChildren[anchorIndex].el : null+              while(j <= newEnd) {+                  patch(null, newChildren[j++], container, anchor)+              }}}

在上面这段代码中,首先计算锚点的索引值(即 anchorIndex) 为newEnd + 1。如果小于新的一组子节点的数量,则说明锚点元素 在新的一组子节点中,所以直接使用 newChildren[anchorIndex].el 作为锚点元素;否则说明索引 newEnd 对应的节点已经是尾部节点了,这时无须提供锚点元素。有了 锚点元素之后,我们开启了一个 while 循环,用来遍历索引 j 和索引 newEnd 之间的节点,并调用 patch 函数挂载它们。

删除
案例:
  • 旧的一组子节点:p-1、p-2、p-3。
  • 新的一组子节点:p-1、p-3。

请添加图片描述
当前置节点,后置节点都处理完成,后剩余未被处理的节点如下图所示:
请添加图片描述

索引 j 和索引 oldEnd 之间的任何节点都应该被卸载,具体实现如下:

function patchKeyedChildren(n1, n2, container) {const newChildren = n2.childrenconst oldChildren = n1.children// 处理相同的前置节点// 索引 j 指向新旧两组子节点的开头let j = 0let oldVNode = oldChildren[j]let newVNode = newChildren[j]// while 循环向后遍历,直到遇到拥有不同 key 值的节点为止while(oldVNode.key === newVNode.key) {// 调用 patch 函数进行更新patch(oldVNode, newVNode, container)// 更新索引 j,让其递增j++oldVNode = oldChildren[j]newVNode = newChildren[j]}// 处理后置节点:// 索引 oldEnd 指向旧的一组子节点的最后一个节点let oldEnd = oldChildren.length - 1// 索引 newEnd 指向新的一组子节点的最后一个节点let newEnd = newChildren.length - 1oldVNode = oldChildren[oldEnd]newVNode = newChildren[newEnd]// while 循环从后向前遍历,直到遇到拥有不同 key 值的节点为止while(oldVNode.key === newVNode.key) {// 调用 patch 函数进行更新patch(oldVNode, newVNode, container)// 递减 oldEnd 和 nextEndoldEnd --newEnd--oldVNode = oldChildren[oldEnd]newVNode = newChildren[newEnd]}// 新增// 预处理完毕后,如果满足如下条件,则说明从 j --> newEnd 之间的节点应作 为新节点插入if(j > oldEnd && j <= newEnd) {// 锚点索引const anchorIndex = newEnd + 1// 锚点元素const anchor = anchorIndex < newChildren.length ? newChildren[anchorIndex].el : nullwhile(j <= newEnd) {patch(null, newChildren[j++], container, anchor)}+         } else if (j > newEnd && j <= oldEnd) {// 删除// j -> oldEnd 之间的节点应该被卸载+            while(j <= oldEnd) {+                unmount(oldChildren[j++])}}}

在上面这段代码中,我们新增了一个 else…if 分支。当满足条件j > newEnd && j <= oldEnd时,则开启一个while循环,并调用unmount 函数逐个卸载这些遗留节点。

移动

有点复杂

相关文章:

vuejs 设计与实现 - 快速diff算法

Vue.js 2 所采用的双端 Diff 算法。既然快速 Diff 算法如此高效&#xff0c;我们有必要了解它的思路。接下来&#xff0c;我们就着重讨论快速 Diff 算法的实现原理。 相同的前置元素和后置元素 快速 Diff 算法借鉴了纯文本 Diff 算法中预处理的步骤。 案例&#xff1a; 旧的…...

webpack基础知识七:说说webpack proxy工作原理?为什么能解决跨域?

一、是什么 webpack proxy&#xff0c;即webpack提供的代理服务 基本行为就是接收客户端发送的请求后转发给其他服务器 其目的是为了便于开发者在开发模式下解决跨域问题&#xff08;浏览器安全策略限制&#xff09; 想要实现代理首先需要一个中间服务器&#xff0c;webpac…...

nginx负载均衡(nginx结束)

本节主要内容 1、四层&#xff0c;七层代理的配置方法 2、负载均衡的算法 nginx负载均衡&#xff1a;反向代理来实现 反向代理有两种转发方式&#xff1a;1、四层代理 2、七层代理 Nginx的七层代理和四层代理 七层是最常见的反向代理方式&#xff0c;只能配置在nginx配置文…...

Git与Github常用方法

目录 1. Github基本使用方法2. Git使用方法3. git、VS code、Github联合使用方法4. Git配置Github远程仓库SSH密钥5 常见问题 1. Github基本使用方法 仓库&#xff08;Repository&#xff09;&#xff1a;Github上用来存放代码的空间&#xff0c;包含代码、文档和其他文件。提…...

Centos7离线安装MySQL8

1、下载MySQL https://downloads.mysql.com/archives/community/ 2、下载完毕后&#xff0c;上传到Centos&#xff0c;解压 tar -xf mysql-8.0.33-1.el7.x86_64.rpm-bundle.tar 3、逐条执行安装命令 rpm -ivh mysql-community-common-8.0.33-1.el7.x86_64.rpm rpm -ivh …...

AWD攻防学习总结(草稿状态,待陆续补充)

AWD攻防学习总结 防守端1、修改密码2、备份网站3、备份数据库4、部署WAF5、部署文件监控脚本6、部署流量监控脚本/工具7、D盾扫描&#xff0c;删除预留webshell8、代码审计&#xff0c;seay/fortify扫描&#xff0c;漏洞修复及利用9、时刻关注流量和积分信息&#xff0c;掉分时…...

扫雷(超详解+全部码源)

C语言经典游戏扫雷 前言一.游戏规则二.所需文件三.创建菜单四.游戏核心内容实现1.创建棋盘2.打印棋盘3.布置雷4.排查雷5.game()函数具体实现 五.游戏运行实操六.全部码源 前言 &#x1f600;C语言实现扫雷是对基础代码能力的考察。通过本篇文章你将学会如何制作出扫雷&#xff…...

python生成exe脚本全过程

python生成exe脚本全过程 1、定义设计的GUI界面2、几个GUI界面常用函数2.1 tk.Label2.2 tk.StringVar2.3 tk.Entry2.4 tk.Button2.5 tk.Text2.6 tk.Scrollbar 3、实例3.1 需求3.2实现 4、如何使用pycharm生成可执行exe文件4.1安装pyinstaller4.2 生成exe文件 5、生成exe过程中遇…...

【机器学习1】什么是机器学习机器学习的重要性

什么是机器学习? 简而言之&#xff0c;机器学习就是训练机器去学习。 机器学习作为人工智能(Artificial Intelligence,AI)的一个分支&#xff0c;以其最基本的形式来使用算法通过从数据中获取知识来进行预测。 不同于人类通过分析大量数据手动推导规则和模型&#xff0c;机…...

立即开始使用 3D 图像

一、说明 这个故事介绍了使用这种类型的数据来训练机器学习3D模型。特别是&#xff0c;我们讨论了Kaggle中可用的MNIST数据集的3D版本&#xff0c;以及如何使用Keras训练模型识别3D数字。 3D 数据无处不在。由于我们希望构建AI来与我们的物理世界进行交互&#xff0c;因此使用3…...

鸿鹄工程项目管理系统em Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统em

​ Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目…...

《向量数据库》——怎么安装向量检索库Faiss?

装 Faiss 以下教程将展示如何在 Linux 系统上安装 Faiss: 1. 安装 Conda。 在安装 Faiss 之前,先在系统上安装 Conda。Conda 是一个开源软件包和环境管理系统,可在 Windows、macOS 和 Linux 操作系统上运行。根据以下步骤在 Linux 系统上安装 Conda。 2. 从官网…...

学习pytorch 2 导入查看dataset

学习pytorch 2 2. dataset实战代码数据集 2. dataset实战 B站小土堆视频 代码 from torch.utils.data import Dataset from PIL import Image #import cv2 import osclass MyData(Dataset):def __init__(self, root_dir, label_dir):self.root_dir root_dirself.label_dir …...

三、kubeadm部署单Master节点kubernetes集群

kubeadm部署单Master节点kubernetes集群 一、kubernetes 1.21发布 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sGgnZuno-1691633861803)(kubeadm部署单Master节点kubernetes集群 1.21.0.assets/image-20220119160108054.png)] 1.1 介绍 2021年…...

js-6:typeof和instanceof的区别

1、typeof typeof操作符返回一个字符串&#xff0c;表示未经计算的操作数的类型。 operand表示对象或原始值的表达式&#xff0c;其类型将被返回。 从上面的例子可以看出&#xff0c;前6个都是基础数据类型&#xff0c;虽然typeof null为object&#xff0c;但这只是javascrip…...

SQL SERVER 异地备份到远程共享文件夹异常处理

SQL SERVER 异地备份到远程共享文件夹异常处理 SQL Server 异地备份到远程共享文件夹异常处理 - 灰信网&#xff08;软件开发博客聚合&#xff09; -- 允许配置高级选项 EXEC sp_configure show advanced options, 1 GO -- 重新配置 RECONFIGURE GO -- 启用xp_cmdshell EXEC sp…...

服务器数据恢复-RAID5上层Hyper-V虚拟机数据恢复案例

服务器数据恢复环境&#xff1a; 一台Windows Server服务器&#xff0c;部署Hyper-V虚拟化环境&#xff0c;虚拟机的硬盘文件和配置文件存放在一台DELL存储中。该存储中有一组由4块硬盘组建的RAID5阵列&#xff0c;用来存放虚拟机的数据文件&#xff0c;另外还有一块大容量硬盘…...

Easy Rules规则引擎(1-基础篇)

目录 一、序言二、Easy Rules介绍三、定义规则(Rules)1、规则介绍2、编程式规则定义3、声明式规则定义 四、定义事实(Facts)五、定义规则引擎(Rules Engine)1、规则引擎介绍2、InferenceRulesEngine规则引擎示例(1) 定义触发条件(2) 定义规则触发后的执行行为(3) 测试用例 一、…...

Linux 上安装部署Nacos

标题&#xff1a;在Linux上安装和部署Nacos Nacos是一个开源的分布式服务发现和配置管理平台&#xff0c;它可以帮助开发人员实现微服务架构中的服务注册、发现和动态配置管理。 步骤1&#xff1a;准备工作 在开始安装Nacos之前&#xff0c;确保您已经具备以下条件&#xff1…...

电动机的启动

1电动机启动分类 电动机启动方式包括&#xff1a;全压直接启动、自耦减压启动、Y-Δ 启动、软启动器、变频器。其中软启动器和变频器启动为潮流。当然也不是一定要使用软启动器和变频器启动&#xff0c;在运用的时候根据实际情况&#xff0c;从经济和适用性自行考虑选择。 2电…...

python性能分析,logging性能,print性能,文件写入性能对比

先说结论&#xff0c;没想到的是print性能比logging性能好&#xff0c;输出到控制台会极大降低程序性能&#xff0c;以下是我的性能对比结果&#xff1a; 运行情况是python后台运行并输出到日志&#xff0c;命令是 python3 test.py > /opt/testtime.log 2>&1 &...

[GIN-debug] [ERROR] listen tcp: address 8080: missing port in address

学习Golang_gin框架的第一天 遇到一下报错 : [GIN-debug] [ERROR] listen tcp: address 8080: missing port in address 错误代码 : package mainimport "github.com/gin-gonic/gin"func main() {router : gin.Default()router.GET("/index", func…...

PHP codeigniter4 搭配Nginx

> 主要是为了用Nginx运行PHP环境 1. Nginx 官方文档的配置 default.conf This configuration enables URLs without “index.php” in them and using CodeIgniter’s “404 - File Not Found” for URLs ending with “.php”. server {listen 80;listen [::]:80;se…...

AWS——04篇(AWS之Amazon S3(云中可扩展存储)-02——EC2访问S3存储桶)

AWS——04篇&#xff08;AWS之Amazon S3&#xff08;云中可扩展存储&#xff09;-02——EC2访问S3存储桶&#xff09; 1. 前言2. 创建EC2实例 S3存储桶3. 创建IAM角色4. 修改EC2的IAM 角色5. 连接EC2查看效果5.1 连接EC25.2 简单测试5.2.1 查看桶内存储情况5.2.2 复制本地文件…...

.netcore下grpc概述

一、什么是grpc 是一种与语言无关的高性能远程过程调用 (RPC) 框架。基于http/2标准设计&#xff0c;提供了头部压缩、tcp连接上的多路复用、流量控制、流式处理&#xff08;客户端流/服务端流/双向流&#xff09;。提供统一使用的.proto文件&#xff0c;它定义 grpc 服务和消…...

Address already in use

netstat -tunllp netstat -tunllp 命令是用来查看系统上所有的网络连接和监听端口&#xff0c;包括 TCP 和 UDP 连接。这个命令的选项含义如下&#xff1a; -t: 显示 TCP 连接-u: 显示 UDP 连接-n: 不进行主机名和服务名的解析&#xff0c;直接显示数字形式的 IP 地址和端口号…...

♥ vue中$set用法详细讲解

♥ vue中$set用法详细讲解 1、认识 在vue中&#xff0c;并不是任何时候数据都是双向绑定的。 官方文档介绍 使用场景 当数据没有被双向绑定的时候&#xff0c;我们就需要使用set了 举个例子&#xff1a; vue的data里边声明或者已经赋值过的对象或者数组&#xff08;数组里…...

岩土工程仪器多通道振弦传感器信号转换器应用于桥梁安全监测

岩土工程仪器多通道振弦传感器信号转换器应用于桥梁安全监测 桥梁作为交通运输的重要节点&#xff0c;其安全性一直备受关注。不同于其他建筑物&#xff0c;桥梁所处的环境复杂多变&#xff0c;同时&#xff0c;其所需承受的负荷也相对较大&#xff0c;这就需要对桥梁的安全进…...

企业权限管理(六)-订单详情

订单详情查询 跳转到订单详情页面orders-show.jsp <button type"button" class"btn bg-olive btn-xs" onclick"location.href${pageContext.request.contextPath}/orders/findById.do?id${orders.id}">详情</button>OrdersControl…...

基于Tars高并发IM系统的设计与实现-实战篇5

基于Tars高并发IM系统的设计与实现-实战篇5 群聊服务 GroupChatServer 群聊服务既可以接受来自BrokerServer的用户请求&#xff0c;也需要接收来自其他服务的RPC请求;所以本服务提供两套RPC接口&#xff1a;通用RPC接口和专用RPC接口。 通用RPC接口 通用RPC接口主要处理如下…...