Vue构造选项-进阶属性
今天主要是学以下进阶属性
- computed 计算属性
- watch 侦听
- directives 指令
- mixin 混入
- extends 继承
- provide/inject
之前学了options.data
除了data变化更新UI,还能做点啥?
下面的代码运行在完整版的Vue中
computed - 计算属性
用途
被计算出来的属性就是计算属性
new Vue({
data: {
user: {
email: "111111@qq.com",
nickname: "小王",
phone: "12323121322"
}
},
computed: {
displayName: {
get() {
const user = this.user;
return user.nickname || user.email || user.phone;
},
set(value) {
this.user.nickname = value;
}
}
},
template: `
<div>
{{displayName}}
<div>
{{displayName}}
</button @click="add">set</button>
</div>
</div>
`,
methods: {
add(){
this.displayName = '圆圆'
}
}
})
get和set
让我们可以直接读和写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("小葵", "女"),
]
};
},
template: `
<div>
<div><button>全部</button><button>男</button><button>女</button>
<ul>
<li v-for="(u, index) in users" :key="index">{{u.name}} - {{u.gender}}</li>
</ul>
</div>
`
}).$mount("#app")
需求:点击男就显示全部男的,女和全部同理
思路:不能改变原来的users,那就再去开辟一个新的地方,需要些什么就存什么,然后展示出来
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>
<ul>
<li v-for="(u, index) in displayUsers" :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: ''
};
},
computed: {//这个计算出来的就是我们要的,是根据users和gender计算出来的
displayUsers(){
const {users, gender} = this
if(gender === ''){
return users
}else if(gender === 'male'){
return users.filter(u => u.gender === "男")
}else if(gender === 'female') {
return users.filter(u => u.gender === "女")
}
}
},
methods: {
showMale() {
this.gender = 'male';
},
showFemale() {
this.gender = 'female';
},
showAll(){
this.gender = '';
}
},
template: `
<div>
<div>
<button @click="gender = ''">全部</button>
<button @click="gender = 'male'">男</button>
<button @click="gender = 'female'">女</button>
<ul>
<li v-for="(u, index) in displayUsers" :key="index">{{u.name}} - {{u.gender}}</li>
</ul>
</div>
`
}).$mount("#app")
上面的代码button
里面用到gender
这些data
里面的值,都不需要加this
这样的写法就简单了很多,好懂而且方便改动代码。
computed
是有缓存的
意思是:如果我依赖的属性没有变化,这个计算属性就不会再算一次。上面的就是users和gender
不变就不会重新计算,一直点击全部,也只会计算一次。
watch - 监听/侦听
用途
当数据变化时,执行一个函数
和computed差不多,都是数据变了,就计算出新的属性,不过还是有区别
watch就是用来监听,就是会执行写的那个函数
但是有时候就不需要执行这个函数,很简单,添加一个判断是否需要执行的一个变量,用if(){}
,来做就行。
methods
中
undo() {
this.inUndoMode = true;
this.n = old;
this.inUndoMode = false;
}
data
中
data: {
n: 0,
history: [],
inUndoMode: false
}
watch
中
watch: {
n(newValue, oldValue) {
console.log(this.inUndoMode)
if(!this.inUndoMode) {
//执行操作
}
}
}
这个n(){}
就是监听data中的n
,n
变了,就执行里面的代码
但是watch
是异步的,methods
中this.n = old
之后,会立刻去执行watch
中的函数吗?
不会,所以一直把methods
中的
this.inUndoMode = false;
执行了,才去执行watch
函数
所以模式还是没有改变
解决:做一个等待,等watch执行了就可以执行this.inUndoMode = false;
了
methods
中
watch: {
undo() {
this.inUndoMode = true;
this.n = old;
this.$nextTick(() => {
this.inUndoMode = false;
})
}
}
this.$nextTick
就是Vue里面自己封装的异步函数。
现在就解决了这个问题。
watch: {
n : {handler(){},immediate: true}
}
当一个数据初始化的时候,watch
提供了一个参数的值,immediate
,true
就在初始化的时候就开始监听,false
就在后面变化的时候监听
这样就和computed
的功能差不多没区别了
不过都有了computed
,为什么还要不用它而去模拟它呢,所以用处不大.
都是在数据变化的时候执行一个函数
computed
着重于依赖之间的变化,得出一个结果
watch
着重于变化时去执行什么东西,
数据变化
什么是数据变化?
- 简单类型看值
- 复杂类型看地址
就是===
看是否相等
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("a 变了");
},
}
})
上面的代码。如果是监听对象里面的属性,就写成"obj.a": function() {}
如果a
变了,点击了第二个按钮,obj也没有变化(因为地址没有变)
如果点击按钮三,就会发现obj
变了,但是还是{a: 'a'}
,所以a
没有变化
这里是一个对象地址变了,这个对象在Vue中才算变了,才会触发watch的监听
需求:对象里面的属性的值变了,也算对象变了,这里有一个deep
属性
watch
中
obj: {handler(){}, deep: true}
这样就是里面的属性变了,那么这个obj就变了,就会触发watch
里面的函数。
watch
里面不要写箭头函数,因为watch
要用到this
,箭头函数没有自己的this
,得不到vm
,而写function
,当这个函数被调用时,就会给被Vue
传递一个this
是vm
new Vue({...})
这是函数的调用
function x() {}
这才是函数的声明
前者this
指向window
或者全局属性
后者this
指向x
这个函数
还可以使用
this.$watch('n', function(){})
这样来是用watch,可以放到生命周期钩子中使用。
总结
computed
- 计算属性
- 计算出一个值,使用这个值不用加括号
- 根据依赖的变化,有缓存
watch
- 监听
- immediate 第一次渲染的时候是否执行函数
- deep 监听对象时,是否要看对象里面的属性