开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 8 天,点击查看活动详情
前言
vue3开始了!!!
思考了下关于vue3 怎么写。我想先从vue3的网上的一些与vue2对比的一些面试题入手。先整理一下2版本和3版本的区别,及开发v3项目时遇到的一些问题。再去整理v3的源码。我觉得有方向的看V3的源码我会更有兴趣看下去(因为我确实纯看源码会烦躁)
下面列一下问题
V2与V3的区别
既然是新版本,肯定是要对比一下的。
区别:
| 区别 | v2 | v3 |
|---|---|---|
| 响应式 | Object.definePropety() | Proxy |
| API | object API | Composition API(组合API) |
| dom | diff | 重构虚拟dom |
| ... | ... | ... |
V3新特性
数据响应式
vue3启用了proxy替代Object.defineProperty。
对于Proxy可以理解成:在目标对象之前假设一层拦截,外界访问,必须要先通过这层拦截
操作时是对new Proxy返回的一个新对象进行操作的.
相比较proxy比defineproperty遍历属性的方式效率更高,性能更好
- 解决了对象、数组更新的检测问题,优化了响应式的监听的性能(V2对于数组的监听有缺陷),
- 可以监听删除的属性
- 可以监听数组的索引和length
- proxy可以直接对整个对象劫持。(v2检测对象属性,需要深层次监听才可以)
- 可以动态监听新增的属性
- 响应式是惰性的
- V2中,响应式是递归遍历对象,以保证这个对象每一层都是响应式的,有很大的性能消耗
- V3中,proxy不需要初始化的时候遍历所有属性,只有访问的时候再去递归处理。就是按需实现响应式,减少性能消耗。他的处理方式是在getter里面实现递归的
组合式API
V2中的写法,被称作options API(选项式API)
先提一下选项式的缺陷:因为这种方式,特定的代码需要写在特定的位置,代码量一多,导致后续维护或者接手的人的接受度不友好。代码很乱
V3中,提出Composition API(组合式API)
- setup
- 是v3中新增的一个配置项,值为一个函数。是组合式api写法的入口点
- setup不能是一个async函数
- return 中返回的属性跟data合并,返回的方法跟methods方法合并,如若重名,setup为主
写法如下(两种):
<script setup>...</script>
<script>
setup(props, contex){}|| setup(props, {attrs,slots,emit}){}
</script>
-
ref reactive toRef toRefs
- ref: 是一个定义基本数据类型的响应式引用.
- 仅能监听基本类型的变化,不能监听复杂类型的变化(数组,对象)
- ref的底层原理也是调用了reactive
const name = ref('vue3') console.log(name.value)- reactive:检测复杂数据类型,返回对象的响应式副本。这个必须要传一个对象,不能传基本类型.
const obj = reactive({name: 'vue3'}) console.log(obj.name)- toRefs:将响应式对象转换为普通对象,把对象中的每一个属性,包裹成ref对象(接收一个对象作为参数,遍历对象的所有属性,然后挨个调用toRef执行)
setup(){
let msg = { name: 'zs', age: 16 }
let msg3 = toRefs(msg)
console.log(msg) // { name:ref, age:ref } ref代指ref对象
function change3() {
msg3.name.value = 'zl'
msg3.age.value = 20
console.log(msg, msg3) // {name: "zl", age: 20} { name:ref, age:ref }
}
change3()
return { msg3, change3 }
}
- [toRef](https://www.javascriptc.com/vue3js/api/refs-api.html#toref):可以用来为源响应式对象上的 property 新创建一个 [`ref`](https://www.javascriptc.com/vue3js/api/refs-api.html#ref)。然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。
- 用来抽离响应式对象的某一个属性,并把这个属性包裹成ref对象。使其与原对象产生链接
setup(props, { emit }) {
const page = toRef(props, 'page')//将props里面的page 转成一个 ref的响应式的值,相当于:const page = ref()这种形式。
const handleCurrentChange = val => {
emit('update:page', val) // 这里改变了page 比如从1变成了2,但是视图上没有改变,视图上还是1
emitChange()
}
const emitChange = () => { // 这里触发change之后页面才会跳到第二页,并展示第二页的数据
emit('change', {
currentPage: page.value,
pageSize: size.value,
})
}
return {
handleCurrentChange,
}
},
- provide inject
provide、inject提供依赖注入 ,实现祖孙级组件通信- 用法和V2没啥区别
// 祖先组件 const msg = ref('red') provide('msg', msg) // 子组件 setup() { const msg = inject('msg') return { msg } }
V3中获取dom
V2中我们获取dom:
<div ref='title'>标题</div>
console.log(this.$refs.title)
V3中我们获取dom:
<div ref='title'>标题</div>
setup(){
const refTitle = ref(null)
console.log(menu_item.value)
}
获取dom之后修改样式
const bg = ref(null);
nextTick(() => {
bg.value.style.backgroundImage = `url(${bg})`; //设置背景图片
});
后记
本文仅作为自己一个阅读记录,具体还是要看大佬们的文章