程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Vue2

  • Vue3

    • 初识Vue3
    • 组合式API
    • Vue3中的data数据
      • 1. 响应式和非响应式数据
        • 非响应式数据
        • 响应式数据
      • 2. ref 定义基本类型
        • 基本语法
        • 使用方法
      • 3. reactive 定义对象类型
        • 基本语法
        • 使用方法
      • 4. ref 定义对象类型
        • 基本语法
        • 使用方法
      • 5. 定义数据时不传递初始值
        • ref() 定义时没有传递初始值
        • reactive({}) 定义时没传递初始值
        • 总结
      • 6. ref 对比 reactive
        • 宏观角度的选择
        • 两者区别
        • 使用原则
    • vue3 的 script标签
    • setup函数中执行顺序
    • toRefs() 与 toRef()
    • computed()
    • Vue3弱化this
    • watch() 和 watchEffec()
    • define函数用法
    • defineExpose() 和 ref 属性
    • vue.config.js
    • 生命周期
    • Vue3全局API调用
    • 自定义 Hook
    • 传递数据(props)
    • 路由
    • pinia
    • 组件通信
    • getCurrentInstance() 和 nextTick()
    • Vue3 新组件
  • vue3 + TS 项目集成

  • Vue全家桶
  • Vue3
scholar
2024-08-05
目录

Vue3中的data数据

# Vue3中的data数据

在vue2中,我们使用data定义响应式数据。而在 Vue3 中,ref 和 reactive 是两种定义响应式数据的主要方式。它们分别用于处理基本类型数据和对象类型数据,使数据在 Vue 组件中具有响应性。下面将详细介绍它们的基本语法和使用方法。

# 1. 响应式和非响应式数据

# 非响应式数据

非响应式数据在 Vue3 中通常是通过普通的变量定义的。它们的值不会自动更新到模板中,也不会触发视图的重新渲染。

示例代码:

// 定义非响应式数据
let name = '张三'; // 创建一个普通的字符串变量

console.log(name); // 访问数据,输出:张三

name = '李四'; // 修改数据
console.log(name); // 输出:李四
1
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>
1
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); // 输出:李四
1
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>
1
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);
1
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>
1
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);
1
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>
1
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);
1
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>
1
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(); // 不传递初始值
1
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!
1
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>
1
2
3
4
5
6
7
8
9
10
11

# reactive({}) 定义时没传递初始值

import { reactive } from 'vue';

let myReactiveObject = reactive({}); // 定义一个空对象
1
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
1
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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 总结

  • ref():如果不传递初始值,则创建一个值为 undefined 的响应式变量,可以在后续赋值。
  • reactive({}):如果传递一个空对象 {},则创建一个空的响应式对象,可以在后续动态添加属性。

这两种方式在 Vue3 中的使用场景各有不同,具体选择哪种方式取决于你需要定义的响应式数据的类型和初始化方式。

# 6. ref 对比 reactive

# 宏观角度的选择

  1. ref 用于定义: 基本类型数据、对象类型数据。
  2. reactive 用于定义: 对象类型数据。

# 两者区别

  • 1. 对 ref 创建的变量进行操作必须使用 .value(可以在 VS Code 上安装 volar 插件自动添加 .value)。

    image-20240901090050436

  • 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
      10

      Object.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
    5
  • 2. 需要响应式对象,层级不深: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
    11
  • 3. 需要响应式对象,且层级较深:推荐使用 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 则能避免这些问题。
编辑此页 (opens new window)
上次更新: 2025/02/01, 02:18:15
组合式API
vue3 的 script标签

← 组合式API vue3 的 script标签→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式