计算属性和watch监视
一.姓名案例
1.姓名案例-插值语法
<div id="root">
姓:<input type="text" value="张" v-model="firstname">
<br/><br/>
名:<input type="text" value="三" v-model="lastname">
<br/><br/>
全名:<span>{{firstname.slice(0,3)}} - {{lastname}}</span>
</div>
因为插值语法有局限性,如果需要对一个变量进行比较复杂的操作,推荐的是按照方法。
2.姓名案例-方法属性
<div id="root">
姓:<input type="text" value="张" v-model="firstname">
<br/><br/>
名:<input type="text" value="三" v-model="lastname">
<br/><br/>
全名:<span>{{fullName()}}</span>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
new Vue({
el:'#root',
data:{
firstname:'李',
lastname:'四'
},
methods:{
fullName(){
return this.firstname + '-' + this.lastname
}
}
})
</script>
全名:<span>{{fullName()}}</span> 不加小括号,代表把函数写上去 ,加了小括号,会得到方法的返回值。如果是回调使用(比如绑定按钮的点击事件方法等等),小括号可加可不加。
在 Vue.js 中,当绑定的数据发生变化时,Vue 的响应式系统会自动检测到这些变化 ,并触发视图更新,而不需要手动操作 DOM。这是 Vue 的核心特性之一,称为响应式数据绑定。
3.姓名案例-计算属性
计算属性:
1.定义:要用的属性不存在,要通过已有属性算得来。
2.原理:底层借助了objcet.defineproperty方法提供的getter和setter
3.get所数什么时候执行?
(1).初次读取时会执行一次。
(2).当依赖的数据发生改变时会被再次调用。
4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。缓存体现在初次刷新的时候,只调用计算属性一次get方法。
5.备注:
1.计算属性最终会出现在vm上,直接读取使用即可。
2.如果计算属性要被修改,那必须写set的数去响应修改,且set中要引起计算时依赖的数据发生
<div id="root">
姓:<input type="text" value="张" v-model="firstname">
<br/><br/>
名:<input type="text" value="三" v-model="lastname">
<br/><br/>
全名:<span>{{fullName}}</span> <br/><br/>
全名:<span>{{fullName}}</span> <br/><br/>
全名:<span>{{fullName}}</span> <br/><br/>
全名:<span>{{fullName}}</span> <br/><br/>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:'#root',
data:{
firstname:'李',
lastname:'四'
},
computed:{
fullName:{
get(){
console.log('get被调用了')
return this.firstname + '-' +this.lastname;
},
set(value){
const arr = value.split('-');
this.firstname = arr[0];
this.lastname = arr[1];
}
}
}
})
</script>
在 Vue.js 中,data
选项用于定义组件的响应式数据属性(属性名:属性值),而计算属性(computed properties)则是基于已有的响应式数据属性,通过逻辑运算或加工生成新的属性。
在computed属性中,必须要有get,且当有人读取fullName时get就会被调用,且返回值就作为fullName的值,所以vm._data.fullName = undefined ,因为计算好之后,就会立即渲染。
计算属性的结果会被缓存,只有当依赖的响应式属性发生变化时,才会重新计算。
getter
的调用时机?
初次读取 fullName
时:当你在模板中首次访问 {``{ fullName }}
,或者在 JavaScript 代码中首次访问 vm.fullName
,getter
会被调用。
所依赖的数据发生变化时:如果 firstName
或 lastName
发生变化,fullName
的缓存会失效,下次访问 fullName
时,getter
会再次被调用。
在 getter
中,this
指向当前的 Vue 实例(vm
),因此你可以访问 this.firstName
和 this.lastName
。
定义 setter
默认情况下,计算属性是只读的。如果你尝试直接赋值给 fullName
(例如:vm.fullName = 'Jane Smith'
),Vue 会抛出一个警告:[Vue warn]: Computed property "fullName" was assigned to but it has no setter.
如果 需要fullName
是可写的,需要显式地定义一个 setter
。setter
会在尝试修改 fullName
时被调用。在 setter
中,建议解析新的值并更新依赖的数据属性(如 firstName
和 lastName
)。
示例解释
Getter :在初次读取或依赖数据变化时,getter
会被调用,返回计算后的值。
Setter :当你尝试修改 fullName
时,setter
会被调用,解析新的值并更新 firstName
和 lastName
。
当firstName
或 lastName
发生变化,计算属性get会重新调用。

定义了setter,在控制台修改计算属性,页面会进行刷新最新属性值。

4.计算属性简写和完整写法对比
computed:{
//完整写法
fullName:{
get(){
console.log('get被调用了')
return this.firstname + '-' +this.lastname;
},
set(value){
const arr = value.split('-');
this.firstname = arr[0];
this.lastname = arr[1];
}
}
//简写 只考虑读取不考虑修改
fullName(){
return this.firstname + '-' +this.lastname;
}
}
二.天气案例
1. 表达式的形式
<h2>今天天气很{{ishot ? '炎热' :'凉爽'}}</h2>
2. 计算属性
<h2>今天天气很{{info}}</h2>
<button>切换天气</button>
computed:{
info(){
return this.ishot ? '炎热' :'凉爽'
}
},
methods:{
changeweather(){
this.ishot = !this.ishot
}
}
3.在button上面进行直接写
<button @click="ishot = !ishot">切换天气</button> 可以做一些简单的语句@click="ishot = !ishot;x++"
但如果是比较难的,alert
在 Vue.js 中,如果你在组件的方法或计算属性中直接调用 alert(1)
,JavaScript 的作用域链解析规则如下:
当前组件实例(
vm
) :首先会在当前 Vue 组件实例(通常称为vm
,即 ViewModel)的作用域中查找alert
函数。原型链:如果组件实例中没有找到,会沿着 JavaScript 的原型链向上查找。
全局作用域(
window
) :如果原型链中也没有找到,最后会在全局作用域(浏览器中是window
对象)中查找。
没找到就会报错,需要这样写window.alert(1), 然后再data当中进行写data{window}。所以还是要在回调函数当中写,方便点。
4.监视属性
监视属性watch:
1.当被监视的属性变化时,回调所数自动调用,进行相关操作
2.监视的属性必须存在,才能进行监视!!
3.监视的两种写法:
(1).new Vue时传入watch配置
(2).通过vm.$watch监视
new Vue时传入watch配置
监听 ishot
数据属性的变化
watch:{
ishot:{
immediate:true,
handler(newValue,oldValue){
console.log(newValue,oldValue)
console.log('ishot被监视了,并且修改了')
}
}
}
immediate 选项:
当设置为 true
时,会在侦听器创建后立即调用 一次 handler,即使 ishot
的初始值没有变化也会触发,默认是 false
(只有在值变化时才触发)
handler 函数:
当 ishot
的值发生变化时会被调用,接收两个参数:newValue
:变化后的新值 oldValue
:变化前的旧值
通过vm.$watch监视
vm.$watch('ishot', {
immediate: true, // 初始化时立即调用 handler
handler(newValue, oldValue) {
console.log(newValue, oldValue);
console.log('ishot被监视了,并且修改了');
}
});
深度监视
(1).Vue中的watch默认不监测对象内部值的改变(一层)
(2).配置deep:true可以监测对象内部值改变(多层)。备注:
(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
(2).使用watch时根据数据的具体结构,决定是否采用深度监视。
这里有两个侦听器:一个专门监听 numbers.a
的变化,另一个监听整个 numbers
对象的变化
watch: {
// 专门监听 numbers.a 的变化
'numbers.a': {
handler(newValue, oldValue) {
console.log(newValue, oldValue);
console.log('number.a累加');
}
},
// 监听整个 numbers 对象的变化
numbers: {
deep: true, // 深度监听对象内部的变化
handler(newValue, oldValue) {
console.log(newValue, oldValue);
console.log('监测a,b的变化。');
}
}
}
监听嵌套属性 ('numbers.a') :
使用点号表示法可以监听嵌套对象的属性
只有当 numbers.a
的值发生变化时才会触发 handler
不需要 deep: true
,因为它只监听特定属性
监听整个对象 (numbers) :
当 numbers
对象本身被重新赋值时,或者对象内部的任何属性(包括嵌套属性)发生变化时都会触发
deep: true
是必需的,否则只会监听对象引用的变化,而不会监听对象内部属性的变化
deep 选项 :
当设置为 true
时,Vue 会递归监听对象内部所有属性的变化
默认是 false
(浅层监听)
注意事项 :
如果属性路径写错(如 'number.a'
而不是 'numbers.a'
),Vue 不会报错,但侦听器不会生效
深度监听 (deep: true
) 会带来性能开销,应谨慎使用
5.完整写法和简写
watch 完整写法和简写
watch:{
完整写法
'ishot':{
immediate:true,//初始化时让handler调用一下,及时刚刷新好,那个会输出
handler(newValue,oldValue){
console.log(newValue,oldValue)
console.log('ishot被监视了,并且修改了')
}
},
简写
ishot(newValue,oldValue){
immediate:true,//失效
console.log(newValue,oldValue)
console.log('ishot被监视了,并且修改了')
}
}
vm.$watch 完整写法和简写
vm.$watch('ishot',{
immediate:true,//初始化时让handler调用一下,及时刚刷新好,那个会输出
handler(newValue,oldValue){
console.log(newValue,oldValue)
console.log('ishot被监视了,并且修改了')
}
});
//简写
vm.$watch('ishot',function(newValue,oldValue){
console.log(newValue,oldValue)
console.log('ishot被监视了,并且修改了')
});
简写形式可以将handler当中的代码写入简写方式方法。但是不能将配置比如:immediate:true写入简写的方法。
三.computed和watch之向的区别
computed和watch之向的区别
1.computed能完成的功能,watch都可以完威。
2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
两个重要的小原则:
1.所被Vue管理的的数,最好写成普通函数,这样this的指向才是vm或组件实例对象。
2.所有不被Vue所管理的的数(定时器的回调的数、ajax的回调数等),最好写成箭头的数,这样this的指向才是vm或组件实例对象。
小贴士
1.一些特定的函数和写法会被 Vue 的响应式系统自动管理
1. 回调函数(Methods)
Vue 会自动管理在
methods
选项中定义的函数,使其内部的this
指向当前组件实例,并确保它们能访问响应式数据。2. 计算属性(Computed)的 Getter/Setter
在
computed
中定义的函数会被 Vue 自动转换为响应式的 getter/setter,依赖的响应式数据变化时会触发重新计算。3. 侦听器(Watch)的回调
在
watch
中定义的回调函数会被 Vue 管理,能访问组件实例,并在依赖变化时触发。4. 生命周期钩子
Vue 内置的生命周期钩子(如
created
、mounted
)会被自动调用,函数内的this
指向组件实例。5. 简写的箭头函数问题
⚠️ 注意 :如果使用箭头函数(如
methods: { handleClick: () => {} }
),this
不会指向组件实例,因为箭头函数绑定父级上下文。Vue 无法正确管理此类函数。2.计算属性的核心特性?
立即返回值:计算属性必须是一个同步函数,直接返回一个值。
缓存机制:只有当依赖的响应式数据变化时,计算属性才会重新计算,否则直接返回缓存的结果。
纯函数:计算属性不应有副作用(如修改外部状态、发起异步请求等)。
3.为什么计算属性不能包含异步操作?
设计限制 :计算属性的返回值必须是一个确定的值,而异步操作(如
setTimeout
或 API 请求)会导致返回值是undefined
或一个Promise
,这与计算属性的同步特性冲突。缓存失效:异步操作的非确定性(如网络延迟)会破坏计算属性的缓存机制,导致无法预测何时更新。
虽然
watch
的回调函数本身是由 Vue 管理的(例如,自动绑定this
上下文),但如果你在watch
的回调函数中使用定时器(如setTimeout
),这些定时器是由 JavaScript 引擎的事件循环机制管理的,而不是直接由 Vue 管理。
4.watch
回调由 Vue 管理Vue 会确保
watch
的回调函数中的this
指向当前组件实例。Vue 会自动追踪回调函数中使用的响应式依赖。