当前位置: 首页 > 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.xdnf.cn/news/1276579.html

相关文章:

  • Vue 事件冒泡处理指南:从入门到精通
  • vue2升级vue3:单文件组件概述 及常用api
  • 基于VuePress2开发文档自部署及嵌入VUE项目
  • 【数据分析】循环移位岭回归分析:光遗传学冻结行为模式研究
  • 2025华数杯比赛还未完全结束!数模论文可以发表期刊会议
  • SAP学习笔记 - 开发57 - RAP开发 Managed App RAP action 之 Accept Travel 和 Reject Travel
  • special topic 8 (2) and topic 9 (1)
  • 一键复制产品信息到剪贴板
  • Kafka消费者相关原理
  • K8s DaemonSet 详解
  • es-drager-blog
  • 安全生产基础知识(一)
  • ThreadLocal的原理是什么,使用场景有哪些?
  • 状态机浅析
  • Linux操作系统从入门到实战(十八)在Linux里面怎么查看进程
  • Pico+unity VR入门开发超详细笔记2025
  • SpringBoot实现文件上传
  • 一些js数组去重的实现算法
  • 故障诊断 | VMD-CNN-BiLSTM西储大学轴承故障诊断附MATLAB代码
  • MyBatis进阶:动态SQL、多表查询、分页查询
  • openresty-lua-redis案例
  • Python 的列表 list 和元组 tuple 有啥本质区别?啥时候用谁更合适?
  • Ubuntu 安装 Kibana
  • 旅行者1号无线电工作频段
  • MyBatisPlus插件原理
  • MVCC和日志
  • 音视频学习(五十一):AAC编码器
  • C4.5算法:增益率(Gain Ratio)
  • 嵌入式第二十四课!!linux应用软件编程与文件操作!!!
  • Rust 实战四 | Traui2+Vue3+Rspack 开发桌面应用:通配符掩码计算器