vue计算属性和监听属性的区别是什么

总结:

  1. 计算属性computed在使用时,一定要注意,函数里面的变量都会被监听,只要里面的某一个值变动,便会将整个函数执行一遍。 而 watch 只是监听某一个值,若是监听的值里面也有很多变量,也会全部监听
  2. 计算后的属性可不在 data 中定义,如果定义会报错,因为对应的computed作为计算属性定义并返回对应的结果给这个变量,变量不可被重复定义和赋值。  而 watch 监听 data 中定义的变量变化

computed特性
1.是计算值,
2.应用:就是简化tempalte里面{{}}计算和处理props或$emit的传值
3.具有缓存性,页面重新渲染值不变化,计算属性会立即返回之前的计算结果,而不必再次执行函数

watch特性
1.是观察的动作,
2.应用:监听props,$emit或本组件的值执行异步操作
3.无缓存性,页面重新渲染时值不变化也会执行

接下来介绍下 各自的方法:

1. 计算属性 computed

在一个计算属性里可以完成各种复杂的逻辑,包括运算、函数调用等,只要最终返回一个结果就可以。

  <div id="example">
        <p>Original message: "{{ message }}"</p>
        <p>Computed reversed message: "{{ reversedMessage }}"</p> // 我们把复杂处理放在了计算属性里面了    </div>
var vm = new Vue({
    el: '#example',
    data: {
        message: 'Hello'
    },
    computed: {
        reversedMessage: function () {
            // `this` 指向 vm 实例
            return this.message.split('').reverse().join('')
        }
    }});

结果:
       Original message: "Hello"
  Computed reversed message: "olleH"

计算属性还可以依赖多个Vue 实例的数据,只要其中任一数据变化,计算属性就会重新执行,视图也会更新。

每一个计算属性都包含一个getter和一个setter ,我们上面的两个示例都是计算属性的默认用法, 只是利用了getter 来读取。

在你需要时,也可以提供一个setter 函数, 当手动修改计算属性的值就像修改一个普通数据那样时,就会触发setter 函数,执行一些自定义的操作,例如:

    <div id="demo">
        <p> {{ fullName }} </p>
        <input type="text" v-model="fullName">
        <input type="text" v-model="firstName">
        <input type="text" v-model="lastName">
    </div>
    <script>
        var vm = new Vue({
            el: '#demo',
            data: {
                firstName: 'zhang',
                lastName: 'san'
            },
            computed: {
                fullName: {
                    //getter 方法
                    get(){
                        console.log('computed getter...')
                        return this.firstName + ' ' + this.lastName
                    },
                    //setter 方法
                    set(newValue){
                        console.log('computed setter...')
                        var names = newValue.split(' ')
                        this.firstName = names[0]
                        this.lastName = names[names.length - 1]
                        return this.firstName + ' ' + this.lastName
                    }
                
                }
            },
            updated () {
                console.log('updated')
            }
        })    </script>

我们可以看到,input 是直接绑 v-model="fullName",如果我们这里直接修改了fullName的值,那么就会触发setter,同时也会触发getter以及updated函数。其执行顺序是setter -> getter -> updated,如下:

console.log('computed setter...')console.log('computed getter...')console.log('updated')

注意:并不是触发了setter也就会触发getter,他们两个是相互独立的。我们这里修改了fullName会触发getter是因为setter函数里有改变firstName 和 lastName 值的代码。

2. 方法

除了使用计算属性外,我们也可以通过在表达式中调用方法来达到同样的效果,如:

  <div>{{reverseTitle()}}</div>
methods: {
  reverseTitle: function () {
    return this.title.split('').reverse().join('')
  }}

我们可以将同一函数定义为一个方法而不是一个计算属性,两种方式的最终结果确实是完全相同的。只是一个使用reverseTitle()取值,一个使用reverseTitle取值。

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

这就意味着只要 title还没有发生改变,多次访问 reverseTitle计算属性会立即返回之前的计算结果,而不必再次执行函数。

3. 侦听属性 watch

watch监控自身属性变化:

   new Vue({
        el: '#app',
        data: {
            firstName: 'hello',
            lastName: 'vue',
            fullName: 'hello.ve'
        },
        watch: {
            'firstName': function(newval, oldval) {
                // console.log(newval,oldval);
                this.fullName = this.firstName + this.lastName;
            },
            'lastName': function(newval, oldval) {
                // console.log(newval,oldval);
                this.fullName = this.firstName + this.lastName;
            }
        }
    });

watch监控路由对象:

    new Vue({
        el: '#app',
        router: router, //开启路由对象
        watch: {
            '$route': function(newroute, oldroute) {
                console.log(newroute, oldroute);
                //可以在这个函数中获取到当前的路由规则字符串是什么
                //那么就可以针对一些特定的页面做一些特定的处理
            }
        }
    })

watch监听对象的单个属性:
watch如果想要监听对象的单个属性的变化,必须用computed作为中间件转化,因为computed可以取到对应的属性值。

data(){
      return{
        'first':{
          second:0
        }
      }
    },
    computed:{
      secondChange(){
        return this.first.second      }
    },
    watch:{
      secondChange(){
        console.log('second属性值变化了')
      }
    },

简单实现 computed和watch

公共类

function defineReactive(data, key, val, fn) {
      let subs = [] // 新增
      Object.defineProperty(data, key, {
        configurable: true,
        enumerable: true,
        get: function() {
          // 新增
       if (data.$target) {
        subs.push(data.$target)
      }
      return val     },
     set: function(newVal) {
      if (newVal === val) return
      fn && fn(newVal)
      // 新增
      if (subs.length) {
        // 用 setTimeout 因为此时 this.data 还没更新
        setTimeout(() => {
          subs.forEach(sub => sub())
        }, 0)
      }
      val = newVal    },
   })
 }

computed实现

function computed(ctx, obj) {
  let keys = Object.keys(obj)
  let dataKeys = Object.keys(ctx.data)
  dataKeys.forEach(dataKey => {
    defineReactive(ctx.data, dataKey, ctx.data[dataKey])
  })
  let firstComputedObj = keys.reduce((prev, next) => {
    ctx.data.$target = function() {
      ctx.setData({ [next]: obj[next].call(ctx) })
    }
    prev[next] = obj[next].call(ctx)
    ctx.data.$target = null
    return prev  }, {})
  ctx.setData(firstComputedObj)}

watch实现

function watch(ctx, obj) {
  Object.keys(obj).forEach(key => {
    defineReactive(ctx.data, key, ctx.data[key], function(value) {
      obj[key].call(ctx, value)
    })
  })}


郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: