进阶属性预览
![5c754f8deb0945870b06172ace085f75.png](https://i-blog.csdnimg.cn/blog_migrate/c4726cfe1e289bfcc62a544e514e1901.jpeg)
options.data发生的事情:
- 会被Vue监听,每次data的读写都会被vue监控
- 会被Vue的实例监听(vm)代理
- vue会在data变化时更新UI
computed属性
需求一:展示用户信息,如果有名字,展示名字;没有名字,展示邮箱;没有邮箱,展示手机号。
代码:
new Vue({
data() {
return {
user:{
email:"xiequantai@qq.com",
nickname:"啊谢",
phone:"13812345678"
}
}
},
computed: {
displayName(){
const user=this.user
return user.nickname || user.email || user.phone
}
},
template:`
<div>
{{displayName}}
<div>
{{displayName}}
</div>
</div>
`
}).$mount('#app')
displayName是属性名,可以将display改成对象的形式,用getter、setter(写成函数)读取、设置displayName的值:
new Vue({
data() {
return {
user:{
email:"xiequantai@qq.com",
nickname:"啊谢",
phone:"13812345678"
}
}
},
computed: {
displayName:{
get(){
const user=this.user
return user.nickname || user.email || user.phone
},
set(value){
//用户传入一个value,将nick的值改成value
this.user.nickname=value
}
}
},
template:`
<div>
{{displayName}}
<div>
{{displayName}}
<button @click="add">set</button>
</div>
</div>
`,
methods: {
//点击时,将计算属性改成"圆圆"
add(){
this.displayName="圆圆"
}
},
}).$mount('#app')
第二个需求:点击"男"按钮,展示男的;点击“女”,展示女的;点击“全部”,展示全部列表。首先,写出3个按钮,然后将用户的姓名、性别都展示出来。
//封装一个写入姓名、性别的函数
let id=0
const createUser=(name,gender)=>{
id+=1
return{
id:id,
name:name,
gender:gender
}
}
new Vue({
data() {
return {
users:[
createUser("方方","男"),
createUser("圆圆","女"),
createUser("lisa","女"),
createUser("啊谢","男")
]
}
},
template:`
<div>
<div>
<button>全部</button>
<button>男</button>
<button>女</button>
</div>
<ul>
//v-for语法,u是给users里面的每一项取个名字。
<li v-for="(u,index) in users":key="index">{{u.name}} - {{u.gender}}</li>
</ul>
</div>
`,
}).$mount("#app")
下一步是让按钮有效:使用computed。
//封装一个函数:导出用户的姓名、性别
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:undefined。否则,后面有用set,会很麻烦
gender: ""
};
},
//计算属性
computed: {
displayUsers() {
const hash = {
male: "男",
female: "女"
};
//users和gender从vm对象上拿到,函数返回值就可以不加this了(在displayUsers)
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");
@click的用法
第一种—— v-on:click="fn"
第二种——@click="fn"
第三种——@click="fn(参数)"
第二步:不用computed怎么筛选
//封装一个函数:导出用户的姓名、性别
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("小葵", "女")
],
//用来复制users里面数据的
displayUsers: []
};
},
//完成对users里面的复制
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");
计算属性是有缓存的,属性如果没有改变,数据不会重新渲染。
watch属性
当数据变化时,就会执行一个函数。
例子一:撤销
new Vue({
data:{
n:0,
history:[],
//开始的撤销模式是关闭的
inUndoMode:false
},
watch:{
//观察n的变化
n(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(){
//pop从数组中拿到最后一项,然后拿到最后一项的from值
const last=this.history.pop()
console.log("----")
console.log(last)
console.log("----")
const old=last.from
console.log("-----")
console.log(old)
//打开撤销状态
this.inUndoMode=true
//watch是异步的
this.n=old
//一会关闭撤销模式,相当于setTimeout(,0)
this.$nextTick(()=>{
this.inUndoMode=false
},0)
}
},
}).$mount("#app")
设置撤销模式的原因是,让history不记录撤销的数组。watch是异步的,关闭撤销模式需要再次设置一个异步,this.$nextTick().
例子二:模拟computed
new Vue({
data: {
user: {
email: "fangfang@qq.com",
nickname: "方方",
phone: "13812312312"
},
displayName:undefined
},
watch: {
//观察user.email的变化
"user.email": {
handler:"changed",
immediate: true // 第一次渲染是也触发 watch
},
"user.nickname": {
handler: "changed",
immediate: true // 第一次渲染是也触发 watch
},
"user.phone": {
handler: "changed",
immediate: true // 第一次渲染是也触发 watch
}
},
template: `
<div>
{{displayName}}
<!--点击时,触发user.nickname函数,使nickname为空-->
<button @click="user.nickname=null">remove nickname</button>
</div>
`,
methods: {
changed() {
console.log(arguments);
const user = this.user;
//由于vue默认undefined或者null不展示,所以展示邮箱
this.displayName = user.nickname ||user.email || user.phone;
}
}
}).$mount("#app");
小结
- 我们给"user.email"绑定了一个handler方法,我们写的 watch 方法其实默认写的就是这个handler,Vue会去处理这个逻辑,最终编译出来其实就是这个handler,handler后面可以接变量,也可以接函数。
而immediate:true代表如果在 wacth 里声明了"user.email"之后,就会立即先去执行里面的handler方法。如果没有immediate或者immediate:false,第一次变化不会执行。
- deep选项,deep:true,只监听一个对象就可以,不需要监听里面的所有属性。如果deep:flase,就只看对象表层的地址,如果对象里面的属性发生了变化,对象的地址不发生变化。
- watch选项里面不能写箭头函数,因为箭头函数里面不能用this,里面的this指代window,而vue里面的每一个this都应该指代vm。
- watch里面的各种写法:
第一种:key:function(newValue,oldValue){ }
第二种:key(newValue,oldValue){ }
第三种:key变化时,分别执行f1和f2,key:[ f1,f2 ]
第四种:
key:'methodsName',然后在methods里面写相关的方法
第五种:
key:{
handle:fn,
deep:true,
immediate:true,
'object.a':function(){}
}
第六种:第五种写到外面的形式
vm.$watch(
'n',//监听的东西
function(){},
{deep:true,
immediate:true,
}
)
computed和watch的区别
computed就是计算属性的意思,watch就是监听的意思。computed如果依赖属性不变,computed的值就不会重新计算,即根据依赖会产生缓存。watch的作用是,监听一个属性,如果发生变化了,就执行函数。watch有两个属性,第一个是immediate,如果是true,第一次渲染就会执行computed里面的函数;第二个是deep,如果是true,表示监听一个对象的同时,也要监听对象里面属性的变化。