2.4.1、插值语法实现反转字符串
<body><!-- 需求:用户输入字符串,然后反转展示在页面中 --><div id="app"><h1>{{msg}}</h1>输入的信息:<input type="text" v-model="info" /> <hr /><!--直接写在插值语法中,有以下三个问题:1. 可读性差。2. 代码没有得到复用。3. 难以维护。-->反转的信息:{{info.split('').reverse().join('')}} <hr />反转的信息:{{info.split('').reverse().join('')}} <hr />反转的信息:{{info.split('').reverse().join('')}} <hr /></div><script>const vm = new Vue({el: "#app",data: {msg: "插值语法-反转字符串案例",info: "",},});</script></body>
vue官网中说:
模版内的表达式以及指令语法非常便利,但设计他们的初衷是用于简单运算,在模版中放入太多的逻辑会让模版过重且难以维护
2.4.2、方法实现反转字符串
<body><div id="app"><h1>{{msg}}</h1>输入的信息:<input type="text" v-model="info" /> <br /><!-- 在插值语法中可以调用方法,小括号不能省略。这个方法需要是Vue实例所管理的。 -->反转的信息:{{reverseInfo()}} <br /><!-- 缺点:效率有问题 会重复调用 -->反转的信息:{{reverseInfo()}} <br />反转的信息:{{reverseInfo()}} <br />反转的信息:{{reverseInfo()}} <br /></div><script>const vm = new Vue({el: "#app",data: {msg: "计算属性-反转字符串案例",info: "",},methods: {// 反转信息的方法reverseInfo() {return this.info.split("").reverse().join("");},},});</script></body>
2.4.3、计算属性实现反转字符串
1. 什么是计算属性?
使用Vue的原有属性,经过一系列的运算/计算,最终得到了一个全新的属性,叫做计算属性。
Vue的原有属性: data对象当中的属性可以叫做Vue的原有属性。
全新的属性: 表示生成了一个新的属性,和data中的属性无关了,新的属性也有自己的属性名和属性值。
2. 计算属性的作用?
代码得到了复用。
代码更加便于维护了。
代码的执行效率高了。
3. 计算属性怎么用?
语法格式:
computed : {// 这是一个计算属性,可以有多个计算属性
计算属性1 : {
// 当读取计算属性1的值的时候或该计算属性所关联的Vue原有属性的值发生变化时,getter方法被自动调用。
get(){},
// 当修改计算属性1的值的时候,setter方法被自动调用。
set(val){}
},
计算属性2 : {},
}
(1)计算属性需要使用新的配置项:computed
(2)计算属性通过vm.$data ,vm._data 是无法访问的。
(3)计算属性的getter/setter方法中的this是vm。
(4)计算属性的getter方法的调用时机:
①第一个时机:初次访问该属性。
②第二个时机:计算属性所依赖的数据发生变化时。
(5)计算属性的setter方法的调用时机:
①当计算属性被修改时。(在setter方法中通常是修改属性,因为只有当属性值变化时,计算属性的值就会联动更新。注意:计算属性的值被修改并不会联动更新属性的值。)
(6)计算属性没有真正的值,每一次都是依赖data属性计算出来的。
(7)计算属性的getter和setter方法不能使用箭头函数,因为箭头函数的this不是vm。而是window。
<body><div id="app"><h1>{{msg}}</h1>输入的信息:<input type="text" v-model="info" /> <br />反转的信息:{{reversedInfo}}<br />反转的信息: <input type="text" v-model="reversedInfo" /><!-- 多次调用计算属性,只会执行一次,效率高 -->{{fun}} <br /><!-- {{fun}} <br />{{fun}} <br />{{fun}} <br />{{fun}} <br /> --><!-- 多次调用方法,每次都是执行,效率低 --><!-- {{hello()}} <br />{{hello()}} <br />{{hello()}} <br />{{hello()}} <br />{{hello()}} <br /> --></div><script>const vm = new Vue({el: "#app",data: {msg: "计算属性-反转字符串案例",info: "",},methods: {hello() {console.log("hello方法执行了");return "hello";},},computed: {// 可以定义多个计算属性fun: {// get方法的调用时机get() {console.log("getter方法调用了");//console.log(this === vm)return "haha" + this.info;},// 不能使用箭头函数,使用箭头函数会导致this的指向是:window// get:()=>{// console.log('getter方法调用了')// console.log(this === vm)// return 'haha'// },set(val) {console.log("setter方法调用了");//console.log(this === vm)},},// 完整写法/* reversedInfo : { get(){return this.info.split('').reverse().join('')},// 当修改计算属性的时候,set方法被自动调用。set(val){//console.log('setter方法被调用了。')// 不能这么更改计算属性的值,这样做就递归了。//this.reversedInfo = val// 怎么修改计算属性呢?原理:计算属性的值变还是不变,取决于计算属性关联的Vue原始属性的值。// 也就是说:reversedInfo变还是不变,取决于info属性的值变不变。// 将值赋给info,通过info来实现反推修改,//例如,需要将翻转值修改为hello,则需要反转给info,通过info再反转回来// 本质上:修改计算属性,实际上就是通过修改Vue的原始属性来实现的。this.info = val.split('').reverse().join('')}} */// 简写形式:set不需要的时候。reversedInfo() {return this.info.split("").reverse().join("");},},});</script></body>
4、计算属性的简写形式
只考虑读取,不考虑修改时,可以启用计算属性的简写形式。
1. computed : {
2. reversedInfo(){
3. console.log('getter被调用了');
4. return this.info.split('').reverse().join('')
5. }
6. }
2.5、侦听属性
2.5.1、侦听属性作用
侦听属性的变化其实就是监视某个属性的变化。当被监视的属性一旦发生改变时,执行某段代码。
2.5.2、watch配置项
监视属性变化时需要使用watch配置项
可以监视多个属性,监视哪个属性,请把这个属性的名字拿过来即可。
i.可以监视Vue的原有属性
ii.如果监视的属性具有多级结构,一定要添加单引号:'a.b'
iii.无法直接监视对象深层次属性,如a.b,b属性压根不存在。
iv.启用深度监视,默认是不开启深度监视的。
v.也可以监视计算属性
2.5.3、如何深度监视:
(1) 监视多级结构中某个属性的变化,写法是:’a.b.c’ : {}。注意单引号哦。
(2) 监视多级结构中所有属性的变化,可以通过添加深度监视来完成:deep : true
2.5.4、 如何后期添加监视:
(1) 调用API:vm.$watch(‘number1’, {})
2.5.5、 watch的简写:
(1) 简写的前提:当不需要配置immediate和deep时,可以简写。
(2) 如何简写?
① watch:{
number1(newVal,oldVal){},
number2(newVal, oldVal){}
}
(3) 后期添加的监视如何简写?
① vm.$watch(‘number1’, function(newVal, oldVal){})
<body><div id="app"><h1>{{msg}}</h1>数字:<input type="text" v-model="number" /><br />数字:<input type="text" v-model="a.b" /><br />数字:<input type="text" v-model="a.c" /><br />数字:<input type="text" v-model="a.d.e.f" /><br />数字(后期添加监视):<input type="text" v-model="number2" /><br /></div><script>const vm = new Vue({el: "#app",data: {msg: "侦听属性的变化",// 原有属性number: 0,// 多层次属性a: {b: 0,c: 0,d: {e: {f: 0,},},},number2: 0,},// 计算属性computed: {hehe() {return "haha" + this.number;},},watch: {//1、可以监视多个属性,监视哪个属性,请把这个属性的名字拿过来即可。//1.1 可以监视Vue的原有属性/* number : {// 初始化的时候,调用一次handler方法。immediate : true,// 这里有一个固定写死的方法,方法名必须叫做:handler// handler方法什么时候被调用呢?当被监视的属性发生变化的时候,handler就会自动调用一次。// handler方法上有两个参数:第一个参数newValue,第二个参数是oldValue// newValue是属性值改变之后的新值。// oldValue是属性值改变之前的旧值。handler(newValue, oldValue){console.log(newValue, oldValue)// this是当前的Vue实例。// 如果该函数是箭头函数,这个this是window对象。不建议使用箭头函数。console.log(this)}}, *///1.2 如果监视的属性具有多级结构,一定要添加单引号:'a.b'/* 'a.b' : { handler(newValue, oldValue){console.log('@')} },'a.c' : { handler(newValue, oldValue){console.log('@')} }, */// 无法监视b属性,因为b属性压根不存在。/* b : { handler(newValue, oldValue){console.log('@')} } *///1.3 启用深度监视,默认是不开启深度监视的。a: {// 什么时候开启深度监视:当你需要监视一个具有多级结构的属性,并且监视所有的属性,需要启用深度监视。deep: true,handler(newValue, oldValue) {console.log("@");},},//1.4 也可以监视计算属性/* hehe : {handler(a , b){console.log(a, b)}} *///2、 监视某个属性的时候,也有简写形式,什么时候启用简写形式?// 当只有handler回调函数的时候,可以使用简写形式。number(newValue, oldValue) {console.log(newValue, oldValue);},},});//3、 如何后期添加监视?调用Vue相关的API即可。//3.1 语法:vm.$watch('被监视的属性名', {})/* vm.$watch('number2', {immediate : true,deep : true,handler(newValue, oldValue){console.log(newValue, oldValue)}}) *///3.2 这是后期添加监视的简写形式。vm.$watch("number2", function (newValue, oldValue) {console.log(newValue, oldValue);});</script></body>
2.5.6. computed和watch如何选择?
比大小的案例
2.5.6.1、watch实现
<body><div id="app"><h1>{{msg}}</h1>数值1:<input type="number" v-model="num1" /><br />数值2:<input type="number" v-model="num2" /><br />比较大小:{{compareResult}}</div><script>const vm = new Vue({el: "#app",data: {msg: "比较大小的案例",num1: 0,num2: 0,compareResult: "",},watch: {// 监视num1num1: {immediate: true,handler(val) {let result = val - this.num2;if (result == 0) {this.compareResult = val + " = " + this.num2;} else if (result > 0) {this.compareResult = val + " > " + this.num2;} else {this.compareResult = val + " < " + this.num2;}},},// 监视num2num2: {immediate: true,handler(val) {let result = this.num1 - val;if (result == 0) {this.compareResult = this.num1 + " = " + val;} else if (result > 0) {this.compareResult = this.num1 + " > " + val;} else {this.compareResult = this.num1 + " < " + val;}},},},});</script></body>
2.5.6.2、computed实现
<body><div id="app"><h1>{{msg}}</h1>数值1:<input type="number" v-model="num1" /><br />数值2:<input type="number" v-model="num2" /><br />比较大小:{{compareResult}}</div><script>const vm = new Vue({el: "#app",data: {msg: "比较大小的案例",num1: 0,num2: 0,},computed: {// 计算属性的简写形式compareResult() {let result = this.num1 - this.num2;if (result == 0) {return this.num1 + " = " + this.num2;} else if (result > 0) {return this.num1 + " > " + this.num2;} else {return this.num1 + " < " + this.num2;}},},});</script></body>
2.5.6.3、总结
(1) 以上比较大小的案例可以用computed完成,并且比watch还要简单。所以要遵守一个原则:computed和watch都能够完成的,优先选择computed。
(2) 如果要开启异步任务,只能选择watch。因为computed依靠return。watch不需要依赖return。
比较大小的案例:延迟3s出现结果
watch: {// 监视num1num1: {immediate: true,handler(val) {let result = val - this.num2;// 需求2:3s后出现比较结果// 此时使用箭头函数,箭头函数没有this,会向上找到num1,num1是vm的属性,// 如果将此时箭头函数转成普通函数,this就会是windowsetTimeout(() => {if (result == 0) {this.compareResult = val + " = " + this.num2;} else if (result > 0) {this.compareResult = val + " > " + this.num2;} else {this.compareResult = val + " < " + this.num2;}}, 3000);},},// 监视num2num2: {immediate: true,handler(val) {let result = this.num1 - val;setTimeout(() => {if (result == 0) {this.compareResult = this.num1 + " = " + val;} else if (result > 0) {this.compareResult = this.num1 + " > " + val;} else {this.compareResult = this.num1 + " < " + val;}}, 3000);},},},
computed: {// 计算属性的简写形式// 计算结果3s后显示,由于setTimeout是异步的,是有js引擎调用的,所以它的this是window,可以使用箭头函数compareResult() {setTimeout(() => {let result = this.num1 - this.num2;if (result == 0) {return this.num1 + " = " + this.num2;} else if (result > 0) {return this.num1 + " > " + this.num2;} else {return this.num1 + " < " + this.num2;}}, 3000);},
2.5.7. 关于函数的写法,写普通函数还是箭头函数?
(1) 不管写普通函数还是箭头函数,目标是一致的,都是为了让this和vm相等。
(2) 所有Vue管理的函数,建议写成普通函数。
(3) 所有不属于Vue管理的函数,例如setTimeout的回调函数、Promise的回调函数、AJAX的回调函数,建议使用箭头函数。