Vue3的响应式
Vue2的响应式是通过Object.defindeProperty的访问器属性来调用get和set方法,并且会通知观察者Wacher重新render组件. 这种方法对于深层的数据是不太友好的,不能直接监听对象和数组的变化.
Vue3中的响应式则是通过 Proxy 替代Object.defineProperty,这样就可以直接监听对象和数组的变化,并且有多达13种拦截方法。 实现深度观测的方法: 判断当前的Reflect.get的返回值是否为Object,如果是则再通过reactive方法做代理. 核心: (1)通过Proxy(代理):拦截对data任意属性的任意操作. (2)通过Reflect(反射):动态对被代理对象的相应属性进行特定操作
<script type="text/javascript">
const user = {
name: 'zmj',
age: 20,
wife: {
name: 'bb',
age: 19
}
}
const proxyUser = new Proxy(user, {
get(target, prop) {
console.log('get调用了');
return Reflect.get(target, prop)
},
set(target, prop, val) {
console.log('set调用了');
return Reflect.set(target, prop, val)
},
deleteProperty(target, prop) {
console.log('delete调用了');
return Reflect.deleteProperty(target, prop);
}
})
console.log(proxyUser.name);
proxyUser.name = 'lqb'
console.log(user);
proxyUser.gender = '男',
console.log(user);
delete proxyUser.name;
console.log(user);
proxyUser.wife.name = 'zzz'
console.log(user);
</script>
常用的Composition API
setup():
执行时机: 在beforeCreate之前执行一次,并且this为undefined. 参数: (1)props:值为对象, 包含组件外部传递过来,且组件内部声明接受了的属性. (2)context: 上下文对象: attrs:值为对象,包含组件外部传递进来但是没有在props配置中声明的属性,即相当于this.
a
t
t
r
s
.
s
l
o
t
s
:
收
到
的
插
槽
的
内
容
,
相
当
于
t
h
i
s
.
attrs. slots:收到的插槽的内容,相当于this.
attrs.slots:收到的插槽的内容,相当于this.slots. emit:分发自定义事件的函数,相当与this.$emit
reactive():
作用: 定义一个对象类型的响应式数据(基本类型要用ref)。 reactive定义的响应式数据是"深层次的",不管数据有多深都能监视得到。 基于Proxy实现,通过代理对象操作源对象内部数据进行操作。 获取reactive代理数据值时,不需要 .value 但是使用ref代理时,取得值就需要. value
<script lang="ts">
import { reactive } from "@vue/reactivity";
import { defineComponent } from "@vue/runtime-core";
interface IPersion {
name: string;
age: number;
job: {
type: string,
salary: string,
a: any
};
hobby: any;
}
export default defineComponent({
setup() {
const persion: IPersion = reactive({
name: "李四",
age: 19,
job: {
type: "前端工程师",
salary: "20K",
a: {
b: {
c: 666,
},
},
},
hobby: ["抽烟", "喝酒", "烫头"],
});
function changeInfo() {
persion.name = "李四";
persion.age = 48;
persion.job.type = "JAVA工程师";
persion.job.salary = "60K";
persion.job.a.b.c = 999;
persion.hobby[0] = "学习";
}
return {
persion,
changeInfo,
};
},
});
</script>
computed():
vue3中的计算属性是可以直接在setup中使用的,只需要从vue中引入computed即可
<script lang="ts">
import { reactive, computed} from "vue";
import { defineComponent } from "@vue/runtime-core";
export default defineComponent({
setup() {
let person = reactive({
firstName: '张',
lastName: '三',
})
person.fullName = computed(() => {
return person.firstName + person.lastName
})
return {
person
};
},
});
</script>
计算属性里的值是只读属性,不可以修改.如果要修改需要考虑读和写的完整写法
setup() {
let person = reactive({
firstName: '张',
lastName: '三',
})
person.fullName = computed({
get() {
return person.firstName + '-' +person.lastName
},
set(value) {
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
return {
person
};
},
watch():
watch可以在setup中多次调用。并且监视的是用 ref 或者 reactive 代理的数据类型。 watch监视的是一个属性而不是一个值 所以用ref定义的基本数据被监视时不需要 .value watch接受三个参数: 第一个:监视的对象 第二个:数据变化后需要做的操作,也就是一个回调函数,将新的值与旧的值作为参数传入这个回调函数中。 第三个:传入一个对象,里面是各种配置项
import { ref, watch} from "vue";
export default ({
setup() {
let sum = ref(0)
watch(sum, (newValue, oldValue) => {
console.log('sum变了', newValue, oldValue);
}, {immediate:true, deep: true})
return {
sum
};
},
});
如果是监视reactive所定义的一个响应式数据的全部属性时,则得不到oldValue,并且会强制开启深度监视,无法关闭。
import { reactive,ref, watch} from "vue";
export default ({
setup() {
const person = reactive({
name: 'zmj',
age: 18,
job: {
j1: {
salary: 20
}
}
})
watch(person, (newValue, oldValue) => {
console.log('person改变了', newValue, oldValue);
})
return {
person
};
},
});
但是如果是监视reactive所定义的一个响应式数据的某个属性时,就可以得到oldValue,但是第一个参数需要是一个函数并且返回监视的那个属性
<script>
import { reactive,ref, watch} from "vue";
export default ({
setup() {
const person = reactive({
name: 'zmj',
age: 18,
job: {
j1: {
salary: 20
}
}
})
watch(() => person.age, (newValue, oldValue) => {
console.log('age改变了', newValue, oldValue);
})
return {
person
};
},
});
</script>
watchEffect():
用法:不需要指明监视哪个属性,回调函数中用到哪个属性,就监视哪个属性。不用写返回值。
watchEffect(() => {
const x1 = person.age
console.log('watchEffect执行了');
})
toRef()/toRefs():
作用:创建一个ref对象,其value值指向另一个对象中的某个属性。 应用:要将响应式对象中的某个属性单独提供给外部使用时。 语法:
let person = reactive({
name: 'zzz',
age:'18'
})
const name = toRef(person, 'name')
toRefs():批量创建多个ref对象。 语法:
let person = reactive({
name: 'zzz',
age:'18'
})
const x= toRefs(person)
shallowReavtive():
作用:只处理对象最外层属性的响应式。
shallowRef():
作用:只处理基本数据类型的响应式,不进行对象的响应式处理。
toRaw():
作用:将一个由reactive生成的响应式对象转为普通对象。 应用:用于读出响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面的更新。
markRaw():
作用:标记一个对象,使其永远不会再成为响应式对象。 应用:一些第三方类库的值不应该被设置为响应式。当渲染某些不可变数据源的列表时,跳过响应式转换可提高性能。
|