您现在的位置是:首页 >其他 >【vue3】需要了解哪些【未完结】网站首页其他
【vue3】需要了解哪些【未完结】
这里写目录标题
- 一.vue3入门
- 1. vue3带来了什么
- 2. vue3工程的创建
- 二、常用Composition API
- 1. setup(函数和语法糖)
- 2. ref 和reactive
- 3. vue3的响应式原理
- 4.computed
- 5.watch
- 6. watchEffect函数
- 7.watch 和 computed 的区别
- 8.watch和watchEffect的区别
- 9. watchEffect与computed
- 10. vue的生命周期
- 11. toRef 和 toRefs 函数
- 12. shallowReactive 与 shallowRef
- 13. readonly 与 shallowReadonly
- 14. toRaw 与 markRaw
- 15.customRef 自定义ref使用
- 16.provide 与 inject
- 17.响应式数据的判断
一.vue3入门
1. vue3带来了什么
-
更快的渲染速度:Vue3使用了Proxy代理对象,可以更快地跟踪数据变化,从而提高渲染速度。
-
更小的体积:Vue3的体积比Vue2更小,同时也支持按需加载,减少了页面加载时间。
-
更好的TypeScript支持:Vue3对TypeScript的支持更加完善,可以更好地进行类型检查和代码提示。
-
更好的组件封装:Vue3引入了Composition API,可以更好地封装组件逻辑,使得组件更加可复用和易维护。
-
更好的响应式系统:Vue3的响应式系统进行了重构,可以更好地处理嵌套对象和数组的变化,同时也提供了更多的API来处理响应式数据。
总之,Vue3带来了更好的性能、更小的体积、更好的TypeScript支持、更好的组件封装和更好的响应式系统,使得开发者可以更加高效地开发Vue应用。
2. vue3工程的创建
1. 使用vue-cli创建
2. 使用vite创建
与webpack的区别
- 底层原理:vite通过go语言实现,性能好,打包速度快很多,比webpack快10-100倍
- vite采用预构建,会把所有的模块做预编译,打包构建时只更新有修改的模块,webpack项目越大打包速度越慢
- vite有缓存,工具模块和包依赖等采用强缓存,直接缓存到浏览器,不会再重新加载。对可能发生变化的模块做协商缓存,只编译有变化的部分
二、常用Composition API
vue3中的组合API都是函数,使用时需要先引入(setup不需要引入)
1. setup(函数和语法糖)
- 是vue3的一个新配置项,值是一个函数
- 执行时间:在beforeCreate之前,即组件创建之前
- 这就意味着在setup函数中 this 还不是组件实例,this 此时是 undefined
- 在模版中需要使用的数据和函数,需要在 setup 返回
- setup的参数:
- props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性
- context:上下文对象
- attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs。
- slots: 收到的插槽内容, 相当于 this.$slots。
- emit: 分发自定义事件的函数, 相当于 this.$emit。
- 组件中所用到的:数据(vue2中的data)、方法(vue2中的methods)、生命周期等,均需要写在setup中,且需要被返回后才可以在模板中使用
- etup有两种返回值
- 返回一个对象,则对象中的属性、方法,在模板中可以直接使用
- 返回一个渲染函数,则可以自定义渲染的内容
// import {h} from 'vue'
export default {
name: 'App',
setup() {
// 数据(相当于vue2中的data)
let name = 'dudu'
// 方法(相当于vue2中的methods)
const sayHi = () => {
console.log(`hi,${name}`)
}
// 返回一个对象
return {
name,
sayHi
}
// 返回一个渲染函数
// return () => {
// return h('要返回的元素','要返回的内容')
// }
},
}
- 尽量不要vue2、vue3混用
- vue3可以向下兼容vue2的data、methods,vue2的data、methods可以通过this获取setup中数据和方法
- setup里不可以读取data、methods中数据、方法
- 如果vue2、vue3有重名,setup优先
- setup不能是一个async函数,如果使用了async返回的就不是一个对象,而是promise,模板中也就不能使用。但是可以和Suspense、异步组件搭配使用async
- setup语法糖可以直接在script标签中写,不需要返回值
<script setup>
// 按需引入
import { ref, reactive, onMounted } from "vue";
import { ElMessage } from "element-plus";
import axios from "axios";
// 定义响应式数据
const showButton = ref(false);
const value1 = ref("");
const inputValue = ref("");
// 定义函数
const handleCommand = (command) => {
ElMessage(`click on item ${command}`);
};
const handleFocus = () => {
showButton.value = true;
};
</script>
2. ref 和reactive
- ref
- 作用:定义基本类型的响应式数据
- JS操作数据: xxx.value
- 模板中读取数据不需要 .value
- 接收的数据(initValue)可以是:基本类型、也可以是对象类型
- 基本类型的数据:响应式是通过Object.defineProperty()的get与set完成
- 对象类型的数据:通过vue3的新函数——reactive函数实现(proxy)
- reactive作用:定义对象类型的响应式数据(基本类型用ref)
- 接收一个对象或数组,返回一个代理对象(proxy对象)
- reactive定义的响应式数据是深层次的
- 内部基于ES6的proxy实现,通过代理对象对源对象内部数据进行操作
- 区别
- 定义
ref :定义基本数据类型
reactive:定义对象或数组类型的数据 - 原理
ref:通过Object.defineProperty()的get和set来实现响应式(数据劫持)
reactive:通过Proxy来实现响应式(数据劫持),并通过Reflect操作源对象内部数据 - 使用:
ref定义的数据:操作数据需要 .value ,读取数据时模板中不需要 .value
reactive定义的数据:操作和读取都不需要 .value
一般使用 reactive 较多,可以将基本类型的数据封装在对象里,然后再使用reactive
- 定义
3. vue3的响应式原理
1. Vue2 的响应式原理
- 实现原理
- 对象类型:通过Object.defineProperty()对属性读取、修改进行拦截(数据劫持)
- 数组类型:通过重写更新数组的一系列方法来实现拦截(对数组的变更方法进行了包裹)
- 存在的问题
- 新增属性、删除属性,界面不会更新
- 直接通过下表修改数组,界面不会自动更新
2.vue3的的响应式原理
- 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
- 通过Reflect(反射): 对源对象的属性进行操作
4.computed
- 与Vue2中computed配置功能一致
- 使用vuex中的state时,需要用到响应式
- 给computed传入函数,返回值就是计算属性的值
给computed传入对象,get获取计算属性的值,set监听计算属性改变。这种写法适用于需要读写计算属性的情况
setup(){
...
//计算属性——简写
let fullName = computed(()=>{
return person.firstName + '-' + person.lastName
})
//计算属性——完整
let fullName = computed({
// 读
get(){
return person.firstName + '-' + person.lastName
},
// 写
set(value){
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
5.watch
- 监视单个数据
// 监视(简单写法)
/**
* 第一个参数:要监视的内容
* 第二个参数:监视的值:newValue、oldValue
*/
watch(sum,(newVal,oldVal) => {
console.log('sum值发生了变化')
})
- 监视多个数据(可以写多个watch,也可以写成数组形式)
watch([xxx,xxxxx],(newVal,oldVal) => {
console.log('监视多个内容!',newVal,oldVal)
})
- 参数问题
- 第一个参数:要监视的内容
- 第二个参数:监视的值:newValue、oldValue
- watch的第三个参数为相关配置
immediate:是否立即监听
deep:深度监听
watch([xxx,xxxxxx],(newVal,oldVal) => {
console.log('监视多个内容!',newVal,oldVal)
},{
immediate:true,
deep:true
})
注意有坑!!!
- 坑1: 监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)。
/* 监视reactive定义的响应式数据
若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!
若watch监视的是reactive定义的响应式数据,则强制开启了深度监视
*/
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{immediate:true,deep:false}) //此处的deep配置不再奏效
- 坑2: 监视reactive定义的响应式数据中某个或某些属性时:deep配置有效
监视某个或某些属性要写成函数形式,返回需要监视的属性
//监视reactive定义的响应式数据中的某些属性
watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true}
- watch监视ref时的value问题
基本类型数据:监视的是数据对应的实例对象,加上了.value 表示监视ref的值
对象或数组:需要加上 .value 或者开启深度监视
6. watchEffect函数
- watchEffect函数中直接写回调函数,不需要指定监视的内容
- 回调函数内部使用的数据就是被监视的数据
watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性
7.watch 和 computed 的区别
- 缓存
computed支持缓存,相依赖的数据发生改变才会重新计算;
watch不支持缓存,只要监听的数据变化就会触发相应操作 - 异步
computed不支持异步,当computed内有异步操作时是无法监听数据变化的;
watch支持异步操作 - 数据
computed属性的属性值是一函数,函数返回值为属性的属性值,computed中每个属性都可以设置set与get方法。
watch监听的数据必须是data中声明过或父组件传递过来的props中的数据,当数据变化时,触发监听器
8.watch和watchEffect的区别
watch
和 watchEffect
都是 Vue 3 中的响应式 API,它们的主要区别在于:
watch
是一个有返回值的函数,需要手动停止监听,而watchEffect
是一个自动清理的函数,不需要手动停止监听。watch
可以监听多个数据源,而watchEffect
只能监听一个数据源。watch
可以通过第三个参数options
来配置监听行为,比如是否立即执行回调函数、是否深度监听等,而watchEffect
没有这些配置选项。- watch具有一定的惰性lazy 第一次页面展示的时候不会执行,只有数据变化的时候才会执行(设置immediate: true时可以变为非惰性,页面首次加载就会执行)。watchEffect立即执行,没有惰性,页面的首次加载就会执行
9. watchEffect与computed
-
computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
-
而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
-
computed若是值没有被使用时不会调用,但是watchEffect始终会调用一次
10. vue的生命周期
vue2 的生命周期
包含创建 、运行、销毁三个阶段
- beforeCreate():实例在内存中被创建出来,还没有初始化好data和methods属性
- create():实例已经在内存中创建,已经初始化好data和method,此时还没有开始编译模版。
- beforeMount():已经完成了模版的编译,还没有挂载到页面中。
- mounted():将编译好的模版挂在到页面指定的容器中显示。
- beforeUpdate():状态更新之前执行函数,此时data中的状态值是最新的,但是界面上显示的数据还是旧的,因为还没有开始重新渲染DOM节点。
- updated():此时data中的状态值和界面上显示的数据都已经完成了更新,界面已经被重新渲染好了!
- beforeDestroy():实例被销毁之前。
- destroyed():实例销毁后调用,Vue实例指示的所有东西都会解绑,所有的事件监听器都会被移除,所有的子实例也都会被销毁。组件已经被完全销毁,此时组件中所有的data、methods以及过滤器,指令等,都已经不可用了。
vue3的生命周期
- setup():开始创建组件之前,在beforeCreated和created之前执行,创建的是data和method
- onBeforeMount():组件挂载到节点上之前执行的函数;
- onMounted():组件挂载完成后执行的函数;
- onBeforeUpdate():组件更新之前执行的函数;
- onUpdate():组件更新完成之后执行的函数;
- onBeforeUnmount():组件卸载之前执行的函数;
- onUnmounted():组件卸载完成后执行的函数;
- onActivated():被包含在< keep-alive >中的组件,会多出两个生命周期钩子函数,被激活时执行;
- onDeactivated():比如从A组件,切换到B组件,A组件消失时执行;
- onErrorCaptured():当捕获一个来自子孙组件的异常时激活钩子函数。
vue2和vue3的生命周期对比
vue2的生命周期 | ue3的生命周期 |
---|---|
beforeCreate | setup() |
created | setup() |
beforeMount | onBeforeMount(() => {}) |
mounted | onMounted(() => {}) |
beforeMount | onBeforeUpdate(() => {}) |
updated | onUpdated(() => {}) |
beforeDestroy | onBeforeUnmount(() => {}) |
destroyed | onUnmounted(() => {}) |
11. toRef 和 toRefs 函数
toRef
和 toRefs
是 Vue 3 中的两个响应式函数,它们的作用是将一个普通的 JavaScript 对象或者数组转换成响应式对象或数组。
toRef
函数将一个普通的 JavaScript 对象的属性转换成一个响应式对象的属性,返回一个Ref
对象。toRefs
函数将一个普通的 JavaScript 对象的所有属性转换成响应式对象的属性,返回一个包含所有Ref
对象的对象。toRefs
函数返回的是一个包含所有Ref
对象的对象,而不是一个响应式对象。如果需要将这个对象传递给子组件,需要使用toRef
函数将其转换成响应式对象。
toRef
函数将一个普通的 JavaScript 对象的属性转换成一个响应式对象的属性,返回一个 Ref
对象。Ref
对象是一个包装器,可以通过 .value
属性获取或设置值。当原始对象的属性值发生变化时,Ref
对象的值也会相应地更新。
import { reactive, toRef } from 'vue'
const state = reactive({
count: 0
})
const countRef = toRef(state, 'count')
console.log(countRef.value) // 0
state.count++
console.log(countRef.value) // 1
toRefs
函数将一个普通的 JavaScript 对象的所有属性转换成响应式对象的属性,返回一个包含所有 Ref
对象的对象。这个函数的主要作用是将一个响应式对象解构成普通的 JavaScript 对象,方便在模板中使用。
import { reactive, toRefs } from 'vue'
const state = reactive({
count: 0,
message: 'Hello, world!'
})
const refs = toRefs(state)
console.log(refs.count.value) // 0
console.log(refs.message.value) // 'Hello, world!'
需要注意的是,toRefs
函数返回的是一个包含所有 Ref
对象的对象,而不是一个响应式对象。如果需要将这个对象传递给子组件,需要使用 toRef
函数将其转换成响应式对象。
import { reactive, toRefs, toRef } from 'vue'
const state = reactive({
count: 0,
message: 'Hello, world!'
})
const refs = toRefs(state)
export default {
setup() {
return {
count: toRef(refs, 'count'),
message: toRef(refs, 'message')
}
}
}
12. shallowReactive 与 shallowRef
shallowReactive
和 shallowRef
是 Vue 3 中的两个响应式 API,它们都可以用来创建响应式数据,但是它们的使用场景和行为有所不同。
shallowReactive
用于创建一个浅层响应式对象,它只会对对象的第一层属性进行响应式处理,而不会对嵌套的对象进行处理。这意味着,如果你修改了嵌套对象的属性,那么这个修改不会触发响应式更新。例如:
import { shallowReactive } from 'vue'
const state = shallowReactive({
name: '张三',
age: 18,
address: {
province: '广东',
city: '深圳'
}
})
// 修改嵌套对象的属性,不会触发响应式更新
state.address.province = '北京'
// 修改第一层属性,会触发响应式更新
state.name = '李四'
shallowRef
用于创建一个浅层响应式引用,它可以将任何类型的数据转换为响应式数据。与 shallowReactive
不同的是,shallowRef
不会对对象进行浅层处理,而是直接将整个对象转换为响应式数据。这意味着,如果你修改了嵌套对象的属性,那么这个修改会触发响应式更新。例如:
import { shallowRef } from 'vue'
const state = shallowRef({
name: '张三',
age: 18,
address: {
province: '广东',
city: '深圳'
}
})
// 修改嵌套对象的属性,会触发响应式更新
state.value.address.province = '北京'
// 修改第一层属性,会触发响应式更新
state.value.name = '李四'
总的来说,shallowReactive
和 shallowRef
都是用于创建响应式数据的 API,但是它们的使用场景和行为有所不同。如果你需要对嵌套对象进行响应式处理,那么应该使用 shallowRef
;如果你只需要对第一层属性进行响应式处理,那么可以使用 shallowReactive
。
13. readonly 与 shallowReadonly
readonly
和 shallowReadonly
都是 Vue3 中提供的响应式 API,用于创建只读的响应式对象。它们的区别在于:
-
readonly
可以递归地将一个对象转换为只读的响应式对象,而shallowReadonly
只会将对象的第一层属性转换为只读的响应式对象,不会递归转换嵌套的对象。 -
readonly
返回的对象是完全只读的,无法修改对象的属性值,也无法添加或删除属性。而shallowReadonly
返回的对象只是第一层属性只读,如果对象的属性是一个对象,那么这个对象的属性仍然可以修改。
readonly
的使用方法如下:
import { reactive, readonly } from 'vue'
const state = reactive({
count: 0,
obj: {
name: '张三',
age: 18
}
})
const readonlyState = readonly(state)
console.log(readonlyState.count) // 0
console.log(readonlyState.obj.name) // 张三
// 尝试修改只读对象的属性值
readonlyState.count = 1 // 报错,无法修改只读对象的属性值
readonlyState.obj.name = '李四' // 成功,只读对象的属性值可以修改
从上面的例子可以看出,readonly
可以将一个响应式对象转换为只读的响应式对象,可以通过访问只读对象的属性值来获取数据,但是无法修改只读对象的属性值。
shallowReadonly
的使用方法如下:
import { reactive, shallowReadonly } from 'vue'
const state = reactive({
count: 0,
obj: {
name: '张三',
age: 18
}
})
const readonlyState = shallowReadonly(state)
console.log(readonlyState.count) // 0
console.log(readonlyState.obj.name) // 张三
// 尝试修改只读对象的属性值
readonlyState.count = 1 // 报错,无法修改只读对象的属性值
readonlyState.obj.name = '李四' // 成功,只读对象的属性值可以修改
// 尝试修改只读对象的嵌套对象的属性值
readonlyState.obj.age = 20 // 成功,只读对象的嵌套对象的属性值可以修改
从上面的例子可以看出,shallowReadonly
可以将一个响应式对象的第一层属性转换为只读的响应式对象,可以通过访问只读对象的属性值来获取数据,但是无法修改只读对象的第一层属性值,而嵌套对象的属性值可以修改。
14. toRaw 与 markRaw
toRaw
和 markRaw
是 Vue.js 3.x 中的两个 API,用于处理响应式数据。
toRaw
方法用于获取一个响应式对象的原始数据,即非响应式的数据。markRaw
方法用于标记一个对象为“非响应式的”,即使这个对象被包含在响应式对象中,也不会被转换为响应式数据markRaw
方法只能标记对象本身为非响应式的,而不能标记对象的属性为非响应式的。如果需要标记对象的属性为非响应式的,可以使用 markRaw 方法嵌套对象。
toRaw使用:
在下面的例子中,toRaw
方法将响应式对象 state
转换为了原始数据 rawState
,并将其输出到控制台。
import { reactive, toRaw } from 'vue'
const state = reactive({
count: 0
})
const rawState = toRaw(state)
console.log(rawState) // { count: 0 }
markRaw使用:
在下面的例子中,markRaw
方法将对象 { name: 'John', age: 30 }
标记为非响应式的,并将其作为 state
对象的一个属性。即使 state
对象是响应式的,data
属性也不会被转换为响应式数据。因此,当我们修改 data
属性的值时,不会触发响应式更新。
import { reactive, markRaw } from 'vue'
const state = reactive({
count: 0,
data: markRaw({
name: 'John',
age: 30
})
})
console.log(state.data.name) // 'John'
state.data.name = 'Mike'
console.log(state.data.name) // 'Mike'
在下面的例子中,我们使用 markRaw
方法将对象 { name: 'John', age: 30 }
标记为非响应式的,并将其作为 state
对象的一个属性 data.info
。这样,即使 state
对象是响应式的,data.info
属性也不会被转换为响应式数据。因此,当我们修改 data.info
属性的值时,不会触发响应式更新。
import { reactive, markRaw } from 'vue'
const state = reactive({
count: 0,
data: {
info: markRaw({
name: 'John',
age: 30
})
}
})
console.log(state.data.info.name) // 'John'
state.data.info.name = 'Mike'
console.log(state.data.info.name) // 'Mike'
15.customRef 自定义ref使用
在 Vue 3 中,customRef
是一个新的 API,它允许我们创建一个自定义的 ref。
使用 customRef
,我们可以自定义 ref 的读取和写入行为,从而实现更加灵活的数据绑定。
下面是一个使用 customRef
的示例:
import { customRef } from 'vue';
function useCustomRef(initialValue) {
let value = initialValue;
return customRef((track, trigger) => ({
get() {
track();
return value;
},
set(newValue) {
value = newValue;
trigger();
}
}));
}
export default {
setup() {
const customRef = useCustomRef('initial value');
return {
customRef
};
}
};
在上面的示例中,我们定义了一个 useCustomRef
函数,它接受一个初始值,并返回一个自定义的 ref。
在 customRef
的工厂函数中,我们定义了 get
和 set
方法,它们分别对应 ref 的读取和写入操作。在 get
方法中,我们使用 track
函数来追踪依赖,以便在数据变化时更新组件。在 set
方法中,我们使用 trigger
函数来触发更新。
最后,在组件中使用 useCustomRef
函数创建一个自定义的 ref,并将其返回。
使用自定义的 ref,我们可以实现更加灵活的数据绑定,例如在 set
方法中添加一些额外的逻辑,或者在 get
方法中返回一个经过计算的值。
16.provide 与 inject
在 Vue 3 中,provide
和 inject
仍然可以用来实现父组件向子组件传递数据,但是与 Vue 2 中的用法略有不同。
provide
和 inject
都是在组件实例上定义的属性,provide
定义在父组件中,inject
定义在子组件中。provide
可以是一个对象或者一个函数,inject
可以是一个数组或者一个对象。
下面是一个使用 provide
和 inject
实现父组件向子组件传递数据的例子:
<template>
<div>
<child-component></child-component>
</div>
</template>
<script>
import { provide, inject } from 'vue'
const MyProvideComponent = {
setup() {
const data = 'Hello, World!'
provide('myData', data)
}
}
const ChildComponent = {
setup() {
const data = inject('myData')
return { data }
},
template: '<div>{{ data }}</div>'
}
export default {
components: {
ChildComponent
},
extends: MyProvideComponent
}
</script>
在上面的例子中,我们在父组件中定义了一个 provide
,将数据 Hello, World!
以 myData
的键名提供给子组件使用。在子组件中,我们使用 inject
获取父组件提供的数据,并将其绑定到模板中。
需要注意的是,provide
和 inject
并不是响应式的,如果需要在子组件中响应式地使用父组件提供的数据,可以使用 reactive
或 ref
等响应式 API 进行包装。
17.响应式数据的判断
- isRef : 检查一个值是否为一个 ref 对象
- isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
- isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
- isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理