9个关于 Vue3.0 api 方法的总结
ref与toRef、toRefs
ref
函数包装了一个响应式的数据对象。toRef
是将某个对象中的某个值转化为响应式数据,其接收两个参数,第一个参数为 obj
对象;第二个参数为对象中的属性名。toRefs
其作用就是将传入的对象里所有的属性的值都转化为响应式数据对象,该函数支持一个参数,即 obj
对象ref
是对传入数据的拷贝;toRef
是对传入数据的引用ref
的值改变会更新视图;toRef
的值改变不会更新视图
reactive与shallowReactive
reactive
方法是用来创建一个响应式的数据对象,可以是嵌套的对象,会给内部的每一个对像都加入一个Proxy包裹着shallowReactive
代表一个浅层的 reactive
,意思就是监听了第一层属性的值,一旦发生改变,则更新视图。代表着当使用时只给第一层加入了Proxy
<template>
<div>{{state.count}}</div>
</template><script>
import { reactive,shallowReactive }from 'vue'
export default {
name: 'HelloWorld',
props: {
msg: String
},
setup() {
const state= reactive({count:3})
return {
state
}
}
}
</script>复制代码
现在对比reactive和shallowReactive
使用reactive
<template>
<div>{{state.count}}</div>
</template>
<script>
import { reactive,shallowReactive }from 'vue'
export default {
name: 'HelloWorld',
props: {
msg: String
},
setup() {
const obj={
one:{
name:'小明',
two:{
name:'小王',
three:{
name:'小李',
}
}
}
}
const state= reactive(obj)
console.log(state.one)
console.log(state.one.two)
console.log(state.one.two.three)
return {
state
}
}
}
</script>
使用shallowReactive
<template>
<div>{{state.count}}</div>
</template>
<script>
import { reactive,shallowReactive }from 'vue'
export default {
name: 'HelloWorld',
props: {
msg: String
},
setup() {
const obj={
one:{
name:'小明',
two:{
name:'小王',
three:{
name:'小李',
}
}
}
}
const state= shallowReactive(obj)
console.log(state)
console.log(state.one)
console.log(state.one.two)
console.log(state.one.two.three)
return {
state
}
}
}
</script>
运行结果如下:
3.toRaw和markRaw
toRaw
方法是用于获取 ref
或 reactive
对象的原始数据的;
示例如下:
<script>
import {reactive, toRaw} from 'vue'
export default {
setup() {
const obj = {
name: '哈哈哈哈哈哈哈',
age: 35
}
const state = reactive(obj)
const raw = toRaw(state)
console.log(state)
console.log(raw)
console.log(obj === raw) // true
}
}
</script>
结果如下:
markRaw
方法可以将原始数据标记为非响应式的,即使用 ref
或 reactive
将其包装,仍无法实现数据响应式,其接收一个参数,即原始数据,并返回被标记后的数据。示例如下:
<script>
import {reactive, toRaw,markRaw} from 'vue'
export default {
setup() {
const obj = {
name: '哈哈哈哈哈哈哈',
age: 35
}
markRaw(obj)
const state = reactive(obj)
console.log(obj)
console.log(state)
}
}
</script>
结果:
4.useRoute和useRouter
<template>
<div>
<router-link to="/home">Home</router-link>
<router-link to='/test'>Test</router-link>
</div>
<router-view></router-view>
</template>
<script>
import { onMounted } from "vue";
import { useRoute, useRouter } from "vue-router";
export default {
setup(props, context) {
onMounted(() => {
console.log(route);
console.log(router);
});
const route = useRoute();
const router = useRouter();
return {};
},
};
</script>
5.watch和watchEffect
watch
和watchEffect
都是用来监视某项数据变化从而执行指定的操作的,但是他们之间在用法上还是有区别的:
watch( source, cb, [options] )
source:可以是表达式或函数,用于指定监听的依赖对象
cb:依赖对象变化后执行的回调函数
options:可参数,可以配置的属性有 immediate(立即触发回调函数)、deep(深度监听)
当ref时
<template>
<div>
<router-link to="/home">Home</router-link>
<router-link to='/test'>Test</router-link>
</div>
<router-view></router-view>
</template>
<script>
import { ref,watch} from "vue";
export default {
setup() {
const state = ref(0)
watch(state, (newValue, oldValue) => {
console.log(`原值为${oldValue}`)
console.log(`新值为${newValue}`)
/* 1秒后打印结果:
原值为0
新值为1
*/
})
// 1秒后将state值+1
setTimeout(() => {
state.value ++
}, 1000)
},
};
</script>
当reactive时
<script>
import {reactive, watch} from 'vue'
export default {
setup() {
const state = reactive({count: 0})
watch(() => state.count, (newValue, oldValue) => {
console.log(`原值为${oldValue}`)
console.log(`新值为${newValue}`)
/* 1秒后打印结果:
原值为0
新值为1
*/
})
// 1秒后将state.count的值+1
setTimeout(() => {
state.count ++
}, 1000)
}
}
</script>
结果如下:
监听多个值:
<script>
import {reactive, watch} from 'vue'
export default {
setup() {
const state = reactive({ count: 0, name: 'zs' })
watch(
[() => state.count, () => state.name],
([newCount, newName], [oldvCount, oldName]) => {
console.log(oldvCount) // 旧的 count 值
console.log(newCount) // 新的 count 值
console.log(oldName) // 旧的 name 值
console.log(newName) // 新的 name 值
}
)
setTimeout(() => {
state.count ++
state.name = 'ls'
}, 1000)
}
}
</script>
结果如下:
watchEffect
,它与 watch
的区别主要有以下几点:
不需要手动传入依赖
每次初始化时会执行一次回调函数来自动获取依赖
无法获取到原值,只能得到变化后的值
<template>
<div>
<router-link to="/home">Home</router-link>
<router-link to='/test'>Test</router-link>
</div>
<router-view></router-view>
</template>
<script>
import {reactive, watchEffect} from 'vue'
export default {
setup() {
const state = reactive({ count: 0, name: 'zs' })
watchEffect(() => {
console.log(state.count)
console.log(state.name)
/* 初始化时打印:
0
zs
1秒后打印:
1
ls
*/
})
setTimeout(() => {
state.count ++
state.name = 'ls'
}, 1000)
}
}
</script>
6.computed 返回一个 ref 对象。
<script>
import {computed,ref} from 'vue'
export default {
setup() {
const x=computed(()=>{
return 'jjjjj'
})
console.log(x.value)
const count = ref(1)
const plusOne = computed({
get: () => {
console.log('---------Get',count.value)
return count.value + 1
},
set: val => {
console.log('---------Set',val)
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value)
}
}
</script>
结果如下:
7.provide和inject
provide :向子组件以及子孙组件传递数据。接收两个参数,第一个参数是
key
,即数据的名称;第二个参数为value
,即数据的值inject :接收父组件或祖先组件传递过来的数据。接收一个参数
key
,即父组件或祖先组件传递的数据名称
//a.vue
<script>
import {provide} from 'vue'
export default {
setup() {
const obj= {
name: '哈哈哈哈哈哈',
age: 22
}
// 向子组件以及子孙组件传递名为info的数据
provide('info', obj)
}
}
</script>
//b.vue
<script>
import {inject} from 'vue'
export default {
setup() {
// 接收a.vue传递过来的数据
inject('info') // {name: '哈哈哈哈哈哈', age: 22}
}
}
</script>
//c.vue
<script>
import {inject} from 'vue'
export default {
setup() {
// 接收a.vue传递过来的数据
inject('info') // {name: '哈哈哈哈哈哈', age: 22}
}
}
</script>
8.vue2与vue3生命周期对比
<template>
<div id="app"></div>
</template>
<script>
// 1. 从 vue 中引入 多个生命周期函数
import {onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, unMounted} from 'vue'
export default {
name: 'App',
setup() {
onBeforeMount(() => {
// 在挂载前执行某些代码
})
onMounted(() => { // 在挂载后执行某些代码
})
onBeforeUpdate(() => {
// 在更新前前执行某些代码
})
onUpdated(() => {
// 在更新后执行某些代码
})
onBeforeUnmount(() => {
// 在组件销毁前执行某些代码
})
unMounted(() => {
// 在组件销毁后执行某些代码
})
return {}
}
}
</script>
9.setup(props,context)
(1)props:
组件传递的参数,是响应式的,可以通过使用watchEffect或watch进行观测和响应
不要直接使用解构赋值,会使得参数失去响应性
若要解构:const { title } = toRefs(props)
(2)context:
上下文对象 对应之前vue2的
context.attrs this.$attrs 组件标签上的属性(非响应式对象)
context.slots this.$slots 插槽(非响应式对象)
context.emit this.$emit 标签上自定义的触发事件(方法)
context.emit('自定义事件名',参数)
无法访问:因为是在组件创建实例之前指向
data
computed
methods
解构:
context是一个普通的JavaScript对象,也就是说,它不是响应式的,可以直接解构
attrs和slots是内部组件实例上相应值的代理。这样可以确保它们即使在更新后也始终会显示最新值,以便我们可以对它们进行结构分解,而不必担心访问老的引用:
但避免对内部的属性进行解构,并始终以attrs.x或slots.x的方式使用
(3)this指向问题:
因为setup()是在解析其它组件选项之前被调用的,所以setup()内部的this的行为与其它选项中的this完全不同
(4)更好的模块化问题:
可以从其他文件引入函数等,然后在setup中执行,其他文件中可以使用v3的组合式api(需先导入),但必须在setup中调用
(5)return返回值方式:
返回的内容可以在命令式api中this.x访问到
方式一:
return{
返回的属性和方法,在setup外部能够使用,返回的普通属性不是响应式的,即改变不会更新视图
}
方式二:
return () => h('div', ["哇咔咔"]) 还可以直接返回一个渲染函数,将替换模板中的内容
方式三:注意此时组件已经变成了一个异步组件,可使用Suspense悬挂展示
可以返回一个成功状态的Promise对象,会将成功态的[[PromiseResult]]结果作为返回值
return new Promise((resolve,reject)=>{ 也可返回一个Promise对象,使得组件为异步的
...
resolve({
数据
})
})
return await ...
转自:https://juejin.cn/post/6989217956483825695