Vue的动态数据计算

我自己很笨,学习编程也是一点一点啃,总是把在别人看起来很简单的一个问题,自己都要反复琢磨好多遍,特别是有时候啃官方文档的时候,出现一些比较绕口的词,我怎么也不能理解,所以我就会不停的反问自己,你真的理解这个词吗?之后就会琢磨好久,用自己能理解的语言写出来,并记录下来!

如果,我分享的对您有帮助,那么我们一起进步,点赞随缘,收藏随心!

什么是动态数据?

发挥一下阅读理解能力,动态数据应该指的就是不断变化的数据,非固定一成不变的数据!

常见的几种场景

  • 商城种常见的购物车数据就是不断变化的
  • 购买商品支付的金额会根据选购的数量不断变化
  • 字符串实时拼接等

vue实现这种需求有四种方式

1.JavaScript表达式

vue提供了一种非常方便的操作,模板语法{{}}可以使用单一的JavaScript表达式,但只适合简单的需求(比如字符串拼接),稍微复杂的需求不建议试用!

  • 例子 - 反转字符串:
<div id="example">
	{{ message.split('').reverse().join('') }}
</div>
    
    <script type="text/javascript">
      
      const app = new Vue({
        el: "#example",
        data:{
          message: '我是一个例子!'
        }
      })
      
    </script>

上边的反转字符串我们也可以通过定义一个方法来实现,但是这种简单的需求单独定义个方法又是大材小用了!

2.method方法

那么,假如我们有一个购物车的需求,我们要根据商品的价格和数量来计算出总价的时候,这个场景就相对复杂了,就可以使用这种方法!

<div id="app">
	<ul>
		<li v-for="(item, index) in books" :key="index">
			<span>名称:{{item.name}}</span>
			<span>价格:{{item.price.toFixed(2)}}</span>
			<span>数量:{{item.num}}</span>
			<br>
			<input type="button" value="+" @click="item.num += 1">
			<input type="button" value="-" @click="item.num -= 1">
		</li>
	</ul>
    
	<p>总价:{{totalPrice()}}</p>
</div>
    
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    books: [
                        {
                            name: 'Android',
                            price: 12.00,
                            num: 0
                        },{
                            name: 'IOS',
                            price: 13.00,
                            num: 0
                        },{
                            name: 'javaScript',
                            price: 14.00,
                            num: 0
                        },
                    ],
                    // totalPrice: 0.00
                },
                
                methods:{
                  totalPrice: function(){
                    var result = 0
                    // forEach()获得数组的每个元素,参数为一个回调函数
                    this.books.forEach(book => {
                      result += book.price * book.num;
                    });
                    return result;
                  }
                }
            });
        </script>

我们通过定义了一个方法实现了购物车基本的运算,但是我们发现,每进行一次计算,一旦触发了页面的重新渲染,totalPrice()方法都要执行一次,我们重新写个点击事件来验证下!在以上代码中添加,如图:

<h1>验证</h1>
<p>{{testData}}</p>
<input type="button" value="test" @click="testMethod()">
复制代码

 

testMethod: function(){
	console.log('testMethod');
	this.testData += 1
},
复制代码

data中别忘了声明testData属性,点击这个事件我们来验证下!

点击之后我们发现,只要我们定义的这个testMethod方法触发一次页面渲染,totalPrice方法也要跟着执行一次,那么,如果我们这个页面有很多操作事件,每一次触动渲染,它都跟着执行一次,就会造成很多性能浪费,此时,这个带有缓存功能的计算属性computed就很好的解决了这个问题!

3.computed属性

计算属性是基于它们的响应式依赖进行缓存的,只在相关响应式依赖发生改变时它们才会重新求值。

这句话什么意思呢?以刚才我们验证totalPrice方法只要有方法触发了dom的实时渲染,他都要跟着执行一次,变成现在他自己缓存起来,只要他自身不改变不触发dom渲染,你执行别的方法,它就不会再受影响!

如何定义,计算属性?

如图所示: 计算属性computed与mefthods是同级,将我们在methods中定义的totalProice方法移到computed中,名称改为totalProice1。

在data中声明一个totalProice属性,如下图:

将总价中模板语法渲染改为{{ totalPricel }}

此时,我们再去执行testMethod方法就不会影响到他的计算值!如下图:

这就是computed计算属性解决的问题!

计算属性的getter和setter方法

computed 提供了一个 gettersetter 方法,默认情况下,我们只需要关注 computedgetter 方法,看看官网给出的例子,拼接字符串:

<div id="app">
      {{ fullname }}
</div>
    
    <script>
      var app = new Vue({
        el: '#app',
        data:{
          firstName: '刘',
          lastName: '德华'
        },
        computed:{
          fullname: function(){
            return this.firstName + this.lastName
          }
        }
      })
    </script>

同样可以试用computedgetter方法实现,getter方法可以简写成get

computed: {
    fullName: {
        // getter
        get: function () {
         return this.firstName + ' ' + this.lastName
        },
    }
}

 

可以发现运行的结果是一样的,同时也可以去重写它的 setter 方法,如下:

computed: {
    fullName: {
        // getter
        get: function () {
         console.log('get方法');
         return this.firstName + ' ' + this.lastName
        },
        // setter
        set: function (newValue) {
            console.log('set方法:' + newValue);
            var names = newValue.split(' ')
            this.firstName = names[0]
            this.lastName = names[names.length - 1]
        }
    }
}

 

当在控制台去执行app.fullName = 'The Vue'的时候,Vue 会先调用 setter 方法为 firstName 和 lastName 赋值,然后执行 getter 方法,来返回 fullName。

4.watch属性

watch属性又叫侦听属性,顾名思义它具有时刻监听数据的作用!

当你有一些数据(结果数据)需要随着其他数据(目标数据)变动而变动时,可以使用 watch 来监听目标数据的变化,当目标数据发生变化时,Vue 会回调我们的监听事件。

注释掉,上一步定义的computed,添加如下代码,这就是watch的定义方式,需要监听哪个数据就位那个数据定义一个回调函数!

watch:{
	books:{
		handler: function(val, oldval){
			this.totalPrice = 0;
			val.forEach(item => {
				this.totalPrice += item.num * item.price;
			});
		},
		deep: true,
	}
},
侦听器

上例中,使用 watch 属性来对 books 进行数据监听,当 books 发生数据变化时,会回调 handler 方法,handler 方法接收两个参数监听数据的当前值(val),监听数据变化之前的值(注意:当监听的数据为对象或数组时,val 和 oldVal 是相等的,因为这两个引用指向同一块内存空间),这样就可以在回调方法 handler 来计算 totalPrice。

侦听器能实现的效果很多时候都可以用计算属性来实现,那为什么还要定义这样一个方法呢,官方给的说法是:当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

意思是应用场景主要在:异步操作性能开销较大时采用!

我们用刚才的例子加一个定时器,模拟下异步操作,改造handler回调方法!

watch: {
   books: {
        // 监听到数据变化之后的回调方法
        handler:function(val,oldval){
            this.totalPrice = '计算中...';

            var $this = this;
            setTimeout(() => {
                $this.totalPrice = 0;
                val.forEach(item => {
                    $this.totalPrice += item.num * item.price;
                });
            }, 1000);
        },
        deep:true// 对象内部的属性监听,也叫深度监听

    }
},

 

通过上边的模拟异步请求,实现了一个计算中的效果!

四种方式的对比

截止到这里就已经了解了 Vue 中进行动态数据计算的所有方式了,我们把这些方式进行一个总结。

(1)JavaScript 表达式:方法最为简单,不需要学习新的属性和概念就可以直接使用,但是它只有简单的运用场景(比如,简单的字符串拼接),当应用常见变得复杂的时候(如购物车)这种方式就不在适用了。

(2)method 方法:method 方法的形式可以帮助我们应对一个复杂的场景,当页面重新渲染的时候,method 方法每次都会执行。如果页面有大量的渲染动作,并且大量的渲染动作与动态数据计算无关的话,使用这种方式会带来一定的性能浪费。

(3)watch 属性:使用 watch 属性可以对数据进行监听,当被监听的数据发生变化的时候,对应的数据监听方法会被调用,watch 属性同样可以帮助我们应对一个复杂的操作,并且可以提供异步的事件处理。当需要监听一个目标数据的变化时,这种方式是一种非常好的选择,同时如果目标数据有多个 (firstName、lastName),多个目标数据共同影响一个结果数据的话 (fullName),这种监听方式会让人觉得比较奇怪。

这里可以参考官方解释:cn.vuejs.org/v2/guide/co…

(4)computed 属性:computed 属性也是 Vue 中大力推广的一个特性,它会通过声明的方式来确定依赖的关系,只有依赖数据发生响应式变化的时候,才会调用 computed 属性的 getter 方法,并且 computed 属性默认提供了缓存机制,如果依赖数据并没有发生响应式变化,computed 属性不会重新计算,而只是读取缓存数据。

如何选择用那种: 选择那种方式实现,取决于面对了什么样的问题。