Vue3中的data数据
# Vue3中的data数据
在vue2中,我们使用data定义响应式数据。而在 Vue3 中,ref
和 reactive
是两种定义响应式数据的主要方式。它们分别用于处理基本类型数据和对象类型数据,使数据在 Vue 组件中具有响应性。下面将详细介绍它们的基本语法和使用方法。
# 1. 响应式和非响应式数据
# 非响应式数据
非响应式数据在 Vue3 中通常是通过普通的变量定义的。它们的值不会自动更新到模板中,也不会触发视图的重新渲染。
示例代码:
// 定义非响应式数据
let name = '张三'; // 创建一个普通的字符串变量
console.log(name); // 访问数据,输出:张三
name = '李四'; // 修改数据
console.log(name); // 输出:李四
2
3
4
5
6
7
在模板中使用非响应式数据:
<template>
<div>
<p>非响应式姓名:{{ name }}</p>
<button @click="changeName">修改名字</button>
</div>
</template>
<script setup>
let name = '张三'; // 非响应式数据
function changeName() {
name = '李四'; // 修改数据,但不会引起视图更新
console.log(name); // 输出:李四
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
解释:
- 由于
name
是普通变量,模板中的内容不会因为它的变化而自动更新。即使你在changeName
函数中修改了name
,模板中的显示仍然是最初的值。
# 响应式数据
响应式数据通过 ref
或 reactive
定义。当数据变化时,Vue3 会自动追踪这些变化,并更新视图。
示例代码:
import { ref } from 'vue';
// 定义响应式数据
let name = ref('张三'); // 创建一个响应式字符串
console.log(name.value); // 访问数据,输出:张三
name.value = '李四'; // 修改数据
console.log(name.value); // 输出:李四
2
3
4
5
6
7
8
9
在模板中使用响应式数据:
<template>
<div>
<p>响应式姓名:{{ name }}</p>
<button @click="changeName">修改名字</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
let name = ref('张三'); // 响应式数据
function changeName() {
name.value = '李四'; // 修改数据,会引起视图更新
console.log(name.value); // 输出:李四
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
解释:
- 由于
name
是通过ref
定义的响应式数据,模板中的内容会随着name.value
的变化而自动更新。每次调用changeName
函数时,视图都会相应地更新显示新的值。
对比总结
- 非响应式数据:定义简单,但无法自动更新视图。如果需要更新视图,必须手动触发。
- 响应式数据:Vue3 自动追踪数据变化,并在数据变化时自动更新视图。推荐在需要数据绑定和视图更新的场景下使用。
# 2. ref 定义基本类型
ref
是 Vue3 中用于创建基本类型数据的响应式变量的函数。它允许基本数据类型(如字符串、数字、布尔值)在 Vue 组件中具有响应性。
# 基本语法
import { ref } from 'vue';
// 使用 ref 定义一个响应式变量
let variableName = ref(initialValue);
2
3
4
variableName
:定义的变量名。initialValue
:变量的初始值,可以是字符串、数字、布尔值等基本类型。
ref
函数返回一个 RefImpl
的实例对象,这个对象的 value
属性是响应式的,数据的访问和更新都需要通过 value
属性。
# 使用方法
在 JavaScript 中:
import { ref } from 'vue'; // 定义响应式数据 let name = ref('张三'); // 创建一个响应式字符串 console.log(name.value); // 访问数据,输出:张三 name.value = '李四'; // 修改数据 console.log(name.value); // 输出:李四
1
2
3
4
5
6
7
8在模板中:
在模板中,可以直接使用
ref
变量的名称,无需.value
访问其值。<template> <div>{{ name }}</div> <!-- 直接使用 ref 变量名,不需要 .value --> </template> <script setup lang="ts"> import { ref } from 'vue'; // 定义响应式数据 let name = ref('张三'); </script>
1
2
3
4
5
6
7
8
9
10
完整示例
<template>
<div class="person">
<h2>姓名:{{ name }}</h2>
<button @click="changeName">修改名字</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
// 定义一个响应式变量
let name = ref('张三');
function changeName() {
name.value = '李四'; // 修改响应式数据
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 3. reactive 定义对象类型
reactive
是 Vue3 中用于将对象类型的数据转变为响应式数据的函数。它使得复杂类型(如对象、数组)在 Vue 组件中具有响应性,自动追踪嵌套属性的变化。
# 基本语法
import { reactive } from 'vue';
// 使用 reactive 定义一个响应式对象
let reactiveObject = reactive(sourceObject);
2
3
4
reactiveObject
:定义的响应式对象名。sourceObject
:源对象,可以是嵌套的复杂对象。
reactive
函数返回一个 Proxy
实例对象,这个对象的所有属性都是响应式的。可以直接访问和修改对象的属性,而无需使用 .value
。
# 使用方法
在 JavaScript 中:
import { reactive } from 'vue'; // 定义一个响应式对象 let car = reactive({ brand: '奔驰', price: 100 }); console.log(car.brand); // 访问数据,输出:奔驰 car.price += 10; // 修改数据 console.log(car.price); // 输出:110
1
2
3
4
5
6
7
8在模板中:
在模板中,可以直接使用
reactive
对象的属性进行访问。<template> <div>{{ car.brand }} - {{ car.price }}万</div> <!-- 直接使用 reactive 对象属性 --> </template> <script setup lang="ts"> import { reactive } from 'vue'; // 定义一个响应式对象 let car = reactive({ brand: '奔驰', price: 100 }); </script>
1
2
3
4
5
6
7
8
9
10
完整示例
<template>
<div class="person">
<h2>汽车信息:一台{{ car.brand }}汽车,价值{{ car.price }}万</h2>
<button @click="changeCarPrice">修改汽车价格</button>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
// 定义一个响应式对象
let car = reactive({ brand: '奔驰', price: 100 });
function changeCarPrice() {
car.price += 10; // 修改响应式对象属性
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 4. ref 定义对象类型
ref
可以接收基本类型和对象类型的数据。如果 ref
接收的是对象类型数据,它会将其转换为响应式对象,这类似于 reactive
的作用。它允许通过 .value
来访问和修改数据。
# 基本语法
import { ref } from 'vue';
// 使用 ref 定义一个响应式对象
let reactiveVariable = ref(initialObject);
2
3
4
reactiveVariable
:定义的变量名。initialObject
:初始对象值,可以是复杂对象。
ref
函数返回一个 RefImpl
的实例对象,对于对象类型数据,这个对象的 value
属性将是一个响应式对象。
# 使用方法
在 JavaScript 中:
import { ref } from 'vue'; // 定义一个响应式对象 let car = ref({ brand: '奔驰', price: 100 }); console.log(car.value.brand); // 访问数据,输出:奔驰 car.value.price += 10; // 修改数据 console.log(car.value.price); // 输出:110
1
2
3
4
5
6
7
8在模板中:
在模板中,使用
ref
定义的对象类型数据,可以直接使用属性名,无需.value
。<template> <div>{{ car.value.brand }} - {{ car.value.price }}万</div> <!-- 直接使用 ref 对象属性 --> </template> <script setup lang="ts"> import { ref } from 'vue'; // 定义一个响应式对象 let car = ref({ brand: '奔驰', price: 100 }); </script>
1
2
3
4
5
6
7
8
9
10
完整示例
<template>
<div class="person">
<h2>汽车信息:一台{{ car.value.brand }}汽车,价值{{ car.value.price }}万</h2>
<button @click="changeCarPrice">修改汽车价格</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
// 定义一个响应式对象
let car = ref({ brand: '奔驰', price: 100 });
function changeCarPrice() {
car.value.price += 10; // 修改响应式对象属性
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 5. 定义数据时不传递初始值
在 Vue3 中,当你使用 ref
和 reactive
来定义响应式数据时,如果什么都不写,即没有传递初始值,这会有以下含义:
# ref() 定义时没有传递初始值
import { ref } from 'vue';
let myRef = ref(); // 不传递初始值
2
3
含义:
- 当你使用
ref()
而不传递任何初始值时,ref
会创建一个undefined
的响应式变量。 - 这意味着
myRef.value
初始值为undefined
,你可以在后续代码中给它赋值。
示例:
import { ref } from 'vue';
let myRef = ref(); // 定义时未赋值,初始值为 undefined
console.log(myRef.value); // 输出:undefined
// 在后续代码中给它赋值
myRef.value = 'Hello, Vue 3!';
console.log(myRef.value); // 输出:Hello, Vue 3!
2
3
4
5
6
7
8
9
在模板中:
<template>
<div>{{ myRef }}</div> <!-- 输出:Hello, Vue 3! -->
</template>
<script setup>
import { ref } from 'vue';
let myRef = ref(); // 初始值为 undefined
myRef.value = 'Hello, Vue 3!'; // 后续赋值
</script>
2
3
4
5
6
7
8
9
10
11
# reactive({}) 定义时没传递初始值
import { reactive } from 'vue';
let myReactiveObject = reactive({}); // 定义一个空对象
2
3
含义:
- 当你使用
reactive({})
时,并不传递任何属性,reactive
将创建一个空的响应式对象。 - 这个对象可以在后续代码中动态添加属性,这些属性也会自动成为响应式的。
示例:
import { reactive } from 'vue';
let myReactiveObject = reactive({}); // 定义一个空对象
console.log(myReactiveObject); // 输出:{}
myReactiveObject.name = 'Vue 3'; // 动态添加属性
myReactiveObject.version = 3;
console.log(myReactiveObject.name); // 输出:Vue 3
console.log(myReactiveObject.version); // 输出:3
2
3
4
5
6
7
8
9
10
11
在模板中:
<template>
<div>
<p>Name: {{ myReactiveObject.name }}</p>
<p>Version: {{ myReactiveObject.version }}</p>
</div>
</template>
<script setup>
import { reactive } from 'vue';
let myReactiveObject = reactive({}); // 定义一个空对象
myReactiveObject.name = 'Vue 3'; // 动态添加属性
myReactiveObject.version = 3;
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 总结
ref()
:如果不传递初始值,则创建一个值为undefined
的响应式变量,可以在后续赋值。reactive({})
:如果传递一个空对象{}
,则创建一个空的响应式对象,可以在后续动态添加属性。
这两种方式在 Vue3 中的使用场景各有不同,具体选择哪种方式取决于你需要定义的响应式数据的类型和初始化方式。
# 6. ref 对比 reactive
# 宏观角度的选择
ref
用于定义: 基本类型数据、对象类型数据。reactive
用于定义: 对象类型数据。
# 两者区别
1. 对
ref
创建的变量进行操作必须使用.value
(可以在 VS Code 上安装volar
插件自动添加.value
)。2.
reactive
重新分配一个新对象,会失去响应性:import { reactive } from 'vue'; let car = reactive({ brand: '奔驰', price: 100 }); car = { brand: '奥迪', price: 200 }; // 响应性丢失
1
2
3
4如果直接重新赋值整个对象,响应性会丢失。可以使用
Object.assign
方法进行整体替换,保持响应性:import { reactive } from 'vue'; // 定义一个响应式对象 let car = reactive({ brand: '奔驰', price: 100 }); // 使用 Object.assign 进行整体替换 Object.assign(car, { brand: '奥拓', price: 1 }); console.log(car.brand); // 输出:奥拓 console.log(car.price); // 输出:1
1
2
3
4
5
6
7
8
9
10Object.assign(target, source)
target
:目标对象。source
:源对象。
# 使用原则
1. 需要基本类型的响应式数据:必须使用
ref
。import { ref } from 'vue'; let age = ref(25); age.value += 1; // 修改数据 console.log(age.value); // 输出:26
1
2
3
4
52. 需要响应式对象,层级不深:
ref
和reactive
都可以使用。import { ref, reactive } from 'vue'; let userRef = ref({ name: '张三', age: 18 }); let userReactive = reactive({ name: '张三', age: 18 }); userRef.value.age += 1; // 修改数据 console.log(userRef.value.age); // 输出:19 userReactive.age += 1; // 修改数据 console.log(userReactive.age); // 输出:19
1
2
3
4
5
6
7
8
9
10
113. 需要响应式对象,且层级较深:推荐使用
reactive
。import { reactive } from 'vue'; let nestedObject = reactive({ a: { b: { c: { d: 666 } } } }); nestedObject.a.b.c.d = 999; // 修改数据 console.log(nestedObject.a.b.c.d); // 输出:999
1
2
3
4
5
6
7
8
9
10
11
12
13
14
为什么推荐在层级较深的对象中使用 reactive?
- 深层次的响应性管理:
reactive
能够自动管理对象的深层次响应性。当你有一个嵌套层级较深的对象时,reactive
会自动追踪每个嵌套属性的变化,并确保这些变化是响应式的。这在大型复杂对象中尤其有用。 - 便捷性和直观性:使用
reactive
定义对象时,开发者不需要频繁地使用.value
来访问或修改对象的属性。这使得代码更简洁,操作更直观。 - 避免误用:如果你使用
ref
来创建一个层级较深的对象,那么在处理嵌套属性时,可能需要频繁使用.value
,这在代码中容易被忽略或误用,导致响应性失效。而reactive
则能避免这些问题。