一、Vue计算属性
我们先来看一个例子:(需要实现的内容是在姓和名的输入框中输入字段后,下面拼接出全名):
第一种实现方法:
<body>
<div id="root">
<input type="text" v-model="fname"><br/><br/>
<input type="text" v-model="lname"><br/><br/>
<span>{
{fullname()}}</span>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: '#root',
data: function() {
return {
fname: '申',
lname: '颖'
}
},
methods: {
fullname() {
return this.fname + '-' + this.lname;
}
},
})
</script>
</body>
效果展示:
第二种实现方法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<input type="text" v-model="fname"><br/><br/>
<input type="text" v-model="lname"><br/><br/>
<span>{
{fullname}}</span>
<span>{
{fullname}}</span>
<span>{
{fullname}}</span>
<span>{
{fullname}}</span>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: '#root',
data: function() {
return {
fname: '申',
lname: '颖'
}
},
computed: {
fullname: {
// get的作用:当有人读取fullname时,get就会被调用,且返回值作为fullname的值
// get什么时候被调用:
// 1.初次读取fullname时
// 2.所依赖的数据发生变化时
get() {
console.log('get被调用了');
return this.fname + '-' + this.lname;
},
// set什么时候被调用:当fullname被修改的时候
set(value) {
console.log('set', value);
const arr = value.split('-');
this.fname = arr[0];
this.lname = arr[1];
}
}
}
})
</script>
</body>
</html>
上面的代码仔细看
以为会调用四次fullname函数,但是实际只调用了一次,如果是第一种方法的话就会调用四次。因为计算属性自己有缓存机制。
总结计算属性:
1.定义:要用的属性不存在,要通过已有的属性计算得来。
2.原理:底层借助了Object.defineProperty方法提供的getter和setter
3.get函数什么时候执行?
(1)初次读取的时候会执行一次
(2)当依赖的数据发生改变时会被再次调用
4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试更方便。
5.备注:
(1)计算属性最终会出现在vm上,直接读取使用即可
(2)如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生
如果只需要读取计算属性,可以采用下面的简写方式:
<body>
<div id="root">
<input type="text" v-model="fname"><br/><br/>
<input type="text" v-model="lname"><br/><br/>
<span>{
{fullname}}</span>
<span>{
{fullname}}</span>
<span>{
{fullname}}</span>
<span>{
{fullname}}</span>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: '#root',
data: function() {
return {
fname: '申',
lname: '颖'
}
},
computed: {
fullname() {
return this.fname + '-' + this.lname;
}
}
})
</script>
</body>
二、Vue监视属性
监视属性有两种写法
(1)写法1
<body>
<div id="root">
<h2>今天天气很{
{info}}</h2>
<button @click="change">切换按钮</button>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: '#root',
data: function() {
return {
ishot: true
}
},
computed: {
info() {
return this.ishot ? "热" : "不热"
}
},
methods: {
change() {
return this.ishot = !this.ishot;
}
},
watch: {
ishot: {
// immediate代表初始化时让handler调用一下
immediate: true,
// handler什么时候调用?当ishot发生改变时
handler(newvalue, oldvalue) {
console.log('ishot is change', newvalue, oldvalue);
}
}
}
})
</script>
</body>
(2)写法二
<body>
<div id="root">
<h2>今天天气很{
{info}}</h2>
<button @click="change">切换按钮</button>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: '#root',
data: function() {
return {
ishot: true
}
},
computed: {
info() {
return this.ishot ? "热" : "不热"
}
},
methods: {
change() {
return this.ishot = !this.ishot;
}
}
})
vm.$watch('ishot', {
immediate: true,
handler(newvalue, oldvalue) {
console.log('ishot is change', newvalue, oldvalue);
}
})
</script>
</body>
监视属性watch注意点:
(1)当被监视的属性变化时,回调函数(handler)自动调用,进行相关操作
(2)监视的属性必须存在,才能进行监视
(3)监视的两种写法:
1.new Vue时传入watch配置
2.通过vm.$watch监视
(3)深度监视
<body>
<div id="root">
<hr>
<h3>a的值为{
{number.a}}</h3>
<button @click="adda">执行a++</button>
<hr>
<h3>b的值为{
{number.b}}</h3>
<button @click="addb">执行b++</button>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: '#root',
data: function() {
return {
ishot: true,
number: {
a: 1,
b: 2
}
}
},
methods: {
adda() {
return this.number.a++;
},
addb() {
return this.number.b++;
}
},
watch: {
immediate: true,
// 监视多级结构中所有属性的变化
number: {
// deep加上了就代表a或者b变化了都会执行handler函数,如果不加就是整个number变了才会执行handler函数
deep: true,
handler() {
console.log('number被改变了');
}
}
}
})
</script>
</body>
深度监视注意点:
(1)Vue中的watch默认不监视对象内部值的改变(一层)
(2)配置deep:true可以监测对象内部值得改变(多层)
备注:
(1)Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
(2)使用watch时根据数据的具体结构,决定是都采用深度监视
(4)监视的简写形式
当watch里面的配置项只有handler的时候才可以用简写形式
简写形式一:
<body>
<div id="root">
<h2>今天天气很{
{info}}</h2>
<button @click="change">切换按钮</button>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: '#root',
data: function() {
return {
ishot: true
}
},
computed: {
info() {
return this.ishot ? "热" : "不热"
}
},
methods: {
change() {
return this.ishot = !this.ishot;
}
},
watch: {
ishot(newvalue, oldvalue) {
console.log('ishot is change', newvalue, oldvalue);
}
}
})
</script>
</body>
简写形式二:
<body>
<div id="root">
<h2>今天天气很{
{info}}</h2>
<button @click="change">切换按钮</button>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: '#root',
data: function() {
return {
ishot: true
}
},
computed: {
info() {
return this.ishot ? "热" : "不热"
}
},
methods: {
change() {
return this.ishot = !this.ishot;
}
}
})
vm.$watch('ishot', function(newvalue, oldvalue) {
console.log('ishot is change', newvalue, oldvalue);
})
</script>
</body>
三、计算属性与监视属性对比
用监视属性去实现前面那个姓和名拼接成全名的例子并且要额外执行一个输入之后1s才显示
<body>
<div id="root">
<input type="text" v-model="fname"><br/><br/>
<input type="text" v-model="lname"><br/><br/>
<span>{
{fullname}}</span>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: '#root',
data: function() {
return {
fname: '申',
lname: '颖',
fullname: '申-颖'
}
},
watch: {
fname(val) {
// 这里定时器的函数只能写成箭头函数
// 是因为箭头函数没有this就会往外找,就是fname的this,fname的this就是vue所管理的函数,所以是vm
// 如果写成setTimeout(function(){})的话this指向的就是windows了
setTimeout(() => {
console.log(this);
this.fullname = val + '-' + this.lname;
}, 1000)
},
lname(val) {
setTimeout(() => {
this.fullname = this.fname + '-' + val;
}, 1000)
}
}
})
</script>
</body>
如果用计算属性写:
这个部分就有问题,你的return返回的值是交给setTimeout的不是fullName,所以根本得不到计算属性的值就无法渲染。
计算属性与监视属性之间的区别:
(1)计算属性能完成的功能,监视属性都可以完成
(2)监视属性能完成的功能计算属性不一定能完成,例如监视属性可以进行异步操作。
两个重要的小原则:
(1)所有被Vue管理的函数最好写成普通函数,这样this的执行才是vm或者组件实例对象
(2)所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数、Promise的回调函数等),最好写成箭头函数,这样this的指向才是vm或者组件实例对象