vue教程——06 计算属性与Waatch监听
一 计算属性的基本使用。
计算属性的两点通俗易懂理解:
1 computed用来监控自己定义的变量,该变量不在data里面声明,直接在computed里面定义,然后就可以在页面上进行双向数据绑定展示出结果或者用作其他处理;
2 computed比较适合对多个变量或者对象进行处理后返回一个结果值,也就是数多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化,举例:购物车里面的商品列表和总金额之间的关系,只要商品列表里面的商品数量发生变化,或减少或增多或删除商品,总金额都应该发生变化。这里的这个总金额使用computed属性来进行计算是最好的选择
官网:对于任何复杂逻辑,你都应当使用计算属性。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>计算属性的基本使用</title>
</head>
<body>
<div id="app">
<!-- Mastache语法 ,此处最好用计算属性-->
<h2>{{firstName+ " " + lastName}}</h2>
<!-- 计算属性 -->
<h2>{{fullName}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
firstName:"Kobe",
lastName:"Bryant"
},
computed: {
fullName:function(){
return this.firstName + " " + this.lastName
}
},
})
</script>
</body>
</html>
二 计算属性的get与 set方法
以刚才例子为例,修改一下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>计算属性的get与set方法</title>
</head>
<body>
<div id="app">
<!-- Mastache语法 ,此处最好用计算属性-->
<h2>{{firstName+ " " + lastName}}</h2>
<!-- 计算属性 -->
<h2>{{fullName}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
firstName:"Kobe",
lastName:"Bryant"
},
computed: {
fullName:{
get(){
return this.firstName + ' ' + this.lastName
},
set(value){
var arr = value.split(' ')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
},
})
</script>
</body>
</html>
getter与setter什么时候使用?
1 调用插值表达式的时候 :走get方法
2 设置这个属性属性值的时候:走set方法,同时会拿到设置的这个值(value),我就可以通过这个值去设置firstName和lastName。
三 计算属性的缓存
网上经常出现的例子:
本质区别:methods,即使firstName和lastName没有改变,也需要再次执行.
计算属性有缓存,只有关联属性改变才会再次计算
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>计算属性的缓存</title>
</head>
<body>
<div id="app">
<!-- methods,即使firstName和lastName没有改变,也需要再次执行 -->
<h2>{{getFullName}}</h2>
<h2>{{getFullName}}</h2>
<h2>{{getFullName}}</h2>
<h2>{{getFullName}}</h2>
<!-- 计算属性有缓存,只有关联属性改变才会再次计算 -->
<h2>{{fullName}}</h2>
<h2>{{fullName}}</h2>
<h2>{{fullName}}</h2>
<h2>{{fullName}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
firstName:"Kobe",
lastName:"Bryant"
},
computed: {
fullName(){
console.log("调用了计算属性fullName");
return this.firstName + " " + this.lastName
}
},
methods: {
getFullName(){
console.log("调用了getFullName");
return this.firstName + " " + this.lastName
}
},
})
</script>
</body>
</html>
四 Watch监听
watch可以监听数据的改变(不能监测数据内部的改变),但是如果使用不当就是多此一举了。
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
比如以上这个例子,使用watch监听firstName和lastName两个数据,其实就相当于computed,function内使用了Vue实例绑定的firstName和lastName。
Watch的使用场景:
监听数据变化,一般只监听一个变量或数组。
watch(`异步场景`),computed(`数据联动`)
五 watch使用举例
1 watch能监听到数组的push的改变
data () {
return {
demo: [1,2]
}
},
mounted (){
window.myVue = this
},
watch: {
demo(val){
console.log(val)
}
},
myVue.demo.push(3) //[1,2,3]
2 使用深度监听,监听数组对象
data () {
return {
demo:[
{
name:'张三',
age:18
}, {
name:'李四',
age:20
}
]
}
},
mounted (){
window.myVue = this
},
watch: {
demo: {
handler (val) {
console.log(val)
},
// 这里是关键,代表递归监听 demo 的变化
deep: true
}
},
myVue.demo[0].age = 30 //[{name:'张三',age:30},{name:'李四',age:20}]
3 监听对象
data () {
return {
demo:{
name: '张三',
child: {
name: '李四',
age: 20
}
}
}
},
mounted (){
window.myVue = this
},
watch: {
'demo.child': {
handler: function (val) {
console.log(val)
},
deep: true
},
'demo.name' (val) {
console.log(val)
}
},
myVue.demo.name = '王二' //王二
myVue.demo.age = '80' //{name:'李四',age:80}
4 watch监听遇到的问题:
数组方面:watch不能监听一下两种:
1 当你利用索引直接设置一个项时,例如:myVue.demo[1] = 5 解决方案 :this.$set(this.arr,0,100)
2 当你修改数组的长度时,例如:myVue.demo.length = 2 解决方案 :this.arr.splice(0,1)
对象方面:如果是data里面已经有的值,可以直接监听。如果没有,使用this.$set()
请参考:https://blog.csdn.net/qq_38280242/article/details/102807862
大体总结如下:
例子代码:
let vm = new Vue({
el: '#app',
data: {
message: 'wxs',
arr:[1,2,3],
obj:{
name:'wxs',
age:21
}
},
methods:{
change:function () {
this.message = 'vue'
// 举例子,没有代码逻辑
this.arr[0]=100
// 举例子,没有代码逻辑
this.arr.length=0
// 举例子,没有代码逻辑
this.obj.major='xxx'
}
},
watch:{
message:function (newValue,oldValue) {
console.log('message改变了')
},
arr:function (newValue,oldValue) {
console.log('arr木有改变')
},
obj:function (newValue,oldValue) {
console.log('obj木有改变')
}
},
template: `<div><div>{{message}}</div><div>{{arr[0]}}</div><div>{{obj.name}}</div><button @click="change()">改变!</button></div>`
})
当执行上面代码的时候,就会发现vue的watch没法监听。或者说vue无法监听,接下面内容会提及。
解决方法:
let vm = new Vue({
el: '#app',
data: {
message: 'wxs',
arr:[1,2,3],
obj:{
name:'wxs',
age:21
}
},
methods:{
change:function () {
this.message = 'vue'
// 举例子,没有代码逻辑
this.$set(this.arr,0,100)
// 举例子,没有代码逻辑
this.arr.splice(0,1)
// 举例子,没有代码逻辑
this.$set(this.obj,'major','Vue')
}
},
watch:{
message:function (newValue,oldValue) {
console.log('message改变了')
},
arr:function (newValue,oldValue) {
console.log('arr改变了')
},
obj:function (newValue,oldValue) {
console.log('obj改变了')
}
},
template: `<div><div>{{message}}</div><div>{{arr[0]}}</div><div>{{obj.name}}</div><button @click="change()">改变!</button></div>`
})
5 Vue 用 vm.set() 解决对象新增属性不能响应的问题
受 现 代 J a v a S c r i p t 的 限 制 , V u e 无 法 检 测 到 对 象 属 性 的 添 加 或 删 除 。 由 于 V u e 会 在 初 始 化 实 例 时 对 属 性 执 行 g e t t e r / s e t t e r 转 化 , 所 以 属 性 必 须 在 d a t a 对 象 上 存 在 才 能 让 V u e 将 它 转 换 为 响 应 式 的 。 V u e 提 供 了 V u e . s e t ( o b j e c t , p r o p e r t y N a m e , v a l u e ) / 来 实 现 为 对 象 添 加 响 应 式 属 性 。 受现代 JavaScript 的限制 ,Vue 无法检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的。 Vue 提供了 Vue.set (object, propertyName, value) / 来实现为对象添加响应式属性。 受现代JavaScript的限制,Vue无法检测到对象属性的添加或删除。由于Vue会在初始化实例时对属性执行getter/setter转化,所以属性必须在data对象上存在才能让Vue将它转换为响应式的。Vue提供了Vue.set(object,propertyName,value)/来实现为对象添加响应式属性。
我们查看对应的 Vue 源码:vue/src/core/instance/index.js
export function set (target: Array<any> | Object, key: any, val: any): any {
// target 为数组
if (Array.isArray(target) && isValidArrayIndex(key)) {
// 修改数组的长度, 避免索引>数组长度导致splcie()执行有误
target.length = Math.max(target.length, key)
// 利用数组的splice变异方法触发响应式
target.splice(key, 1, val)
return val
}
// key 已经存在,直接修改属性值
if (key in target && !(key in Object.prototype)) {
target[key] = val
return val
}
const ob = (target: any).__ob__
// target 本身就不是响应式数据, 直接赋值
if (!ob) {
target[key] = val
return val
}
// 对属性进行响应式处理
defineReactive(ob.value, key, val)
ob.dep.notify()
return val
}
看源码的结论:watch监听遇到的问题的结论