响应式数据

@Reactivity
调试方法
. 简单事件
. setTimeout()
. 开发工具 vue devtools
Why
Vue 会自动检测响应式数据的变化,进而更新 DOM - 数据驱动 Data Driven
普通变量不会触发视图更新
更多响应式原理,请访问 响应式基础 - Reactivity Fundamentals深入响应式系统
ref()
ref():创建基本数据类型、复合数据类型的响应式数据 - creating reactive references to primitive values
ref() 将传入参数的值包装为一个带 .value 属性的 ref 对象 - wraps primitive values in a reactive object. Access the value using .value
ref() 的 .value 属性是响应式 - Triggers re-renders when the value changes
ref() 还可用于 模板引用,用于获取 DOM 元素
Usage
1. 引入包 ref - 下述各例略
import { ref } from 'vue'
2. 声明响应式变量 - 执行函数、传入参数、变量接收
const count = ref(0)
3.1 结构中使用 - 直接使用;Vue 会 自动拆包 获取其 value - automatically unwrapped in templates
<div>{{count}}</div>
3.2 逻辑中使用 - 赋值时需额外指定 value 属性;可以由开发环境的插件自动补齐 value 属性
console.log(count)
console.log(count.value)
安装了 相关插件 的 Vc Code 环境,在创建 ref 时,可以自动导入
控制台输出,查看响应式变量的细节,如 value 属性在哪里
数据监听时,直接使用,无须使用 value 属性
Vs Code 的 Vue Official 扩展默认勾选 Auto Insert: Dot Value;如果没有或使用其它扩展,请勾选
[] 单独使用和同时使用非响应式数据和响应式数据,查看视图的更新情况
<template>
  <div>
    <div>{{ num }}</div>
    <div>{{ age }}</div>
    <button @click="inc">inc</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
let num = 1
const age = ref(12)
const inc = () => {
  num++
  age.value++
}
</script>
reactive()
reactive():只能创建复合数据类型的响应式数据,如对象、数组 - For more complex state
响应式的代理整个对象 - Creates a reactive proxy of the entire object
不用指定 value 属性 - Properties can be accessed directly without .value
reactive() 将深层地转换对象:当访问嵌套对象时,它们也会被 reactive() 包装 - Suitable for complex nested objects
当 ref 的值是一个对象时,ref() 也会在内部调用它 - reactive()
Usage
1. 引入包 reactive - 下述各例略
import { reactive } from 'vue'
2. 声明响应式变量 - 执行函数、传入参数、变量接收
const obj = reactive({
    id: 10,
    name: 'gz'
})
3.1. 结构中使用
<div>{{obj.id}} - {{obj.name}}</div>
3.2. 逻辑中使用 - 直接修改对象的属性以保持响应性 - 单个属性赋值
const done = () => {
    obj.id = 20
}
console.log(obj)
控制台输出,查看响应式变量的细节
[] 分别声明1个简单 ref、1个复杂的 ref 和一个复杂的 reactive,查看其数据结构
const age = ref(12)
const state = reactive({
  id: 1,
  name: 'xh'
})
const obj = ref({
  id: 1,
  name: 'xh'
})
console.log(age, state, obj);
Limitations
使用不当,会丢失数据的响应式 - Breaks Reactivity
更多注意事项,请访问 limitations of reactiveThe Pitfall of Destructuring Props
1. 不能声明简单数据类型 - value cannot be made reactive: 10
const count = reactive(10)
2. 不能重新赋值/不能轻易地“替换”响应式对象
let obj = reactive({
    id: 10,
    name: 'gz'
})

const done = () => {
    obj = {
      id: 20,
      name: 'gl'
    }
}
3. 不能解构 - destructuring props;因为它是一个整体
const { id, name } = obj
Summary & Homework
Summary
经过函数 ref()、reactive() 处理后,普通的数据或对象就变成了响应式
使用 console.log() 查看一个变量是否具有响应式数据:如果带有 Proxy/refImpl,是响应式数据;否则就是普通变量
实际开发中,更多使用 ref();因为可以直接改,且不容易丢失响应式

. 创建简单的响应式变量时,当然只能 ref()

. 如果需要简单的对象,ref()、reactive() 都可以

. 层级比较深的对象,请使用 reactive()

避免数据的响应式丢失
体会将数据声明为常量的优势
ref()、reactive() 都是深层响应,即所有后代级别对象属性都会响应;如果仅仅限制根级对象属性,请使用 shallowref()shallowreactive()
对 shallowref() 而言,它的根属性是 .value
Homework
[] 主题切换/换肤 - 以 阿里字体图标 为例,仅展示图标的切换;具体主题样式由个人自定义
引入 - 请使用自己的账号选择图标并生成在线 CSS 链接
结构 - 动态绑定样式并绑定点击事件
<span 
  @click="changeTheme" 
  :class="['iconfont', darkMode ? 'icon-Sun' : 'icon-Moon-Star']">
</span>
逻辑
import { ref } from 'vue'

const darkMode = ref(false)

const changeTheme = () => {
  darkMode.value = !darkMode.value
}
样式 - 略

[] 优化

使用内联事件完成 - 省略事件处理函数 changeTheme 的定义

使用三元表达式 - 更直观

<span 
  @click="darkMode = !darkMode" 
  class="iconfont" 
  :class="darkMode ? 'icon-Sun' : 'icon-Moon-Star'">
</span>
import { ref } from 'vue'

const darkMode = ref(false)
[] 商品列表页 Goods.vue → goodsItem.vue;数据节点请参考 响应式综合运用 或自行设计