Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue #12

Open
emilyzfive opened this issue May 12, 2021 · 0 comments
Open

Vue #12

emilyzfive opened this issue May 12, 2021 · 0 comments

Comments

@emilyzfive
Copy link
Owner

Vue 渲染/更新原理

vue template complier 将模版编译为 render 函数,执行 render 函数生成 vnode
patch 函数先判断是不是samevnode(type 相同、key 相同), 如果是则执行 patchvnode, 否则 直接创建节点

patch(elem, vnode) 
patch(vnode, newVnode)

patchvnode 会根据 新旧 children 执行 updateChildren(新旧节点都是 element) addVnodes(新节点是 element,旧节点是 text) removeVnodes(新节点是 text,旧节点是 element)
patch 函数将 vnode 渲染成真实dom,中间会用到 diff 算法, key 起到了很大的作用(只进行同层比较)
响应式数据更新时(Object.defineProperty、Object.proxy),触发 patch 执行

初次渲染过程:

  1. 解析模板为 render 函数(或在开发环境已完成,vue-loader)
  2. 触发响应式,监听 data 属性 getter setter
  3. 执行 render 函数,生成 vnode,patch(elem, vnode)
  4. 执行 render 函数的时候,会触发 getter,数据会被当成依赖被 Watcher 收集起来,后续更新时会触发 setter,setter 会通知 Watcher,执行 re-render

更新过程:

  1. 修改 data, 触发 setter(此前在 getter 中已被监听)
  2. 重新执行 render 函数,生成 newVnode
  3. patch(vnode, newVnode)

异步渲染:

  1. $nextTick 使用
  2. 汇总 data 修改,一次性更新视图
  3. 减少 DOM 操作,提高性能

Vue 模板编译

vue-template-compiler 将模板编译成 render 函数,render 函数执行返回 h 函数,也是 createElement 函数,render 函数返回 vnode
基于 vnode 再执行 patch 和 diff
webpck vue-loader 会在开发环境中编译模板
vue 组件可以用 render 代替 template

const compiler = require('vue-template-compiler')
const template = `<p>{{ message }}</p>`
const res = compiler.compile(template)
console.log(res.render)
// with(this){return _c('p', [_v(_s(message))])}
// this = vm = new Vue({...}) - Vue 实例
// _c: createElement 也就是 h 函数
// _v: createTextVnode
// _s: toString

v-model 原理

添加了监听事件,实现了视图改变数据:双向绑定
自定义 v-model: 子组件数据的更改直接运用于父组件

Vue 响应式

Object.defineProperty 缺点:递归监听,开销大;添加属性、删除属性监听不到(使用 Vue.set、Vue.delete 解决)
Object.proxy 确点:低版本浏览器不能 polyfill
数组如何监听?重写数组原型,在重写的方法中,执行视图更新方法和真正数组原型的方法

路由原理

hash 模式:监听 hash 变化,事件 window.onhashchange
H5 history 模式:window.onpopstate 监听浏览器前进、后退;history.pushState 打开一个新路由

生命周期(包括父子组件)

beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
beforeDestory
destoryed
父子组件:
父组件先触发 beforeCreate created beforeMount,子组件 beforeCreate created beforeMount mounted,父组件再 mounted
父组件先触发 beforeUpdate 子组件 beforeUpdate、updated,父组件再 updated

slot

普通插槽
作用域插槽
具名插槽

Vue 动态组件

根据数据类型,渲染不同的组件

<component :is="componentName" />

Vue 异步组件(按需加载)

在 components 中 import

缓存组件

keep-alive

mixin

多个组件有相同逻辑,抽离出来
mixin 存在的问题:变量来源不明,不利于阅读;多 mixin 可能会造成命名冲突;mixin 和组价可能出现多对多的关系,复杂度较高
composition API 解决以上问题

Vue-router 使用

路由模式(hash、H5 history)
路由配置(动态路由、懒加载)

Vue 性能优化

合理使用 v-show v-if
合理使用 computed
v-for 加 key,以及避免和 v-if 同时使用
自定义事件、DOM 事件及时销毁
合理使用异步组件
合理使用 keep-alive
data 层级不要太深
vue-loader 在开发环境做预编译
前端项目通用性能优化,如图片懒加载等
使用 SSR

nextTick 实现原理

  • vue用异步队列的方式来控制DOM更新和nextTick回调先后执行
  • microtask因为其高优先级特性,能确保队列中的微任务在一次事件循环前被执行完毕
  • 因为兼容性问题,vue不得不做了microtask向macrotask的降级方案

Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。

原理就是使用宏任务或微任务来完成事件调用的机制,让自己的回调事件在一个eventloop的最后执行。宏任务或微任务根据浏览器情况采取不同的api,常见的 macro task 有 setTimeout、MessageChannel、postMessage、setImmediate;常见的 micro task 有 MutationObsever 和 Promise.then。

组件中 data 为什么是函数

Vue 的组件是 vue 的实例,data 是 vue 原型上的属性,构造函数创建的实例都会继承原型的属性,如果 data 是对象的话,会组件间的数据相互影响。为什么函数可以?函数中通过 this 访问的属性,this 指向当前的实例本身,所以不会有这种问题。

computed 和 watch 的区别

computed 是计算属性,由 data 中的已知值得到新值,有缓存,依赖的值变化时才会重新计算,没有变化则读取缓存的数据;如果一个数据需要经过复杂运算则用 computed
watch 是监听数据的变化,当依赖的 data 数据变化时,执行回调,参数是 newVal,oldVal。如果要在一个数据变化时做些事情,就用 watch

Vuex

action 和 mutation 的区别

改变 store 中状态的唯一方法是提交 mutation,mutation 必须是同步函数。
action 提交的是 mutation,而不是直接变更状态;action 可以包含任意异步操作。

组件通信

computed 缓存

watch 如何实现深度监听

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant