381 vue 之 监听 watch:数据持久化,监听基本数据类型,监听对象,计算属性和watch的区别
1、数据持久化 (本地存储)
1. 可以在数组的`增删改`, 都要保存一下, 比较繁琐
2. 监听数组的变化, 数组一旦发生变化, 在监听里面 保存一下(代码写一遍就可以了)
vue 提供了一个监听器.
TodoMVC 数据持久化
需求 : 将todoMVC中的数据, 保存到
本地存储
中 (本地持久化)
-
何时存储数据?
因为功能中的 CRUD 都会修改 list 数据,所以,只要 list 数据发生改变, 就要保存到本地存储中;
方法一 : 在 CRUD 中 分别调用保存数据的方法,(不推荐 太繁琐)
方法二 : 想办法监听 list 数据的改变,只要 list 数据变了, 就调用保存数据的方法
可以使用 vue 的 watch 监听 list 的数据改变
-
存储值
监听数组和监听对象一样 需要深度监听
保存值, 记得把对象转化为字符串(存的快 省空间)
// 监听
watch: {
// 监听list
todoList: {
deep: true,
handler(newVal) {
// console.log('发生变化了', newVal)
// 保存起来
localStorage.setItem('todoList', JSON.stringify(newVal))
}
}
}
-
取值 , 在 data 中可以初始值
记得给一个默认值 空数组 []
const todoList = JSON.parse(localStorage.getItem('todoList')) || [],
2、说明
Vue 中可以通过 watch 配置项, 来监听 vue 实例中数据的变化
3、基本使用
watch: {
// 监听name属性的数据变化
// 作用 : 只要name的值发生变化,这个方法就会被调用
// 第一个参数 : 新值
// 第二个参数 : 旧值,之前的前
name(newVal,oldVal){
console.log('新 :',newVal);
console.log('旧 :',oldVal);
}
}
4、基本使用案例
需求 : 监听用户名文本框字符个数(3-6),并显示格式验证
<input type="text" v-model="name" />
<span v-show="isShow">用户名的字符 在 6-12之间</span> if
(/^[0-9a-zA-Z]{3,6}$/.test(newVal)) { 验证 }
5、监听对象 (数组也属于对象)
// data :
data: {
obj: {
name: 'zs'
}
},
// 组件
<input type="text" v-model="obj.name" />
// 监听
6、开始监听对象的属性
// 从对象的角度来监听的
因为对象和数组都是引用类型, 引用类型变量存的是地址, 地址没有变, 所以不会触发watch
obj: {
// 深度监听 属性的变化
deep: true,
// 立即处理 进入页面就触发
immediate: true,
// 数据发生变化就会调用这个函数
handler(newVal) {
console.log(newVal.name);
}
},
// 从属性的角度来监听
'obj.name'(newVal) {
console.log('监听对象的属性', newVal);
}
7、计算属性和watch的区别
computed 和 watch的区别
computed : 计算属性
- 1.根据已知值 ,得到一个新值
- 2. 新值随着已知值(相关的数据)变化而变化
(1)计算属性 ==> (得到的是)新值
(2)计算属性(num) ==> 是别人影响了我
watch : 监听器
1. 监听 ==> (监听)已知值
2. 监听数据 (num2) => 是我影响到了别人
8、命名规则 : 数字 字母 _ $
let xxx = 'sex'
let obj = {
'mg-name': 'zs',
age: 20,
// sex : '男'
[xxx] : '男'
}
05-监听器的基本使用-我的.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<h1>{{ num }}</h1>
<button @click="fn">按钮</button>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
num: 100,
msg: {}
},
methods: {
fn() {
for (let i = 0; i < 5; i++) {
this.num++
}
}
},
watch: {
num(newVal, oldVal) {
console.log(`新值是:${newVal},旧值是:${oldVal}`); // 新值是:105,旧值是:100
}
}
})
</script>
</body>
</html>
<script>
</script>
06-监听器监听复杂类型.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" v-model="obj.name" />
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
obj: {
name: 'zs'
}
},
// 监听
watch: {
// 监听 obj ,如果监听成功 newVal 就是obj的最新值 newVal 也是对象
// 因为obj是复杂类型 引用类型,直接这么写,监听的是对象的地址 【所以只有地址发送改变时,才会监听到。】
// obj(newVal) {
// console.log(newVal.name)
// }
// 方式1 : 监听对象+ 深度监听 【注意语法】
obj: {
deep: true, // 深度监听
immediate: true, // 立即监听
// 处理
handler(newVal) {
console.log(newVal.name)
}
},
// 方式2: 简单粗暴的直接监听对象里的属性(name)
'obj.name' (newVal) {
console.log(newVal)
}
}
})
</script>
</body>
</html>
08-监听器的小案例.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
需求 : 监听文本框内容的字符串长度 (3-6) , 如果超过范围,提示格式不正确
-->
<div id="app">
<input type="text" v-model="msg" />
<span v-show="isShow">格式不正确</span>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: '',
isShow: false
},
watch: {
msg(newVal) {
if (newVal.length >= 3 && newVal.length <= 6) {
console.log('格式正确')
this.isShow = false
} else {
console.log('格式不正确')
this.isShow = true
}
}
}
})
</script>
</body>
</html>
09-计算属性和监听器的区别.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
计算属性 computed
监听器 watch
计算属性 :
- 根据已知值, 得到一个新值
- 新值随着`相关的数据`发生变化而变化
- 是一个新值, 不是data里的值
区别 :
- 别人改变, 影响到了我
监听器
- 监听数据的变化
- 监听的不是一个新值(可以是data里的值)
区别 :
- 我改变了, 去影响别人 【被监听的数据改变了,会触发一些操作。】 【当被监听的数据改变了,就......】
-->
<div id="app"></div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
num1: 100,
num2: 200
},
computed: {
totalNum() {
return this.num1 + 20
}
},
watch: {
num2(newVal) {
// console.log(newVal)
if (newVal <= 205) {
console.log('我想干第一件事')
} else {
console.log('我想干第二件事')
}
}
}
})
</script>
</body>
</html>
补充
侦听属性watch:
- 不支持缓存,数据变,直接会触发相应的操作;
- watch支持
异步
; 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值
;- 当一个属性发生变化时,需要执行对应的操作;一对多;
- 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数:
immediate:组件加载立即触发回调函数执行
watch: {
firstName: {
handler(newName, oldName) {
this.fullName = newName + ' ' + this.lastName;
},
// 代表在wacth里声明了firstName这个方法之后立即执行handler方法
immediate: true
}
}
deep: deep的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器,但是这样性能开销就会非常大了,任何修改obj里面任何一个属性都会触发这个监听器里的 handler。
watch: {
obj: {
handler(newName, oldName) {
console.log('obj.a changed');
},
immediate: true,
deep: true
}
}
~
优化:我们可以使用字符串的形式监听
watch: {
'obj.a': {
handler(newName, oldName) {
console.log('obj.a changed');
},
immediate: true,
// deep: true
}
}
~
这样Vue.js才会一层一层解析下去,直到遇到属性a,然后才给a设置监听函数。