vue3源码(六)渲染原理-runtime-dom

news2024/11/24 5:34:45

1、从入口文件看实现

项目入口文件

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'

createApp(App).mount('#app')

文件位置core\packages\runtime-dom\src\index.ts
在这里插入图片描述
保证了render唯一性

// // rendererOptions 是patchProp 和nodeOps的合集,包含了dom操作和节点对比方法
const rendererOptions = /*#__PURE__*/ extend({ patchProp }, nodeOps)

function ensureRenderer() {
  return (
    renderer ||
    (renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions))
  )
}

createApp中主要调用了ensureRenderer创建返回的App,ensureRenderer中返回createRenderer
createRenderer核心方法baseCreateRenderer 主要包含了创建渲染器和更新和渲染的一系列方法,接下来开始从使用到实现吧~

2、两种渲染器的使用

 import { createRenderer ,render,h} from "/node_modules/@vue/runtime-dom/dist/runtime-dom.esm-browser.js";
      // 1、createRenderer 我们可以自己创建渲染器(自己提供渲染方式)
      // 2、render 内置的渲染器 (渲染dom元素)
      // 3、h 方法可以创建一个虚拟dom (type,propsOrChildren,children)
      console.log(createRenderer,render,h);
      let  ele = h("h1","hello render")
      // render(ele,app)  用提供的api去渲染

      // 自定义渲染器
      const renderer = createRenderer({
        // 创建一个节点
        createElement(type){
         return document.createElement(type)
        },
        // 节点的展示
        setElementText(el,text){
          el.textContent = text
        },
        // 节点内容
        insert(el,container){
          container.appendChild(el)
        }
      })
      renderer.render(ele,app)

      // runtime-dom 提供一系列操作dom的API
      // @vue/runtime-dom是针对浏览器的  --> @vue/runtime-core 是跨平台的  --> @vue/reactivity 

3、renderOptions实现

renderOptions主要包含两个部分:

  • dom节点的操作
  • 属性的操作
const renderOptions = Object.assign({ patchProp }, nodeOps);
export { renderOptions };

3.1 nodeOps

export const nodeOps = {
  insert: (child, parent, anchor) => {
    // 添加节点
    parent.insertBefore(child, anchor || null);
  },
  remove: (child) => {
    // 节点删除
    const parent = child.parentNode;
    parent && parent.removeChild(child);
  },
  createElement: (tag) => document.createElement(tag), // 创建节点
  createText: (text) => document.createTextNode(text), // 创建文本
  setText: (node, text) => (node.nodeValue = text), //  设置文本节点内容
  setElementText: (el, text) => (el.textContent = text), // 设置文本元素中的内容
  parentNode: (node) => node.parentNode, // 父亲节点
  nextSibling: (node) => node.nextSibling, // 下一个节点
  querySelector: (selector) => document.querySelector(selector), // 搜索元素
};

3.2 patchProp

export default function patchProp(el, key, prevValue, nextValue) {
  if (key === "class") {
    return patchClass(el, nextValue);
  } else if (key === "style") {
    return patchStyle(el, prevValue, nextValue);
  } else if (/^on[^a-z]/.test(key)) {
    return patchEvent(el, key, nextValue);
  }else{
    return patchAttr(el, key, nextValue)
  }
}

3.2.1 patchClass

export default function patchClass(el, value) {
  if (value) {
    el.className = value;
  } else {
    el.removeAttribute("class");
  }
}

3.2.2 patchStyle

export default function patchStyle(el, prevValue, nextValue) {
  let style = el.style;
  // 把新的加进来
  for (let key in nextValue) {
    style[key] = nextValue[key];
  }
  // 把多余的删掉
  if (prevValue) {
    for (let key in prevValue) {
      if (nextValue[key] == null) {
        style[key] = null;
      }
    }
  }
}

3.2.3 patchEvent

// 创建一个调用器,执行value值,value可以改变
function createInvoker(value) {
  const invoker = (e) => invoker.value();
  invoker.value = value; // 修改value可以修改方法对应的调用函数
  return invoker;
}

export default function patchEvent(el, name, nextValue) {
  const invokers = el._vei || (el._vei = {});
  const eventName = name.slice(2).toLowerCase();

  const existingInvoker = invokers[name];
  //   如果之前存在同名方法 则修改函数
  if (nextValue && existingInvoker) {
    return (existingInvoker.value = nextValue);
  }
  if (nextValue) {
    // 如果之前没有同名方法, 则给方法赋值
    const invoker = (invokers[name] = createInvoker(nextValue));
    return el.addEventListener(eventName, invoker);
  }
  if (existingInvoker && !nextValue) {
    el.removeEventListener(eventName);
    invokers[name] = undefined;
  }
}

3.2.4 patchAttr

export default function patchAttr(el,key, value) {
  if (value) {
    el.setAttribute(key, value);
  } else {
    el.removeAttribute(key)
  }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

材料科学SCI期刊,IF=6+,超高录用率,2个月录用

一、期刊名称 Advanced Electronic Materials 二、期刊简介概况 期刊类型&#xff1a;SCI 学科领域&#xff1a;材料科学 影响因子&#xff1a;5.3 中科院分区&#xff1a;2区 三、期刊简介 Advanced Electronic Materials 是一个跨学科论坛&#xff0c;旨在为材料科学、…

YOLOv8-对注意力机制模型进行通道剪枝-同时实现涨点和轻量化【附代码】

文章目录 前言视频效果文章概述必要环境一、训练自己的模型1、 训练命令2、 训练参数解析 二、模型剪枝1、 对训练好的模型将进行剪枝2、 剪枝代码详解1.解析命令行参数2. 定义剪枝函数3. 定义剪枝结构4. 更新注意力机制5. 保存更新后的模型6. 主函数 三、剪枝后的训练运行命令…

Windows 11 安装 安卓子系统 (WSA)

How to Install Windows Subsystem for Android (WSA) on Windows 11 新手教程&#xff1a;如何安装Windows 11 安卓子系统 说明 Windows Subsystem for Android 或 WSA 是由 Hyper-V 提供支持的虚拟机&#xff0c;可在 Windows 11 操作系统上运行 Android 应用程序。虽然它需…

c++读取文件时出现中文乱码

原因&#xff1a;UTF-8格式不支持汉字编码 解决&#xff1a;改成ANSI&#xff0c;因为ANSI编码支持汉字编码

生成式人工智能将如何改变网络可访问性

作者&#xff1a;Matthew Adams 受 Be My Eyes 和 OpenAI 启发的一项实验&#xff0c;尝试使用 ChatGPT 4o 实现网页无障碍 在 Elastic&#xff0c;我们肩负着一项使命&#xff0c;不仅要构建最佳的搜索驱动型 AI 平台&#xff0c;还要确保尽可能多的人喜欢使用该平台。我们相…

深入剖析vLLM:大模型计算加速系列之调度器策略探索

原文&#xff1a; 图解大模型计算加速系列&#xff1a;vLLM源码解析2&#xff0c;调度器策略(Scheduler) 目录 收起 前期提要与本期导览 一、入口函数 二、SequenceGroup 2.1 原生输入 2.2 SequenceGroup的作用 2.3 SequenceGroup的结构 三、add_request()&#xff1a…

[python][Anaconda]使用jupyter打开F盘或其他盘文件

jupyter有一个非常不好的体验&#xff0c;就是不能在界面切换到其他盘来打开文件。 使用它&#xff0c;比较死板的操作是要先进入文件目录&#xff0c;再运行jupyter。 以Windows的Anaconda安装了jupyter lab或jupyter notebook为例。 1&#xff0c;先运行Anaconda Prompt 2&…

儿童房间灯哪个牌子的好?几款儿童房间灯具品牌分享

对于视力正处于发育阶段的儿童而言&#xff0c;台灯已不仅仅是一个简单的照明工具。它不仅驱散夜幕下的阴霾&#xff0c;还能为儿童的眼部保驾护航。一款优质的护眼台灯更是不可或缺的守护者。然而&#xff0c;面对市场上琳琅满目的选择&#xff0c;怎样选出一款合适的护眼台灯…

​Stable Diffusion史上最全插件,已打包整理,12个常用插件你肯定用得上!

还在于有丰富的第三方插件&#xff0c;即我们在安装部署之后安装汉化插件的界面 插件安装方式可以是“可下载->加载扩展列表”&#xff0c;然后从列表选择或搜索插件下载&#xff0c;或直接选择“从网站安装”&#xff0c;填写插件的git仓库地址。一般我们从扩展列表搜索即可…

【Python】已解决:pymssql._pymssql.OperationalError 关于关键字‘distinct’的语法错误

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;pymssql._pymssql.OperationalError 关于关键字‘distinct’的语法错误 一、分析问题背景 在使用pymssql库与SQL Server数据库进行交互时&#xff0c;有时会遇到…

WPF在.NET9中的重大更新:Windows 11 主题

在2023年的2月20日&#xff0c;在WPF的讨论区&#xff0c;WPF团队对路线的优先级发起了一次讨论。 对三个事项发起了投票。 第一个是Windows 11 主题 第二个是更新的控件 第三个是可空性注释 最终Windows 11 主题得票最高&#xff0c;WPF团队2023-2024的工作优先级就是Windows…

UE4_材质_水体的反射与折射制作_Ben教程

在这个教程中&#xff0c;将制作水的反射和折射&#xff0c;上个教程&#xff0c;我们主要讲了制作水涟漪&#xff08;水面波纹&#xff09;和水滴法线混合&#xff0c;水深计算&#xff0c;我们首先要谈的是反射和产生折射的问题。我们将所有从干扰从场景中分离出去&#xff0…

微信小程序 canvas 处理图片的缩放移动旋转问题

这里使用到了一个插件&#xff0c;canvas-drag&#xff0c;来实现大部分功能的 上效果 直接上代码吧~ wxml <div class"container"><canvas-drag id"canvas-drag" graph"{{graph}}" width"700" height"750" ena…

页面加载503 Service Temporarily Unavailable异常

最近发现网页刷新经常503&#xff0c;加载卡主&#xff0c;刷新页面就正常了。 研究之后发现是页面需要的js文件等加载失败了。 再研究之后发现是nginx配置的问题。 我之前为了解决一个漏洞检测到目标主机可能存在缓慢的HTTP拒绝服务攻击 把nginx的连接设置了很多限制&#…

JSONpath语法怎么用?

JSONPath 可以看作定位目标对象位置的语言&#xff0c;适用于 JSON 文档。 JSONPath 与 JSON 的 关系相当于 XPath 与 XML 的关系&#xff0c; JSONPath 参照 XPath 的路径表达式&#xff0c;提供了描述 JSON 文档层次结构的表达式&#xff0c;通过表达式对目标…

点云处理实操 点云平面拟合

目录 一、什么是平拟合 二、拟合步骤 三、数学原理 1、平面拟合 2、PCA过程 四、代码 一、什么是平拟合 平面拟合是指在三维空间中找到一个平面,使其尽可能接近给定的点云。最小二乘法是一种常用的拟合方法,通过最小化误差平方和来找到最优的拟合平面。 二、拟合步骤…

【Python】已解决:ERROR: No matching distribution found for JPype

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;ERROR: No matching distribution found for JPype 一、分析问题背景 在Python开发中&#xff0c;有时我们需要使用Java库来扩展功能或实现某些特定任务。JPype…

有手就行,轻松本地部署 Llama、Qwen 大模型,无需 GPU

用 CPU 也能部署私有化大模型&#xff1f; 对&#xff0c;没错&#xff0c;只要你的电脑有个 8G 内存&#xff0c;你就可以轻松部署 Llama、Gemma、Qwen 等多种开源大模型。 非技术人员&#xff0c;安装 Docker、Docker-compose 很费劲&#xff1f; 不用&#xff0c;这些都不…

方法重载与重写的区别

1.方法重载和重写都是实现多态的方式&#xff0c;区别在于重载是编译时多态&#xff0c;重写是运行时多态。 2.重载是在同一个类中&#xff0c;两个方法的方法名相同&#xff0c;参数列表不同&#xff08;参数类型、顺序、个数&#xff09;&#xff0c;与方法返回值无关&#x…

springboot种草好物app-计算机毕业设计源码13151

摘要 随着电子商务的快速发展和智能手机的普及&#xff0c;越来越多的用户选择通过移动应用程序进行商品浏览、购买和分享体验。种草好物App作为一个专注于商品推荐和购物体验的平台&#xff0c;具有广泛的应用前景和商业价值。本研究旨在构建一个功能丰富、性能稳定的种草好物…