计算属性:
提供和data一样的属性页面调用语法规则,
但同时又能兼顾方法的自定义执行逻辑扩展( 计算属性的方法内部this指向于当前应用实例 )
计算属性的特性:
默认情况下计算属性构建的变量为只读变量,只能取值不能修改;
通过对象取值配置,可以实现计算属性的双向操作功能;
应用场景
1. 可以将页面的相关复杂执行逻辑定义于计算中,页面以属性调用的方式简化模板语法的定义
2. 通过计算属性的缓存规则,可以减少模板调用时对计算逻辑的执行的次数提供运行性能的提升
+ 计算属性独立存在没有使用价值的,程序开发中会和其它属性实现关联依赖开发,提供逻辑运算和缓存功能;
+ 计算属性的缓存是指在依赖变量未发生变换时,当前vue容器中多次使用不会重新执行方法,而是读取计算后的缓存结果
3. 通过计算属性的双向操作功能语法,可以将页面具有双向功能但逻辑不同的操作模拟成普通属性的双向功能
<div>
<p>username:{{ username }}</p>
<input type="text" v-model="username">
</div>
<script type="module">
import { createApp } from "../assets/vue/3.0/vue.esm-browser.js";
createApp({
data() {
return {
info: "data属性info",
size: -1,
str: "a",
_username:"测试数据"
}
},
// 带有方法运行和计算功能的数据仓库 - 计算属性
computed: {
// key 属性名,value是执行方法,但必须存在return提供属性返回值
msg: function () {
return "计算属性msg"
},
// key定义计算属性的属性名
// valeu 取值 { get:Fuction,set:Fuction } ,用于构建计算的双向操作功能
// username(){
// return "字符串"
// }
username:{
get:function(){
// 计算属性的取值操作
return this._username
},
set:function(nv){
// 计算属性的赋值操作
console.log(nv);
this._username = nv;
}
}
当需要计算的变量为循环时的临时变量,此时计算功能只能由方法提供
<!-- 当需要计算的变量为循环时的临时变量,此时计算功能只能由方法提供 -->
<ul>
<li v-for="(i) in arr">{{num(i)}}</li>
</ul>
methods: {
num(num){
return num*100+"%"
}
},
5.2、侦听器 (监视器) (watch)
key 定义和描述需要监听的变量名(data,computed,……)
value 取值Function,为被监听的变量提供变换时的主动触发函数
该方法具有两个固定形参,分别是变化后的值和变化前的值
watch:{
// key 定义和描述需要监听的变量名(data,computed,……)
// value 取值Function,为被监听的变量提供变换时的主动触发函数
// 该方法具有两个固定形参,分别是变化后的值和变化前的值
msg:function(nv,ov){
console.log("watch-msg变量发生变换",nv,ov);
},
}
watch 监视器构建时 key可以定义取值表达式(仅支持.号取值),表示需要监控的变量和层级
key取值表达式具有特殊功能的操作,只在vue监视器中有效
// watch 监视器构建时 key可以定义取值表达式(仅支持.号取值),表示需要监控的变量和
层级
// key取值表达式具有特殊功能的操作,只在vue监视器中有效
"user.name":function(nv,ov){
console.log("watch-user.name变量发生变换",nv,ov);
},
//以下方法不可行
// "user['age']":function(nv,ov){
// console.log("watch-user.age变量发生变换",nv,ov);
// }
vue的watch监视器构建的引用数据监控,默认为浅监控,使用时需要转换为深监控
watch 监视器构建时 value取值固定对象结构 { handler:Function,deep:Boolean }
handler 监控数据发生变换时的回调方法
deep 为监控深度的描述 默认为false(浅监控)
// watch 监视器构建时 value取值固定对象结构 { handler:Function,deep:Boolean }
// handler 监控数据发生变换时的回调方法
// deep 为监控深度的描述 默认为false(浅监控)
watch:{
arr:{
handler(nv,ov){
console.log("watch-arr变量发生变换",nv,ov);
},
deep:true // 开启深度监控
},
}
watch 监视器构建时,value取值固定对象 { handler:Function,immediate:Boolean },实现在页面第一次运行时执行方法
immediate 默认值false , 页面首次加载不会执行该监视方法,为true时,页面加载则会执行监视
// watch 监视器构建时,value取值固定对象 { handler:Function,immediate:Boolean
},实现在页面第一次运行时执行方法
// immediate 默认值false , 页面首次加载不会执行该监视方法
watch:{
info:{
handler(nv,ov){
console.log("watch-info=变量发生变换",nv,ov);
},
immediate:true
}
}
出现上面原因,前后值相同是因为只改变了数组里面的内容,对地址没变,所以前后值相同,如果是整个数组都被改变了,则前后值不同
面试题:vue中如何同时对多个变量定义统一监控方法?
方式1:通过计算属性
方式2:通过$watch完成监控
<!--
vue也可以构建可控监视器(vue应用外构建方案)
+ 通过vue提供的应用实例方法 $watch 完成变量监视器的定义
+ $watch定义的监视器会返回一个 关闭该监视器的回调方法
vue变量监视器可以累加,而每次通过$watch返回监控解绑方法是相互独立
vue实例.$watch(expOrFn, callback, [options])
+ expOrFn : 接收被监控的变量的名称 或者 和监控变量有关的方法
+ 定义字符串表达式时,等效于对变量直接完成监控控制
+ 定义方法且方法返回值绑定了相关变量,等同于对绑定的所有变量统一完成监控(expOrFn取值可以是方法构建多变量统一监控)
+ callback : 变量发生变化时执行的回调函数
+ options : 取值 Object ,用于定义除handler以外的其它监视配置(深度监控,初始调用……可选项)
-->
// 在应用根属性上添加一个用于中转,但不需要劫持的变量数据 - 为其他区域提供调用支持
// 这种中转数据变量 在vue 开发规范中建议 以 $ 开头(非仓库中的数据,在实例构建上均以$符开头),实现和普通劫持变量的区分,防止污染
<div id="app">
<p>num1:{{ num1 }}</p>
<input type="number" v-model.number="num1">
<p>num2:{{ num2 }}</p>
<input type="number" v-model.number="num2">
<p>求和:{{ num1+num2 }}</p>
<p>求和:{{ sum }}</p>
<hr>
<p>msg:{{ msg }}</p>
<input type="text" v-model="msg">
<br>
<input type="button" value="绑定msg监视" @click="addWatch()">
<input type="button" value="解绑msg监视" @click="removeWatch()">
<hr>
<p>num3:{{ num3 }}</p>
<input type="number" v-model.number="num3">
<p>num4:{{ num4 }}</p>
<input type="number" v-model.number="num4">
<p>求和:{{ num3+num4 }}</p>
<input type="button" value="绑定num3+num4求和监视" @click="addNumWatch()">
</div>
<script type="module">
import { createApp } from "../assets/vue/3.0/vue.esm-browser.js";
var vm = createApp({
data() {
return {
num1: 10,
num2: 20,
num3: 30,
num4: 40,
msg: "msg",
}
},
computed: {
sum() {
return this.num1 + this.num2
}
},
watch: {
sum(nv, ov) {
console.log("num1+num2求和结果变化:", nv, ov);
}
},
methods: {
addWatch() {
// 在应用根属性上添加一个用于中转,但不需要劫持的变量数据 - 为其他区域提供调用支持
// 这种中转数据变量 在vue 开发规范中建议 以 $ 开头,实现和普通劫持变量的区分
if(this.$unwatch) return;
this.$unwatch = this.$watch("msg", (nv, ov) => {
console.log("$watch 监控的msg发生变化", nv, ov);
})
console.log(this.$unwatch);
console.log(this);
},
removeWatch(){
// 方法转换成布尔类型,是true,方法不存在的话是undefined,相当于false,
/* if(!this.$unwatch){
return
} */
if(!this.$unwatch) return; //ES5中,程序中只有一行代码,大括号可以省略,但是不能换行
this.$unwatch(); // $watch过会返回一个方法函数,该方法函数被执行后会解绑
当前监控器
this.$unwatch = undefined/null; // 解绑以后,this.unwatch依然存在,须重置为重新绑定的取值上,设置为null或者undefined
},
addNumWatch() {
this.$watch(
() => {
// return this.num3+this.num4
// return [this.num3,this.num4]
return {
num3:this.num3,
num4:this.num4
}
},
(nv, ov) => {
// console.log("$watch 监控的num3+num4发生变化", nv, ov);
// console.log("$watch 监控的[num3,num4]发生变化", nv, ov);
console.log("$watch 监控的{num3,num4}发生变化", nv, ov);
}
)
}
}
}).mount("#app")