vue3 优势
- 性能更好
- 体积更小
- 更好的 ts 支持
- 更好的代码结构
- 更好的逻辑抽离
- 更多的新功能
vue3 升级了哪些新功能?
- 组件生命周期(beforeMount,mounted)
- v-model 的使用
- 移除 filter,可以用 computed 代替
- composition API
- emits 属性
- createApp
- Fragment
- 移除 .sync
- 多事件
异步组件写法 defineAsyncComponent 方法
components: {
AsyncCom: (() => import([path]))
}
Teleport(自定义挂载 DOM 元素)
Suspense
<Supense>
// 2个slot应用
<template>
// 异步组件
<Test1 />
</template>
<template #fallback>
Loading...
</template>
</Supense>
options API 和 composition API
- 更好的代码组织
- 更好的逻辑复用
- 更好的类型推导
composition API 是为了解决复杂业务逻辑而设计的
ref
- 值类型 响应式
- 可用于模板和
reactive
中 - 通过
.value
修改值 - 获取
DOM
元素(onMounted
之后)为什么需要 ref ?
- 到处都有值类型,在 setup、computed、合成函数,都可能返回值类型
- 返回值类型会丢失响应式
- proxy 无法代理值类型
toRef
- 针对一个响应式对象(reactive 封装的)的 prop
- 创建一个 ref,具有响应式
- toRef 如果用于普通对象(非响应式对象),产出的结构不具备响应式
toRefs
- 将响应式对象(reactive 封装)转换为普通对象
- 对象的每个 prop 都是对应的 ref
- 两者保证引用关系
ref,toRef,toRefs 最佳使用方式
- reactive 用于对象的响应式,ref 用于值类型响应式
- setup 中返回 toRefs(state),或者 toRef(state,’xxx’)
- ref 变量命名使用 xxxRef
- 合成函数返回响应式对象时,使用 toRefs
v-for 和 key
- vue2 中需要给每个循环的子节点都带上唯一的 key,不能绑定在 template 标签上。
- vue3 中 key 值是绑定在 template 标签上。
v-for 和 v-if 优先级
- vue2 中 v-for拥有更高的优先级,因此在 vue2 中做性能优化,v-if 和 v-for 不能同时在一个元素上使用。
- vue3 中 v-if 比 v-for 拥有更高的优先级
以下代码,vue2 中正常运行,但是在 vue3 中,v-if 生效时,还没有 item 变量,所以会报错
<template>
<div v-for="item in list" v-if="item % 2 === 0" :key="item">{{ item }}</div>
</template>
<script>
export default {
data() {
return {
list: [1, 2, 3, 4, 5],
};
},
};
</script>
为什么要加 .value?
- ref 是一个对象(响应式),通过 .value 存储值
- 通过 .value 属性 get 和 set 实现响应式
为什么需要 toRef 和 toRefs?
- 初衷:不丢失响应式的情况下,解构和扩展数据
- 前提:针对的是响应式对象(reactive 封装的)的非普通对象
- 注意:不创造响应式,而是延续响应式
proxy 如何实现响应式?
- 深度监听,性能更好(Object.defineProperty 是一次性递归监听,而 proxy 是什么时候用什么时候递归)
- 能监听属性的增加/删除
- 能监听数组的变化
- 能规避 Object.defineProperty 的问题
缺点:
- 无法兼容所有的浏览器,无法 polyfill ```javascript function reactive(target = {}) { if(typeof target !== ‘object’ || target === null) { return target }
const proxyConfig = { get(target, key, receiver) {
// 只处理本身(非原型的)的属性 const ownKeys = Reflect.ownKeys(target) if (ownKeys.includes(key)) { console.log('get', key) } const result = Reflect.get(...arguments) //实现深度监听 // 怎么性能优化? return reactive(result)
}, set(target, key, val, receiver) {
// 重复数据,不处理 if (target[key] === val) { return true } const ownKeys = Reflect.ownKeys(target) // 判断是否是新增的还是已有的属性 if(ownKeys.includes(key)) { console.log('已有的 key', key) } else { console.log('新增的 key', key) } console.log('set', key, val) return Reflect.set(...arguments)
}, deleteProperty(target, key) {
const result = Reflect.deleteProperty(target, key) console.log('delete property', key); return result
} }
const observed = new Proxy(target, proxyConfig)
return observed }
const data = { name: ‘jesse wang’, age: 29, info: { a: { b: { c: { d: { e: 100 } } } } } }
const proxyData = reactive(data)
<a name="4wZCs"></a>
#### v-model
双向绑定
<a name="GsDD9"></a>
#### watch 和 watchEffect
- watchEffect 不用手动传入依赖
- 每次初始化时,watchEffect 都会执行一遍回调来自动获取依赖
- watchEffect无法得到原始值,智能得到变化的值
- 监听属性的变化
- watch 明确监听哪个属性,watchEffect 会根据其中的属性,自动监听其变化
<a name="mch2V"></a>
#### setup 如何获取组件的实例?
- 在 setup 中没有 this
- getCurrentInstance,在 mounted 里面获取数据(instance.data.x)
<a name="ZoAWI"></a>
#### vue3 比 vue2 快?
- **proxy** 响应式
- **patchFlag**
- 编译模板时,动态节点做标记
- 标记,分为不同类型,如TEXT,CLASS,PROPS
- diff 算法,可以区分静态节点,以及不同类型的动态节点
- diff 算法比较节点的 patchFlag
- **hoistStatic**
- 将静态节点的定义,提升到父作用域,缓存起来
- 多个相邻的静态节点,会被合并起来(超过 9 个以上不包含 9 个)
- 典型的拿空间换时间的优化策略
- **cacheHandler**
- 缓存事件
- **SSR 优化**
- 静态节点直接输出,绕过 vdom
- 动态节点,还是动态渲染
- **tree-shaking**
- 使用才引入
> diff算法的输入做了优化
> 优化是考虑整个流程优化,而不是单个点的优化
:::danger
Vue3 中源码组织使用 typescript,而 Vue2 中使用的是 Flow。
:::
<a name="7Gews"></a>
#### vite为什么这么快?
- 开发环境下无需打包,使用 **es6 module**
- 生产环境使用 **rollup** 打包
- **es6 module**
- 远程引入
- 外链引入
- 动态引入
```javascript
async () => {
const add = import('./a.js')
add.default(1, 2)
}