Vue3.x 笔记
date
Mar 24, 2021
slug
vue3.x-note
status
Published
tags
Vue3.x
Vuejs
summary
vue3.x 尝鲜笔记,内含vue&react对比,以及vue3.x的改进点
type
Post
Vue & React 设计思路对比Vue Options/Composition ApiOptions ApiComposition ApiVue Complier 到底做了什么jsx & template虚拟 dom性能优化手段setup为什么建议在 vue3+ts 中使用 jsx 开发?提示
Vue & React 设计思路对比
vue: options => composition
react: class => hook
用法相似,但底层设计千差万别
vue 只在初始化的时候执行一次,后续通过响应式更新:响应式 + vdom
- 响应式:数据变了通知变化
- vdom 数据变了并不知道具体变化的地方需要diff算出变化
- 二者一个推一个拉,相互配合
- 如何配合?响应式主动通知变化,vdom 是被动计算
- vue1 中是纯响应式,问题在于响应式对象太大后导致页面卡顿,vue2 引入vdom
react 每次改变都会重新执行 usestate :vdom
- react 没有响应式,纯vdom,计算diff
- vdom 对象太大后导致diff时间过长超过16.6ms页面卡顿
Vue Options/Composition Api
Options Api
写法固定 先写data,method... 当业务逻辑越来越复杂,可维护性越来越差,解决方式提取业务组件、mixins(坑:命名冲突,不好追踪变量来源)
所有的配置式写法都有这种苦恼,所有的东西必须按照某种规则提前写好,代码量越来越多,难以维护。
好处就很明显,简单易懂;不好之处就是不灵活
Composition Api
import { ref, reactive } from 'vue'
export default {
setup() {
let val = ref('')
let todos = reactive([
{ id: 1, title: '1' },
{ id: 2, title: '2' },
])
const addTodo = () => {
todos.push({
id: todos.length,
title: val.value
})
val.value = ''
}
return {
val,
todos,
addTodo
}
}
}
缺点:
1. 难看
2. return 一旦数据量大,也会导致上下反复查阅代码(在script标签中写 setup,即可)
<script setup>
import { ref, reactive } from 'vue'
// import useTodo from './useTodo'
// let { val, todo, addTodo } = useTodo
let val = ref('')
let todos = reactive([
{ id: 1, title: '1' },
{ id: 2, title: '2' },
])
const addTodo = () => {
todos.push({
id: todos.length,
title: val.value
})
val.value = ''
}
<script>
// useTodo.js
import { ref, reactive } from 'vue'
export default () => {
let val = ref('')
let todos = reactive([
{ id: 1, title: '1' },
{ id: 2, title: '2' },
])
const addTodo = () => {
todos.push({
id: todos.length,
title: val.value
})
val.value = ''
}
return { val, todo, addTodo }
}
优点:
1. 通过 import 导入的依赖方便做tree-shaking。按照options的写法,build的时候虽然可以读取每个文件来查看是否使用computed但是build速度会很慢,而composition只需要查看import即可选择是否打包 computed的代码
2. 方便复用、组合逻辑,更彻底的面向对象。而组合优于继承
3. 组件任意拆分后组合类似 hook
Vue Complier 到底做了什么
把jsx、template转化成js、html能在runtime运行(浏览器)
jsx & template
- jsx 就是用js输出html,足够灵活;代价就是优化空间较小
- template不够灵活,要遵循template语法来写,优化空间较大
例子:vue3 diff:
11 /* TEXT, CLASS, PROPS */
11 就是通过位运算将 {{ name }}、:class、:name 通过用位运算组合算出;这也是template的好处,虽然限制多但是可以通过代码打上各种各样的标记来进行优化(diff优化);vue2中没有这项diff优化,在vue3中_createVNode("div", null, "谢谢") =》<div>谢谢</div>
这一项会被当作静态内容,不进行diff真正做到了按需diff
虚拟 dom
- 避免直接操作dom,在操作前通过diff找出真正需要更新的dom树节点而更新,并不是更新整棵树
- vdom除了性能更牛逼的是将view层变成对象(json)后可以通过http拉取,轻松实现跨端。不关注不同端的渲染逻辑只在乎数据(结构),因为对象(json)是基础数据结构所有端都支持
- vue2只做了双端预判,vue3的diff算法:最长递增子序列 + 双端预判
- vdom在vue和react中的区别? react:vdom是被动计算; vue:响应式主动通知变化,vdom是被动计算;具体是什么?根据组件划分,组件之间通过响应式通知,组件内部通过vdom用diff计算
性能优化手段
- complier期的优化非常重要,如果能在build的时候把
let a = new Array(6).fill(1).filter(v => v>0); console.log(a)
转成console.log([1, 1, 1, 1, 1, 1])
让 runtime直接执行console.log([1, 1, 1, 1, 1, 1])
那么性能肯定是大幅度提升的。vue3优化也是借鉴了这个思想,思想来源 facebook 的 prepack.io 项目
- vue complier 层作出的优化是:h 函数新增三个参数:patchflag dynamicprops isBlockNode 更新组件的时候加快render速度
setup
setup(props, { slots, attrs, emit }) {
return {
// ...
}
}
emit 用于响应事件
const state = reactive({
name: '11'
})
state.name += 1
return {
state
}
// 模版里直接取 {{ state.name }}
const nameRef = ref('alex')
nameRef.value += 1
return {
nameRef
}
// 模版里直接取 {{ nameRef }}, 模版解析的时候会自动判断这个值是不是ref是的话直接取value
俩者的区别在于 ref生成的是一个
{ value: 'alex' }
响应式对象const computedNameRef = computed(() => {
return nameRef.value + '2'
})
watchEffect(() => {
console.log(nameRef.value)
})
// reactive、ref值变化后做一些逻辑
// 大部分的时候执行dom、ajax等副作用函数
为什么建议在 vue3+ts 中使用 jsx 开发?
- prop的类型会在传错的时候编译器直接抛出错误,而template不行,需要来回切换查看
- jsx有动态控制组件渲染的能力,而template不行,所有的东西必须静态写死
- 唯一不好的点就是sfc中可以写样式,但是jsx中得使用cssinjs比较繁琐
提示
vue3 setup 中的 return 相当于 render,所以参考react中的一些render规则不要写引起data或者props变化的逻辑从而导致re-render