前言
先介绍本文的主角:
ref
:- 用于包裹基本类型值或对象以创建响应式引用。当你需要对单个值(如数字、字符串、布尔值等)进行响应式处理时,可以使用
ref
。访问.value
属性来获取或设置实际的值。
- 用于包裹基本类型值或对象以创建响应式引用。当你需要对单个值(如数字、字符串、布尔值等)进行响应式处理时,可以使用
reactive
:- 用于使一个普通对象的所有属性变为响应式的。适用于处理复杂的数据结构,如对象和数组。使用
reactive
创建的代理对象可以直接通过属性访问和修改,而不需要.value
。
- 用于使一个普通对象的所有属性变为响应式的。适用于处理复杂的数据结构,如对象和数组。使用
- 计算属性(
computed
) :- 虽然计算属性本身不是响应式数据的创建方式,但它依赖于响应式数据并在依赖项变化时自动重新计算,因此是响应式系统的一部分。
- 侦听器(
watch
) :- 同样,
watch
也不是直接创建响应式数据,但它用于监听响应式数据的变化并执行相应的操作,是响应式系统应用的一个方面。
- 同样,
正文
先给出页面要求:文章源自灵鲨社区-https://www.0s52.com/bcjc/vue-jsjc/16495.html
1、要求有三个部分:书籍推荐、购物车、待办事项文章源自灵鲨社区-https://www.0s52.com/bcjc/vue-jsjc/16495.html
- 书籍推荐:用户可以根据自己的预算点击增加和减少按钮来改变预算,再根据预算推荐给用户适合的书。
- 购物车:可以增加、减少或者删除购买的书籍,并给出需要购买的书籍的总价格。
- 待办事项:可以供用户输入或删除自己需要做的事项。
主体部分
实现一个底部导航栏的功能。导航栏有三个选项,分别是“书籍推荐”、“购物车”和“待办事项”。点击不同的选项会切换不同的内容区域。文章源自灵鲨社区-https://www.0s52.com/bcjc/vue-jsjc/16495.html
文章源自灵鲨社区-https://www.0s52.com/bcjc/vue-jsjc/16495.html
为了实现点击不同部分在不刷新页面的情况下,很容易会想到AJAX异步交互,但这里不需要那么高级,只需要将对象响应式,每点击不同对象自动更新内容文章源自灵鲨社区-https://www.0s52.com/bcjc/vue-jsjc/16495.html
reactive更新页面内容文章源自灵鲨社区-https://www.0s52.com/bcjc/vue-jsjc/16495.html
当你用reactive
处理一个普通对象时,它会返回一个新的代理对象,这个代理对象的属性是有响应式的。这意味着,当这些属性的值发生变化时,依赖于这些值的计算属性或视图将会自动更新。文章源自灵鲨社区-https://www.0s52.com/bcjc/vue-jsjc/16495.html
js
<template>
<nav>
<span @click="changeTab(1)">书籍推荐</span>|
<span @click="changeTab(2)">购物车</span>|
<span @click="changeTab(3)">待办事项</span>
</nav>
<Base v-if="state.index === 1" />
<shopping v-if="state.index === 2" />
<todo v-if="state.index === 3" />
</template>
<script setup>
import Base from './components/base.vue'
import shopping from './components/shopping.vue'
import todo from './components/todo.vue'
import { reactive } from 'vue'
let state = reactive({
index: 1
})
const changeTab = (i) => {
console.log(i)
state.index = i
}
</script>
<style lang="css">
*{
text-align: center;
}
</style>
- 在模板部分,使用
<nav>
标签创建了导航栏容器,其中包含三个<span>
标签作为导航选项。通过@click
事件绑定changeTab
函数来实现选项的点击切换。根据state.index
的值,使用上一篇文章介绍的v-if
指令动态渲染不同的组件内容。 - 在脚本部分,导入了三个组件文件
Base
、shopping
和todo
,以及Vue的reactive
函数。使用reactive
创建了一个响应式对象state
,其初始值为{ index: 1 }
。定义了一个changeTab
函数,用于接收点击事件的参数i
,并通过设置state.index
的值来切换选项卡。
书籍推荐
文章源自灵鲨社区-https://www.0s52.com/bcjc/vue-jsjc/16495.html
ref实现
ref
用于包裹基本类型值或对象以创建响应式引用。当你需要对单个值(如数字、字符串、布尔值等)进行响应式处理时,可以使用ref
。访问.value
属性来获取或设置实际的值。文章源自灵鲨社区-https://www.0s52.com/bcjc/vue-jsjc/16495.html
js
<template>
<div>
<h2>{{ temp }}</h2>
<h5>{{ sugget }}</h5>
<button @click="add">+5</button>
<button @click="minus">-5</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
let temp = ref(20)
let sugget = ref('计算机组成原理')
const add = () => {
temp.value += 5
if (temp.value >= 30) {
sugget.value = '操作系统'
}
else if(temp.value >= 20) {
sugget.value = '计算机组成原理'
}
else if(temp.value >= 10) {
sugget.value = '形势与政策'
}
else{
sugget.value = '草稿本'
}
}
const minus = () => {
temp.value -= 5
if (temp.value >= 30) {
sugget.value = '操作系统'
}
else if(temp.value >= 20) {
sugget.value = '计算机组成原理'
}
else if(temp.value >= 10) {
sugget.value = '形势与政策'
}
else{
sugget.value = '草稿本'
}
}
<h2>{{ temp }}</h2>
:显示由temp
变量管理的温度值,初始值为20。<h5>{{ sugget }}</h5>
:显示建议或提示信息,初始值为“计算机组成原理”。<button @click="add">+5</button>
:点击按钮时调用add
方法,使预算增加5。<button @click="minus">-5</button>
:点击按钮时调用minus
方法,使预算减少5。
let temp = ref(20)
:声明了一个响应式变量temp
,初始值为20。ref
用于创建可变的响应式引用,当temp
的值发生变化时,绑定到它的模板部分会自动更新。let sugget = ref('计算机组成原理')
:同样使用ref
创建了一个响应式字符串变量sugget
,初始值为“计算机组成原理”- 声明两个函数
add
和minus
,它们分别用于增加和减少temp
变量的值,并根据temp
的值来更新sugget
的建议文本。
侦听器(watch)实现
watch
不是直接创建响应式数据,但它用于监听响应式数据的变化并执行相应的操作,是响应式系统应用的一个方面。文章源自灵鲨社区-https://www.0s52.com/bcjc/vue-jsjc/16495.html
js
<template>
<div>
<h2>{{ temp }}</h2>
<h5>{{ sugget }}</h5>
<button @click="add">+5</button>
<button @click="minus">-5</button>
</div>
</template>
<script setup>
import { ref,watch } from 'vue'
let temp = ref(20)
let sugget = ref('计算机组成原理')
const add = () => {
temp.value += 5
}
const minus = () => {
temp.value -= 5
}
watch(temp,(newVal,oldVal)=>{
console.log(newVal,oldVal);
if (newVal >= 30) {
sugget.value = '操作系统'
}
else if(newVal >= 20) {
sugget.value = '计算机组成原理'
}
else if(newVal >= 10) {
sugget.value = '形势与政策'
}
else{
sugget.value = '草稿本'
}
},{ immediate: true })
watch
用于侦听temp
响应式数据的变化,并在数据变化时执行特定的函数。
watch(temp, (newVal, oldVal) => { ... })
:创建一个观察者,监视temp
的值。当temp
的值发生改变时,传入的箭头函数会被调用。这个函数接收两个参数:newVal
是变化后的新值,oldVal
是变化前的旧值。- 接下来的
if...else if...else
语句根据newVal
(即新的temp
值)来更新sugget.value
,提供不同的购书建议: { immediate: true }
:这是一个可选参数,当设置为true
时,表示在初始绑定时就会立即以当前的temp
值执行一次回调函数,意思就是:在运行开始时就会执行watch
函数对temp
值进行判断,这避免了初始值temp
与初始值sugget
无法对应
计算属性(computed)实现
虽然计算属性本身不是响应式数据的创建方式,但它依赖于响应式数据并在依赖项变化时自动重新计算,因此是响应式系统的一部分。
js
<template>
<div>
<h2>{{ temp }}</h2>
<h5>{{ sugget }}</h5>
<button @click="add">+5</button>
<button @click="minus">-5</button>
</div>
</template>
<script setup>
import { ref,watch,computed } from 'vue'
let temp = ref(20)
const sugget = computed(() =>{
if (temp.value >= 30) {
return '操作系统';
}
else if(temp.value >= 20) {
return'计算机组成原理';
}
else if(temp.value >= 10) {
return'形势与政策';
}
else{
return'草稿本';
}
})
const add = () => {
temp.value += 5
}
const minus = () => {
temp.value -= 5
}
computed
用于定义依赖于其他数据的衍生数据。它是一个计算属性,只有当依赖的数据发生变化时才会重新计算,结果会被缓存起来,直到下一次依赖的数据变化。
将sugget
重新声明为一个计算属性,它基于一个函数来计算其返回值。和watch
类似,这个函数内部的逻辑会根据temp.value
的值来决定返回什么样的字符串
使用computed
的优点在于:
- 效率:只有当依赖的响应式属性(在这里是
temp.value
)变化时,才会重新计算sugget
的值,否则直接返回缓存的值,这在性能上更为高效。 - 声明式:使得代码更加清晰易读,关注于“是什么”而不是“怎么做”,提高了可维护性。
watch 和 computed 的区别
- watch默认不会主动执行,且watch是监听某个变量的变更,会执行内部的回调
- computed 默认会主动执行,当回调函数中任意变量值变更时,computed都会重新执行
购物车
理解完前一章讲的模板语法和上文讲的响应式基础,接下来的应用简直过关斩将
- 利用
v-for
模板语法指令遍历books
数组,为每一本书创建一行<tr>
,显示每本书的序号、名称、出版日期、价格和购买数量。 - 为每本书提供增加、减少数量和删除的按钮。
- 定义方法:
add(i)
:根据索引i
,增加对应书籍的购买数量。minus(i)
:根据索引i
,减少对应书籍的购买数量(并禁用减按钮当数量为1时)。del(i)
:根据索引i
,使用splice
方法从books
数组中删除对应的书籍条目。
- 显示总价格
<h2>总价格:{{ totalPrice }}</h2>
,利用计算属性computed
动态计算。 - 使用
reactive
创建书籍响应式对象,使得对象的属性变化能够被Vue自动追踪
响应式更新: 通过将
books
数组设置为响应式的,当数组中的任意一项书籍的属性(如count
)发生变化时(比如通过add
和minus
方法增减数量),Vue会自动检测到这个变化,并相应地更新与这些数据相关的DOM元素,确保用户界面能够即时反映出数据的最新状态。
js
<template>
<table>
<thead>
<th>序号</th>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</thead>
<tbody>
<tr v-for="(item,index) in books" :key="item.id">
<td>{{ index+1}}</td>
<td>{{ item.name }}</td>
<td>{{ item.date }}</td>
<td>{{ item.price }}</td>
<td>
<button @click="minus(index)" :disabled="item.count <= 1">-</button>
<span class="counter">{{item.count}}</span>
<button @click="add(index)">+</button>
</td>
<td>
<button @click="del(index)">删除</button>
</td>
</tr>
</tbody>
</table>
<h2>总价格:{{ totalPrice }}</h2>
</template>
<script setup>
import { computed ,reactive} from 'vue';
const add = (i) => {
books[i].count++
}
const minus = (i) => {
books[i].count--
}
const del= (i) => {
books.splice(i, 1)
}
const totalPrice = computed(() => {
let sum = 0
for (let item of books) {
sum += item.price * item.count
}
return sum
})
const books =reactive([
{
id: 1,
name: '《算法导论》',
date: '2006-9',
price: 85.00,
count: 1
},
。。。。。
])
</script>
<style lang="css" scoped>
table{
border: 1px solid #ccc;
margin: 0 auto;
border-collapse: collapse;
}
th, td{
padding: 8px 16px;
border: 1px solid #aaa;
}
.counter{
margin: 0,5px;
}
</style>
结语
Ref
可以持有任何类型的值,包括深层嵌套的对象、数组或者 JavaScript 内置的数据结构
非原始值将通过 reactive()
转换为响应式代理,Vue 能够拦截对响应式对象所有属性的访问和修改,以便进行依赖追踪和触发更新。
reactive()
API 有一些局限性:
- 有限的值类型:它只能用于对象类型 (对象、数组和如
Map
、Set
这样的集合类型它不能持有如string
、number
或boolean
这样的原始类型- 不能替换整个对象:由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失:
watch
和 computed
的区别
- watch默认不会主动执行,且watch是监听某个变量的变更,会执行内部的回调
- computed 默认会主动执行,当回调函数中任意变量值变更时,computed都会重新执行
评论