网站怎么做免费,wordpress手机显示不了图片,孟州网站建设,外贸网站建设费用多少Vue设计与实现阅读-3 1、声明式描述UI2、渲染器3、组件4、模板的工作原理5、Vue.js 是各个模块组成的有机整体 前言 前面一章我们了解了#xff0c;开发体验是衡量一个框架的重要指标之一。提供友好的警告信息至关重要#xff0c;但是越详细的警告信息#xff0c;意味着框架… Vue设计与实现阅读-3 1、声明式描述UI2、渲染器3、组件4、模板的工作原理5、Vue.js 是各个模块组成的有机整体 前言 前面一章我们了解了开发体验是衡量一个框架的重要指标之一。提供友好的警告信息至关重要但是越详细的警告信息意味着框架体积越大。为了解决这一问题可以利用 Tree-Shaking 机制配合构建工具预定义常量例如 __DEV __ 从而实现只在开发环境中打印警告信息生产环境中清楚这些代码达到代码体积的可控性。 Tree-Shaking 是一种清除 dead code 的机制。可以利用/* #PURE */ 来辅助构建工具进行 Tree-Shaking。 框架的错误处理做的好坏决定了用户程序的健壮性因此需要为用户提供统一的错误处理接口这样用户可以通过注册自定义的错误处理函数来处理异常。 1、声明式描述UI
Vue.js 模板描述
h1 clickhandleClickspan/span
/h1js 对象描述上面的UI
const title {tag: h1,props: {onClick: handleClick},children: [{tag: span}]
}如果我们想表示一个标题根据标题级别的不同分别采用h1~ h6 这几个标签如果用js实现
let level 1;
const title {tag: h${level}
}如果 level 的值变化相应的标签名称也会变化。但是如果用 模板来描述就需要一个个列举出来。
h1 v-iflevel 1/h1
h2 v-else-iflevel 2/h2
...
h6 v-else-iflevel 6/h6远远没有js对象灵活。使用js对象来描述 UI 的方式其实就是虚拟DOM。Vue3中除了支持使用模板描述 UI外还支持虚拟DOM描述 UI。例如我们手写的渲染函数就是使用虚拟 DOM 描述UI。
import {h} from vue;
export default {render() {return h(h1, {onClick: handleClick})}
}2、渲染器
虚拟 DOM 就是用 JS 对象来描述真实的DOM结构。如何将虚拟DOM变成真实的DOM并且渲染到浏览器页面中---渲染器渲染器的作用把虚拟DOM渲染为真实DOM
虚拟DOM如下
const vnode {tag: div,props: {onClick: () alert(hello)},children: click me
}编写一个 渲染器将上面的虚拟 DOM 渲染成真实DOM
function renderer (vnode, container) {// 创建 dom 元素const el document.createElement(vnode.tag);// 添加属性、事件到 dom 元素for (const key in vnode.props) {if (/^on/.test(key)) {// on 开头事件,给元素绑定事件el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key])}}// children 处理if (typeof vnode.children string) {// string -- 文本el.appendChild(document.createTextNode(vnode.children));} else if (Array.isArray(vnode.children)) {// 数组递归调用渲染子节点vnode.children.forEach(child renderer(child, el));}container.appendChild(el)
}运行结果 上述分析器实现思路
创建DOM元素vnode.tag 为标签名给元素添加属性和事件。遍历 props 对象如果 key 是 on 开头说明是事件截取字符 on 使用 toLowerCase将事件名称小写再调用 addEventListener 绑定事件处理元素的 children。如果是字符串创建文本节点如果是数组递归调用 renderer 函数渲染。
发现渲染器实现起来也很简单主要是使用一些熟悉的 DOM 操作 API 来完成渲染工作。上面只是创建节点渲染器的精髓在更新节点的阶段需要精确找啊到 vnode对象的变更点并且只更新变更的内容。
3、组件
上面了解了渲染器会将虚拟 DOM 渲染成真实的 DOM 元素。那组件呢组件和虚拟 DOM 之前有什么关系。
**组件是一组 DOM 元素的封装这组 DOM 元素就是组件要渲染的内容。**定义一个函数来代表组件函数的返回值代表组件要渲染的内容。
const MyComponent function () {return {tag: div,props: {onClick: () alert(click)},children: click me}
}可以看到组件的 返回值也是虚拟 DOM代表了组件要渲染的内容那么我们就可以使用下面的方式来描述组件。其中 tag 可以用来描述组件。
const vnode {tag: MyComponent
}修改之前的渲染函数 // 渲染函数renderer(vnode, container) {if (typeof vnode.tag string) {// string -- 普通标签元素this.mountElement(vnode, container);} else if (typeof vnode.tag function) {// string -- 组件this.mountComponent(vnode, container);}},// 渲染标签元素mountElement(vnode, container) {// 创建 dom 元素const el document.createElement(vnode.tag);// 添加属性、事件到 dom 元素for (const key in vnode.props) {if (/^on/.test(key)) {// on 开头事件,给元素绑定事件el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key])}}// children 处理if (typeof vnode.children string) {// string -- 文本el.appendChild(document.createTextNode(vnode.children));} else if (Array.isArray(vnode.children)) {// 数组递归调用渲染子节点vnode.children.forEach(child this.renderer(child, el));}container.appendChild(el)},// 渲染组件mountComponent(vnode, container) {// 调用组件函数获取要渲染的内容const subTree vnode.tag();this.renderer(subTree, container)},4、模板的工作原理
上面我们了解了虚拟 DOM 是如何渲染成真实 DOM的那么模板是如何工作的呢其实是依赖于编译器。
编译器的作用是将模板编译成渲染函数。 模板如下
div clickhandleClickclick me/div对编译器来说模板相当于一个字符串它会分析字符串并生成一个功能与之相同的渲染函数
render() {return h(div, {onClick: handleClick}, click me)
}在 Vue中一个.vue文件就是一个组件
templatediv clickhandleClickclick me/div
/templatescript
export default {data() {return {}},methods: {handleClick() {// do nothing}}
}
/script其中 template 标签里的内容为模板内容编译器会把模板内容编译成渲染函数并且添加到 script 标签上最终在浏览器里面运行的代码就是
export default {data() {return {}},methods: {handleClick() {// do nothing}},render() {return h(div, {onClick: handleClick}, click me)}
}对一个组件来说他要渲染的内容最终都是通过渲染函数产生的渲染器再将渲染函数返回的虚拟 DOM 渲染为真实 DOM这就是模板的工作原理也是 Vue.js 渲染页面的过程。
5、Vue.js 是各个模块组成的有机整体
组件的实现依赖于渲染器模板的编译依赖于编译器。编译后生成的代码是根据渲染器和虚拟 DOM的设计决定的。 因此Vue的各个模块之间是相互关联相互制约的。 模板
div idfoo :classcls/div渲染函数
render() {return {tag: div,props: {id: foo,class: cls}}
}cls 是一个动态属性那编译器如何知道 cls 发生了变化呢。从上面的模板 我们可以看出 id 是不会发生变化的 :class 可能会发生变化。编译器能识别出哪些是静态属性哪些是动态属性因此可以在生成代码的时候标志出哪些是动态的属性。
render() {return {tag: div,props: {id: foo,class: cls},patchFlags: 1 // 1 代表 class是动态的}
}在虚拟 DOM 中多了一个 patchFlags 属性标志 class 的类型是动态还是静态这样渲染器可以根据这个标志知道有什么属性会发生变化。