携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
今天是学习学习理解《Vue.js设计与实现》的第三篇,第一章到此结束
第一章三篇主要宏观得介绍了框架的设计思路和纲领,首先介绍前端框架中关于命令式,声明式,虚拟dom,运行时和编译时的权衡理念,然后介绍了前端框架设计需要考虑的因素,比如体积,开发体验,特性开关,错误处理等,最后介绍Vue.js在这些理念中做了哪些设计和权衡。
看完第一章,和面试官谈笑风生问题不大,但是如果被问到了细节,就需要后面的章节强化。
详细情况可以查看专栏学习理解《Vue.js设计与实现》
Vue是一个声明式的UI框架。前端页面包括,DOM元素,属性,事件,元素的层级结构。 也就是我们常写的 <template>
vue.js3除了支持使用模板描述UI外,还支持虚拟DOM描述UI。
其实我们在vue.js组件中手写的渲染函数就是使用虚拟DOM来描述UI的。
渲染器的作用就是把虚拟DOM渲染成真实DOM
渲染器函数 renderer(vnode,container)
renderer 函数精髓在于dom更新过程,后面我们会具体学习
如下虚拟dom
const vnode =
{ tag: 'div',
props: {
onclick: ()=> alert('hello')
},
children: 'click me'
}
执行render函数 虚拟DOM渲染为真实DOM
function renderer(vnode, container){
// 使用vnode.tag作为标签名称创建DOM元素
const el = document.createElement(vnode.tag)
// 遍历vnode.props,将属性、事件添加到DOM元素
for(const key in vonde.props){
if(/^on/.test(key)){
// 如果key以on开头,说明它是事件
el.addEventListener(
key.substr(2).toLowerCase(),
vnode.props[key]
)
}
}
// 处理children
if(typeof vnode.children === 'string'){
// 如果children是字符串,说明它是元素的文本子节点
el.appendChild(document.createTextNode(vnode.children))
} else if(Array.isArray(vnode.children)){
// 递归调用render函数渲染子节点,使用当前元素el作为挂载点
vnode.children.forEach(child => renderer(child, el))
}
// 将元素添加到挂载点下
container.appendChild(el)
}
组件就是一组dom的封装
可以用vnode的tag属性来存储要渲染的dom节点
如果tag类型是字符串 则说明是普通字符串
如果tag类型是数组,则说明渲染的是组件,需要递归遍历渲染
声明式地描述UI有两种方式,一个为手写虚拟dom,一个是使用模版,对于模板是怎么工作的,我们需要使用编译器。
编译器的作用就是将模版编译为渲染函数
以.vue文件为例,一个.vue文件就是一个组件,<template>
标签内部的就是模版
编译器 把模版编译成 虚拟dom,虚拟dom在通过渲染函数,更新到真实dom
在编译成过程中会表示静态属性和动态属性,生成代码时附带这些信息。
对渲染器来说省去了寻找变更点的工作量。