对于 vue3 来说,他的响应性核心 API 是 Proxy ,通过该 API 可以监听到具体某一个属性的 getter 和 setter。
因为 vue3 是通过 Proxy 代理对象去实现的响应性,所以不会出现新增属性丢失响应性的问题。
<template>
<div id="app">
<div v-for="(value, key, index) in obj" :key="index">
<p>{{ key }}-{{ value }}-{{ index }}</p>
</div>
<button @click="onAdd">点击</button>
<button @click="onAddVal">修改值</button>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
obj: {
name: '张三'
}
}
},
methods: {
onAdd() {
this.obj.age = 30
},
onAddVal() {
this.obj.age = 38
}
}
}
</script>
<style></style>
通过 Proxy 代理对象得到的响应式,不能解构,一旦解构就会数去响应性
<template>
<div id="app">
<div v-for="(value, key, index) in obj" :key="index">
<p>{{ key }}-{{ value }}-{{ index }}</p>
</div>
<button @click="onAdd">点击</button>
<button @click="onAddVal">修改值</button>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
obj: {
name: '张三'
}
}
},
methods: {
onAdd() {
this.obj.age = 30
},
onAddVal() {
let { age } = this.obj
age = 38
}
}
}
</script>
<style></style>
语法
-
options ApI:
-
composition API : 组合式 API ,没有 this。改变仅针对于 script
声明响应性对象 obj
-
setup 函数:
-
想要让响应式数据或方法被模板( tempalte )使用,那么方式分为三步:
-
声明响应式数据或方法
-
在 setup 函数中,return 一个对象,对象中包含这个数据或方法,setup直接触发,可以将 setup 理解成 created
-
在 tempalte 中使用
-
-
缺点:当页面数据很多的时候,很看起来很臃肿,不利于观看
-
-
<template>
<div id="app">
<div v-for="(value, key, index) in obj" :key="index">
<p>{{ key }}-{{ value }}-{{ index }}</p>
</div>
<button @click="onAdd">点击</button>
<button @click="onAddVal">修改值</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
// 导入 reactive
// 利用 reactive 生成 porxy 代理对象
// 在 setup 中 return { },对象中包含 生成的 proxy 代理对象
// 这样才可以在 template 中访问
setup() {
// 声明响应性对象
const obj = reactive({
name: '张三'
})
const onAdd = () => {
obj.age = 18
}
const onAddVal = () => {
obj.age = 50
}
return {
obj,
onAdd,
onAddVal
}
}
}
</script>
<style></style>
-
script setup 重要
-
想要让响应式数据或方法被模板( tempalte )使用,那么方式分为两步:
-
声明响应式数据或方法
-
在 tempalte 中使用
-
-
改进之后的代码如下:
<template>
<div id="app">
<div v-for="(value, key, index) in obj" :key="index">
<p>{{ key }}-{{ value }}-{{ index }}</p>
</div>
<button @click="onAdd">点击</button>
</div>
</template>
<script setup>
import { reactive } from 'vue'
const obj = reactive({
name: '张三'
})
const onAdd = () => {
obj.age = 18
}
</script>
<style></style>
vue3中 有两种响应式数据的方式
-
reactive: 因为他是基于 proxy 实现的,所以它只能声明复杂数据类型的响应性
-
ref: 可以声明 任意 数据类型的响应。在script 中使用 ref 声明的数据,必须要通过 .value 访问。
<template>
<div id="app">
<div>{{ name }}</div>
<button @click="onAdd">点击</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const name = ref('张三')
const onAdd = () => {
name.value = '李思'
}
</script>
<style></style>
因为proxy比ref更消耗性能,所以使用ref
vue源码类似于
<script>
// const ref = (value) => {
// const obj = {
// value
// }
// return new Proxy(obj, {
// get(target, key) {
// console.log('get');
// return target[key]
// }
// })
// }
class RefImpl {
constructor(val) {
this.val = val
}
// name.value === name.value()
get value() {
console.log('get');
return this.val
}
set value(val) {
console.log('set');
this.val = val
}
}
const ref = (val) => {
return new RefImpl(val)
}
const name = ref('张三')
console.log(name.value);
name.value = '李四'
console.log(name.value);
</script>