进阶属性
computed —— 计算属性
-
不需要加括号
-
它会根据依赖是否变化来缓存
计算属性的好处:可以让一些是根据其他属性计算而来的属性变成一个属性
new Vue({
data: {
user: {
email: "fangyinghang@qq.com",
nickname: "方方",
phone: "13812312312"
}
},
computed: {
displayName: {
get() {
const user = this.user;
return user.nickname || user.email || user.phone;
},
set(value) {
console.log(value);
this.user.nickname = value;
}
}
},
// DRY don't repeat yourself
// 不如用 computed 来计算 displayName
template: `
<div>
{{displayName}}
<div>
{{displayName}}
<button @click="add">set</button>
</div>
</div>
`,
methods: {
add() {
console.log("add");
this.displayName = "圆圆";
}
}
}).$mount("#app");
不用computed筛选男女
// 引用完整版 Vue,方便讲解
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
let id = 0;
const createUser = (name, gender) => {
id += 1;
return { id: id, name: name, gender: gender };
};
new Vue({
data() {
return {
users: [
createUser("方方", "男"),
createUser("圆圆", "女"),
createUser("小新", "男"),
createUser("小葵", "女")
],
displayUsers: []
};
},
created() {
this.displayUsers = this.users;
},
methods: {
showMale() {
this.displayUsers = this.users.filter(u => u.gender === "男");
},
showFemale() {
this.displayUsers = this.users.filter(u => u.gender === "女");
},
showAll() {
this.displayUsers = this.users;
}
},
template: `
<div>
<div>
<button @click="showAll">全部</button>
<button @click="showMale">男</button>
<button @click="showFemale">女</button></div>
<ul>
<li v-for="(u,index) in displayUsers" :key="index">{{u.name}} - {{u.gender}}</li>
</ul>
</div>
`
}).$mount("#app");
用computed筛选男女
// 引用完整版 Vue,方便讲解
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
let id = 0;
const createUser = (name, gender) => {
id += 1;
return { id: id, name: name, gender: gender };
};
new Vue({
data() {
return {
users: [
createUser("方方", "男"),
createUser("圆圆", "女"),
createUser("小新", "男"),
createUser("小葵", "女")
],
gender: ""
};
},
computed: {
displayUsers() {
const hash = {
male: "男",
female: "女"
};
const { users, gender } = this;
if (gender === "") {
return users;
} else if (typeof gender === "string") {
return users.filter(u => u.gender === hash[gender]);
} else {
throw new Error("gender 的值是意外的值");
}
}
},
methods: {
setGender(string) {
this.gender = string;
}
},
template: `
<div>
<div>
<button @click="setGender('') ">全部</button>
<button @click="setGender('male')">男</button>
<button @click="setGender('female')">女</button></div>
<ul>
<li v-for="(u,index) in displayUsers" :key="index">{{u.name}} - {{u.gender}}</li>
</ul>
</div>
`
}).$mount("#app");
用途:
- 被计算出来的属性就是计算属性
缓存
-
如果依赖的属性没有变化,就不会重新计算
-
getter/setter默认不会做缓存,Vue做了特殊处理
watch 监听/侦听
用途
-
一旦data变化,执行一个函数
-
撤销
new Vue({
data: {
n: 0,
history: [],
inUndoMode: false//在撤销模式
},
watch: {
n: function(newValue, oldValue) { //n:function
console.log(this.inUndoMode);
if (!this.inUndoMode) {
this.history.push({ from: oldValue, to: newValue });
}
}
},
// 不如用 computed 来计算 displayName
template: `
<div>
{{n}}
<hr />
<button @click="add1">+1</button>
<button @click="add2">+2</button>
<button @click="minus1">-1</button>
<button @click="minus2">-2</button>
<hr/>
<button @click="undo">撤销</button>
<hr/>
{{history}}
</div>
`,
methods: {
add1() {
this.n += 1;
},
add2() {
this.n += 2;
},
minus1() {
this.n -= 1;
},
minus2() {
this.n -= 2;
},
undo() {
const last = this.history.pop();
this.inUndoMode = true;
console.log("ha" + this.inUndoMode);
const old = last.from;
this.n = old; // watch n 的函数会异步调用
this.$nextTick(() => {
this.inUndoMode = false;
});
}
}
}).$mount("#app");
- 模拟computed
new Vue({
data: {
user: {
email: "fangfang@qq.com",
nickname: "方方",
phone: "13812312312"
},
displayName: ""
},
watch: {
"user.email": {
handler: "changed", //处理器
immediate: true // 第一次渲染是也触发 watch
},
"user.nickname": {
handler: "changed",
immediate: true // 第一次渲染是也触发 watch
},
"user.phone": {
handler: "changed",
immediate: true // 第一次渲染是也触发 watch
}
},
// 不如用 computed 来计算 displayName
template: `
<div>
{{displayName}}
<button @click="user.nickname=undefined">remove nickname</button>
</div>
`,
methods: {
changed() {
console.log(arguments);
const user = this.user;
this.displayName = user.nickname || user.email || user.phone;
}
}
}).$mount("#app");
何谓变化?
- 示例:
new Vue({
data: {
n: 0,
obj: {
a: "a"
}
},
template: `
<div>
<button @click="n += 1">n+1</button>
<button @click="obj.a += 'hi'">obj.a + 'hi'</button>
<button @click="obj = {a:'a'}">obj = 新对象</button>
</div>
`,
watch: {
n() {
console.log("n 变了");
},
obj() {
console.log("obj 变了");
},
"obj.a": function() {
console.log("obj.a 变了");
}
}
}).$mount("#app");
obj原本是{a: 'a'},现在是obj={a:'a'},请问obj变了没有(变了),obj.a变了没有(没有)
如果把一个简单的数据类型的值变了,那就一定是变了;如果把一个对象的简单类型变了,那就只做值的对比;如果把一个对象的地址变了,Vue才会认为这个对象变了。
-
简单的类型看值,复杂类型(对象)看地址
-
这其实就是
===的规则
语法
deep:true是干什么的?
-
如果
object.a变了,请问object算不算也变了 -
如果你需要答案是【也变了】,那么就用
deep:true -
如果你需要答案是【没有变】,那么就用
deep:false -
deep的意思是,监听object的时候是否往深了看
面试题
computed和watch的区别?
-
computed就是计算属性的意思;watch就是监听的意思。
-
computed是用来计算出一个值的,这个值在调用的时候不需要加括号,当属性一样用,第二根据依赖自动缓存,如果依赖不变,这个computed的值就不会重新计算。
-
watch是用来监听的,它有两个选项:①、immediate表示是否在第一次渲染的时候执行这个函数;②、deep是我们监听一个对象,是否要看这个对象里面的属性的变化。