computed
是一个计算属性(被计算出来的属性就是计算属性),不需要加括号,会根据依赖是否变化来缓存。
- 展示用户名
//引用的是完整版Vue
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
data: {
user: {
email: "wuyouzhen@qq.com",
nickname: "Luna",
phone: "13112345678"
}
},
computed: {
displayName(){
const user = this.user
return user.nickname || user.email || user.phone//优先展示nickname,再展示email,再展示phone
}
},
template: `
<div>
{{displayName}}
</div>
`
}).$mount("#app");
如果要多次展示,那就多写几遍即可,哪天改了需求,只需要改顺序就行return user.nickname || user.phone || user.email
,不用再多次重复写。
template: `
<div>
{{displayName}}
<div>
{{displayName}}
</div>
</div>
`
计算属性可以让根据其他属性计算而来的属性变成一个属性,也可以用getter和setter来写
computed: {
displayName: {
get() {
const user = this.user;
return user.nickname || user.email || user.phone;
},
set(value) {
this.user.nickname = value;
}
}
},
template: `
<div>
{{displayName}}
<button @click="add">set</button>
</div>
`,
methods: {
add() {
this.displayName = "圆圆";
}
}
我们既能读displayName,也可以写它
- 展示列表
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");
computed有缓存属性,如果依赖的属性没有变化,也就不会重新计算;getter和setter默认不会做缓存,因为Vue做了特殊处理。
watch
监听/侦听(当数据变化时,执行一个函数)
- 撤销
new Vue({
data: {
n: 0,
history: [],
inUndoMode: false
},
watch: {
n: function(newValue, oldValue) {
if (!this.inUndoMode) {
this.history.push({ from: oldValue, to: newValue });
}
}
},
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;
const old = last.from;
this.n = old; // watch n 的函数会异步调用
this.$nextTick(() => {
this.inUndoMode = false;
});//nextTick延迟回调
}
}
}).$mount("#app");
- 模拟computed(不建议使用)
new Vue({
data: {
user: {
email: "fangfang@qq.com",
nickname: "方方",
phone: "13812312312"
},
displayName: ""
},
watch: {
"user.email": {
handler() {
const {user: { email, nickname, phone }} = this;//从this中解析出user,从user中解析出三个变量
this.displayName = nickname || email || phone;
},
immediate: true // 第一次渲染也触发 watch
},
"user.nickname": {
handler() {
const {user: { email, nickname, phone }} = this;
this.displayName = nickname || email || phone;
},
immediate: true
},
"user.phone": {
handler() {
const {user: { email, nickname, phone }} = this;
this.displayName = nickname || email || phone;
},
immediate: true
}
},
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() {},
obj() {},
"obj.a": function() {}
}
}).$mount("#app");
当点击“n+1”时,n变为1
当点击“obj.a + 'hi'”时,obj没有变(内存地址没变),obj.a变了
当点击"obj = 新对象"时,obj变了(内存地址变了),obj.a没变
但如果需要obj.a变了的同时obj也变,可以使用deep:true,意思时监听object的时候往深了看,默认为false。
watch语法
watch: {a: function (val, oldVal) {}}
也可以是watch: {a() {}}
watch: {b: [f1,f2]}
watch: {c: 'methodName'}
watch: {d: {handler:fn, deep:true, immediate:true}}
- `vm.$watch('n', function(){}, {immediate: true})
注意:不要使用箭头函数,因为this 将不会按照期望指向 Vue 实例,而是全局对象