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

Vue.js设计于实现 - 概览(二)

文章目录

    • vue采用运行时+编译时
    • 虚拟DOM和innerHTML性能消耗比较
    • 打包工具
    • 为用户传入的回调函数添加错误处理
    • Vnode
    • 实现一个只用于创建DOM的render
    • 组件Render
    • 模板工作原理-编译器

vue采用运行时+编译时

运行时(render):vnode转dom

编译时(compiler):vue模板转vnode

虚拟DOM和innerHTML性能消耗比较

  • 创建页面时

虚拟DOM -> vnode(js) + dom
||
命令式的innerHtml -> 字符串(js) + dom

  • 更新DOM时

虚拟DOM -> diff + vnode(js) + 部分dom更新
^
命令式的innerHTML -> 字符串(js) + 销毁、新建dom

打包工具

vue采用rollup.js实现打包

  • 实现良好的tree-shaking(消除不会执行的代码)

打包工具本来就支持,但是如果该函数产生副作用则无法移出

副作用:该函数对外部产生了影响(例如修改或访问了全局变量)

所以如果想要给副作用函数添加tree-shaking,需要给rollup显式声明这段代码不会产生副作用/*#__PURE__*/

为用户传入的回调函数添加错误处理

当我们封装一个工具模块,接收一个回调函数作为参数并执行时,要添加错误处理

// utils.js
export default {foo(fn) {callWithErrorHandling(fn)}
}
function callWithErrorHandling(fn) {try {fn && fn()} catch (e) {console.log(e)}
}

我们可以进一步封装统一的错误处理函数,将错误传递给用户,让用户来控制处理

// utils.js
let handleError = null
export default {foo(fn) {callWithErrorHandling(fn)},// 用户可以调用该函数注册统一的错误处理函数registerErrorHanlder(fn) {handleError = fn}
}
function callWithErrorHandling(fn) {try {fn && fn()} catch (e) {handleError(e)}
}
import utils form 'utils.js'
utils.registerErrorHanlder((e) => {// 用户可以选择在此处对错误进行更进一步的处理,比如上报日志等console.log(e)
})
utils.foo(() => {})

Vnode

// <h1 @click = 'handler'><span><span></h1>
const title = {tag: 'h1',props: {onClick: handler},children: [{ tag: 'span' }]
}
// 使用h函数更加方便的编写虚拟dom
h('h1', { onClick: handler })

实现一个只用于创建DOM的render

function mountElement(vnode, container) {// 使用vnode.tag作为标签名称创建DOMconst element = document.createElement(vnode.tag);// 遍历vnode.props并设置属性、事件if (vnode.props) {for (const [key, value] of Object.entries(vnode.props)) {if (/^on/.test(key)) {// 如果是事件处理器,添加事件监听const eventType = key.slice(2).toLowerCase(); // 去掉'on'前缀element.addEventListener(eventType, value);} else {element.setAttribute(key, value);}}}// 处理子节点if (vnode.children) {if (typeof vnode.children === 'string') {// 文本节点element.appendChild(document.createTextNode(vnode.children));} else {vnode.children.forEach(child => {renderer(child, element);});}}// 挂载container.appendChild(element);}

组件Render

vue的组件就是一组dom元素的封装
即一个拥有返回vnode对象的函数 的对象(这里给组件包一层-通过render获取vnode而不是直接返回vnode对象是因为MyComponent里还要进行其他操作)

const MyComponent = {render() {return {tag: 'div',props: {},children: '123'}}
}
// 在vnode中用tag属性存储组件函数
const vnode = {tag: MyComponent
}

此时的render要支持组件

function renderer(vnode, container) {if(typeof vnode.tag === 'string') {// 正常标签元素,调用上面的mountElementmountElement(vnode, container)} else if(typeof vnode.tag === 'object') {// 组件mountComponent(vnode, container)}
}function mountComponent() {// 获取组件vnodeconst subtree = vnode.tag.render()// 递归渲染subtreerenderer(subtree, container)
}

模板工作原理-编译器

将模板转为render函数
同时编译器能够识别哪些静态属性,哪些是动态,并在生成的render中进行标识,这样就避免了渲染器花费力气去寻找,例如

<div id="foo" :class="cls"></div>
render(){return {tag: 'div',props: {id: 'foo',class: cls},patchFlags: 1 // 假设数字1代表class是动态的}
}
http://www.dtcms.com/a/324714.html

相关文章:

  • 跑酷小游戏2.0
  • C语言(长期更新)第10讲:操作符详解(二)
  • 麻溜启动Oracle实例demo
  • 【渲染流水线】[几何阶段]-[归一化NDC]以UnityURP为例
  • 基于Spring Boot和WebSocket的实时聊天系统
  • Openlayers基础教程|从前端框架到GIS开发系列课程(21)geojson实现线要素和区要素
  • git merge的原理和过程,merge conflict产生的原因、处理的逻辑
  • 【话题讨论】GPT-5 发布全解读:参数升级、长上下文与多领域能力提升
  • MCP学习与实践
  • ESP32安装于配置
  • [激光原理与应用-216]:设计 - 皮秒紫外激光器 - 热管理设计,多维策略保障高效稳定运行
  • 腾讯云EdgeOne Pages深度使用指南
  • 计算机网络:什么是AD域
  • 线程的sleep、wait、join、yield如何使用?
  • 随想记——excel报表
  • XGBoost参数evals的作用及使用方法
  • 【图像算法 - 11】基于深度学习 YOLO 与 ByteTrack 的目标检测与多目标跟踪系统(系统设计 + 算法实现 + 代码详解 + 扩展调优)
  • 什么是缓存击穿、缓存穿透、缓存雪崩及其解决方案
  • Oracle lgwr触发条件
  • Docker 容器化工具及常用操作
  • Excel版经纬度和百分度互转v1.1
  • crc32算法php版----crc32.php
  • 【Spring IoC 核心实现类详解:DefaultListableBeanFactory】
  • Leetcode 3646. Next Special Palindrome Number
  • 分发糖果(贪心算法)
  • Vue.js设计于实现 - 响应式(三)
  • Spring Boot 全局异常处理与日志监控实战
  • OneCode 3.0 可视化功能全面分析:从开发者到用户的全场景解析
  • 一周学会Matplotlib3 Python 数据可视化-绘制条形图(Bar)
  • 论文复现与分析内容关于一种实用的车对车(V2V)可见光通信(VLC)传播模型