Vue3 + vite + Ts + computed(计算属性) 和 watch(侦听器)的简单使用方法
1、computed :计算属性
- 计算属性就是当依赖的值发生变化的时候,才会触发他的更改,如果依赖的值,不发生变化的时候,使用的是缓存中的属性值。
- 简单使用方法,示例代码如下:
import { ref, reactive, computed } from 'vue'
// 计算总价格,通过 computed 计算属性来计算
const totalPrice = computed(() => {
return goodList.reduce((total: number, item: goodList) => {
return total + item.good_count * item.good_price
}, 0)
})
- 简单购物车案例,代码如下:
<template>
<div>
<div>
<input type="text" v-model="keyword" placeholder="搜索">
</div>
<div style="margin-top:15px;">
<table>
<thead>
<tr>
<th>物品名称</th>
<th>物品单价</th>
<th>物品数量</th>
<th>物品总价</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in searchGoogList" :key="item.id">
<td>{{ item.good_name }}</td>
<td>{{ item.good_price }}</td>
<td>
<button @click="item.good_count > 1 ? item.good_count-- : null">-</button>
{{ item.good_count }}
<button @click="item.good_count < 99 ? item.good_count++ : null">+</button>
</td>
<td>{{ item.good_price * item.good_count }}</td>
<td>
<button @click="deleteHandle(index)">删除</button>
</td>
</tr>
<tr>
<td colspan="5" align="right">总价:{{ totalPrice }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script setup lang='ts'>
import { ref, reactive, computed } from 'vue'
// 搜索关键字
const keyword = ref<string>("")
// 物品列表
const goodList = reactive([{
id: 1,
good_name: '小满的绿帽子',
good_price: 500,
good_count: 2
}, {
id: 2,
good_name: '小满的红衣服',
good_price: 10,
good_count: 1
}, {
id: 3,
good_name: '小满的黑袜子',
good_price: 120,
good_count: 1
}])
// 搜索方法
const searchGoogList = computed(() => {
return goodList.filter((item: goodList) => {
return item.good_name.includes(keyword.value)
})
})
// 计算总价格,通过 computed 计算属性来计算
const totalPrice = computed(() => {
return goodList.reduce((total: number, item: goodList) => {
return total + item.good_count * item.good_price
}, 0)
})
// 删除方法
const deleteHandle = (index: number) => {
goodList.splice(index, 1)
}
</script>
<style scoped>
table,
thead tr th,
tbody tr td {
border-collapse: collapse;
border: 1px pink solid;
}
th,
td {
padding: 5px 20px;
}
</style>
注意:这么定义的计算属性是只读的,不能修改
2、watch:侦听器
- 作用:监视数据的变化(和
Vue2
中的watch
作用一致) - 特点:
Vue3
中的watch
只能监视以下四种数据:- 1、
ref
定义的数据 - 2、
reactive
定义的数据 - 3、函数返回一个值
- 4、一个包含上述内容的数组
- 1、
2.1、情况一
- 监听
ref
定义的【基本类型】数据:直接写数据名即可,监视的是其value
值的改变(并停止监听)。
<template>
价格 :<input v-model="price" type="text" /><br />
<button @click="addPriceHandle">增长</button>
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
let price = ref<number>(0);
/**
* 增长价格方法
*/
const addPriceHandle = () => {
price.value += 1;
};
// 监听 message 变量
const stopWatch = watch(price, (newVal: number, oldVal: number) => {
console.log("当前价格:" + newVal);
if (newVal >= 10) {
// 停止监听
stopWatch();
}
});
</script>
<style scoped></style>
2.2、情况二
- 监听
ref
定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视
注意:
1、若修改的是ref
定义的对象中的属性,newValue
和oldValue
都是新值,因为它们是同一个对象。
2、若修改整个ref
定义的对象,newValue
是新值,oldValue
是旧值,因为不是同一个对象了。
<template>
姓名:{{ person.username }}<br />
年龄:{{ person.age }}<br />
<button @click="editUserNameHandle">修改姓名</button>
<button @click="editAgeHandle">修改年龄</button>
<button @click="editHandle">修改对象</button>
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
const person = ref({
username: "人类",
age: 30,
});
/**
* 修改姓名方法
*/
const editUserNameHandle = () => {
person.value.username += "~";
};
/**
* 修改姓名方法
*/
const editAgeHandle = () => {
person.value.age += 1;
};
/**
* 修改整个对象
*/
const editHandle = () => {
person.value = {
username: "近战法师 - 刘铁柱",
age: 50,
};
};
/**
* 监听对象:监听 ref 定义的【对象类型】数据,监听的是对象的地址值
*/
watch(
person,
(newVal: any, oldVal: any) => {
console.log(newVal);
console.log(oldVal);
}
);
</script>
<style lang="scss" scoped></style>
- 深度侦听,示例代码如下:
<template>
姓名:{{ person.username }}<br />
年龄:{{ person.age }}<br />
<button @click="editUserNameHandle">修改姓名</button>
<button @click="editAgeHandle">修改年龄</button>
<button @click="editHandle">修改对象</button>
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
const person = ref({
username: "人类",
age: 30,
});
/**
* 修改姓名方法
*/
const editUserNameHandle = () => {
person.value.username += "~";
};
/**
* 修改姓名方法
*/
const editAgeHandle = () => {
person.value.age += 1;
};
/**
* 修改整个对象
*/
const editHandle = () => {
person.value = {
username: "近战法师 - 刘铁柱",
age: 50,
};
};
/**
* 监听对象:监听 ref 定义的【对象类型】数据,监听的是对象的地址值,若想监听对象内部属性的变化,需要手动开启深度监听
*/
watch(
person,
(newVal: any, oldVal: any) => {
console.log(newVal);
console.log(oldVal);
},
{
deep: true, // 深度监听
immediate: true, // 立即监听
}
);
</script>
<style lang="scss" scoped></style>
2.3、情况三
- 监听
reactive
定义的【对象类型】数据,且默认开启了深度监听。 - 简单例子:
<template>
姓名:{{ person.username }}<br />
年龄:{{ person.age }}<br />
<button @click="editUserNameHandle">修改姓名</button>
<button @click="editAgeHandle">修改年龄</button>
<button @click="editHandle">修改对象</button>
</template>
<script setup lang="ts">
import { reactive, watch } from "vue";
const person = reactive({
username: "人类",
age: 30,
});
/**
* 修改姓名方法
*/
const editUserNameHandle = () => {
person.username += "~";
};
/**
* 修改姓名方法
*/
const editAgeHandle = () => {
person.age += 1;
};
/**
* 修改整个对象
*/
const editHandle = () => {
Object.assign(person, {
username: "近战法师 - 刘铁柱",
age: 60,
});
};
/**
* 监听对象:监听 reactive 定义的【对象类型】数据
*/
watch(person, (newVal: any, oldVal: any) => {
console.log(newVal);
console.log(oldVal);
});
</script>
<style lang="scss" scoped></style>
2.4、情况四
- 监听响应式对象中的某个属性,且该属性时基本类型的,要写成函数式
- 监听
ref
或reactive
定义的【对象类型】数据中的某个属性,注意点如下:- 1、若该属性值不是【对象类型】,需要写成函数形式。
- 2、若该属性值是依然是【对象类型】,可直接编,也可写成函数,建议写成函数。
- 简单例子:
<template>
姓名:{{ person.username }}<br />
年龄:{{ person.age }}<br />
汽车:{{ person.car.c1 + "," + person.car.c2 }}<br />
<br />
<button @click="editUsernameHandle">修改姓名</button>
<button @click="editAgeHandle">修改年龄</button>
<button @click="editC1Handle">修改第一台车</button>
<button @click="editC2Handle">修改第二台车</button>
<button @click="editCHandle">修改所有车</button>
</template>
<script setup lang="ts">
import { reactive, watch } from "vue";
const person = reactive({
username: "张三",
age: 60,
car: {
c1: "奔驰",
c2: "宝马",
},
});
/**
* 修改姓名
*/
function editUsernameHandle() {
person.username += "~";
}
/**
* 监听姓名变化,只监听姓名
*/
watch(
() => person.username,
(newVal, oldVal) => {
console.log(newVal);
console.log(oldVal);
}
);
/**
* 修改年龄
*/
function editAgeHandle() {
person.age += 1;
}
/**
* 修改第一台车
*/
function editC1Handle() {
person.car.c1 += 1;
}
/**
* 修改第二台车
*/
function editC2Handle() {
person.car.c2 += 1;
}
/**
* 修改所有车
*/
function editCHandle() {
Object.assign(person.car, {
c1: "劳斯莱斯",
c2: "布加迪",
});
}
/**
* 监听所有汽车
*/
watch(
() => person.car,
(newVal, oldVal) => {
console.log(newVal);
console.log(oldVal);
},
{
deep: true,
}
);
</script>
<style lang="scss" scoped></style>
结论:监听的要是对象里的属性,那么最好写函数式,。
注意点:若是对象监听的是地址值,需要关注对象内部,需要手动开启深度监听。
2.5、情况五
- 监听上述的多个数据
- 简单例子:
<template>
姓名:{{ person.username }}<br />
年龄:{{ person.age }}<br />
汽车:{{ person.car.c1 + "," + person.car.c2 }}<br />
<br />
<button @click="editUsernameHandle">修改姓名</button>
<button @click="editAgeHandle">修改年龄</button>
<button @click="editC1Handle">修改第一台车</button>
<button @click="editC2Handle">修改第二台车</button>
<button @click="editCHandle">修改所有车</button>
</template>
<script setup lang="ts">
import { reactive, watch } from "vue";
const person = reactive({
username: "张三",
age: 60,
car: {
c1: "奔驰",
c2: "宝马",
},
});
/**
* 修改姓名
*/
function editUsernameHandle() {
person.username += "~";
}
/**
* 修改年龄
*/
function editAgeHandle() {
person.age += 1;
}
/**
* 修改第一台车
*/
function editC1Handle() {
person.car.c1 += 1;
}
/**
* 修改第二台车
*/
function editC2Handle() {
person.car.c2 += 1;
}
/**
* 修改所有车
*/
function editCHandle() {
Object.assign(person.car, {
c1: "劳斯莱斯",
c2: "布加迪",
});
}
/**
* 监听第一台车和姓名
*/
watch(
[() => person.car.c1, () => person.username],
(newVal, oldVal) => {
console.log(newVal);
console.log(oldVal);
}
);
</script>
<style lang="scss" scoped></style>