vue计算属性computed和侦听器watch用法

1.计算属性

计算属性例子:

<template>
  <div>
    <p>消息内容:{{message}}<br>转换后的内容{{reMessage}}</p>
  </div>
</template>
<script>
export default {
  data() {
    return {
      message: "Hello World"
    };
  },
  computed: {
    reMessage: function() {
      return this.message.split("").reverse().join("");
    }
  }
};
</script>

显示结果:
在这里插入图片描述
注释:上述例子中,我们声明了一个计算属性reMessage,我们提供的函数将用作属性reMessage的getter函数,reMessage的值变化始终取决于message的值,当message发生变化时,所有依赖reMessage的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系:计算属性的 getter 函数是没有副作用 (side effect) 的,这使它更易于测试和理解。

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

计算属性的setter

计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter :
如下例子:

<template>
  <div>
      我的firstname是:{{firstName}}<br>
      我的lastname是:{{lastName}}<br>
       <!--我的全名是:{{fullName}}-->
      我的全名是:{{fullName='jack lisa'}}
  </div>
</template>
<script>
export default {
  data() {
    return {
        firstName:'Jone',
        lastName:"coco"
    };
  },
  computed: {
      fullName:{
          get:function(){
              return this.firstName+this.lastName;
          },
          set:function(v){
              var names=v.split(' ');
              this.firstName=names[0];
              this.lastName=names[names.length-1];
          }
      }
  }
};
</script>

上述例子,输出结果为:
在这里插入图片描述
上述例子中如果给fullName赋值,则会调用setter,如果不赋值则会调用getter,同时,他们的firstName和lastName也会被响应更新。

2.侦听器

Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。

虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
如下例子:

<div id="watch-example">
  <p>
    Ask a yes/no question:
    <input v-model="question">
  </p>
  <p>{{ answer }}</p>
</div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
  el: '#watch-example',
  data: {
    question: '',
    answer: 'I cannot give you an answer until you ask a question!'
  },
  watch: {
    // 如果 `question` 发生改变,这个函数就会运行
    question: function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.debouncedGetAnswer()
    }
  },
  created: function () {
    // `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
    // 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
    // AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
    // `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
    // 请参考:https://lodash.com/docs#debounce
    this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
  },
  methods: {
    getAnswer: function () {
      if (this.question.indexOf('?') === -1) {
        this.answer = 'Questions usually contain a question mark. ;-)'
        return
      }
      this.answer = 'Thinking...'
      var vm = this
      axios.get('https://yesno.wtf/api')
        .then(function (response) {
          vm.answer = _.capitalize(response.data.answer)
        })
        .catch(function (error) {
          vm.answer = 'Error! Could not reach the API. ' + error
        })
    }
  }
})
</script>

在这里插入图片描述
在这个示例中,使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

如下简单的例子:

<template>
  <div class="main">
    输入内容:<input type="text" v-model="question">
    <p>
      <span>旧值:{{myolddata}}</span>
      <span>新值:{{mynewdata}}</span>
    </p>
  </div>
</template>
<script>
export default {
  data() {
    return {
      question: "",
      myolddata: "",
      mynewdata: ""
    };
  },
  watch: {
    //watch语法,第一个参数表示新值,第二个参数默认表示旧值,即记录上一次的值
    question: function(newVal, oldVal) {
      this.myolddata = oldVal;
      this.mynewdata = newVal;
    }
  }
};
</script>

在这里插入图片描述
新值和旧值,两个值始终监听文本框值的变化。

例子2:

<template>
  <div class="main">
    输入内容:<input type="text" v-model="cityName">
  </div>
</template>
<script>
export default {
  data() {
    return {
      cityName: "BeiJing"
    };
  },
  watch: {
    cityName(newVal,oldVal)
    {
        console.log(`新值是${newVal},旧值是:${oldVal}`)
    }
  }
};
</script>

每当cityName的值发生变化的时候,就会执行watch中的cityName中的动作。
也可以直接写一个监听处理函数,每当监听到cityName值发送改变时,执行函数,也可以在所监听的数据后面直接加字符串形式的方法名:

watch:{
	cityName:'nameChange'//值可以为methods的方法名
}

watch中immediate和handler用法

我们在使用watch的时候有一个特点,就是当值第一次绑定的时候,不会执行监听函数,只有值发生改变才会执行。如果我们需要在最初绑定值的时候也执行函数,则就需要用到immediate属性。

watch只有当值发生改变时才会执行,如果初始就需要执行,可以添加属性immediate:true。
如果是对象键值变化进行监听时,需要使用deep:true。深度监听。

比如当父组件向子组件动态传值时,子组件props首次获取到父组件传来的默认值时,也需要执行函数,此时就需要将immediate设为true。

new Vue({
  el: '#root',
  data: {
    cityName: ''
  },
  watch: {
    cityName: {
      handler(newName, oldName) {
        // ...
      },
      immediate: true
    }
  } 
})

监听的数据后面写成对象形式,包含handler方法和immediate,之前我们写的函数其实就是在写这个handler方法;

immediate表示在watch中首次绑定的时候,是否执行handler,值为true则表示在watch中声明的时候,就立即执行handler方法,值为false,则和一般使用watch一样,在数据发生变化的时候才执行handler。

watch中的deep用法

当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听。

<input type="text" v-model="cityName.name"/>
new Vue({
  el: '#root',
  data: {
    cityName: {id: 1, name: 'shanghai'}
  },
  watch: {
    cityName: {
      handler(newName, oldName) {
      // ...
    },
    deep: true,
    immediate: true
    }
  } 
})

设置deep: true 则可以监听到cityName.name的变化,此时会给cityName的所有属性都加上这个监听器,当对象属性较多时,每个属性值的变化都会执行handler。如果只需要监听对象中的一个属性值,则可以做以下优化:使用字符串的形式监听对象属性:

watch: {
    'cityName.name': {
      handler(newName, oldName) {
      // ...
      },
      deep: true,
      immediate: true
    }
  }

这样只会给对象的某个特定的属性加监听器。
数组(一维、多维)的变化不需要通过深度监听,对象数组中对象的属性变化则需要deep深度监听。

例子3:

<template>
  <div class="main">
  <!--观察数据为字符串或数组-->
    例子1:
    <input type="text" v-model="example01">
    例子2:
    <input type="text" v-model="example02">
    <!--example03是一个对象,当单观察数据为对象时,如果键值发生变化,为了监听到数据变化,需要添加deep:true参数-->
    例子3:
    <input type="text" v-model="example03.name">
  </div>
</template>
<script>
export default {
  data() {
    return {
      example01: "",
      example02: "",
      example03: {
        name: "lisa",
        age: 12
      }
    };
  },
  watch: {
    example01(newVal, oldVal) {
      console.log(`新值${newVal},旧值${oldVal}`);
    },
    example02: "myfun",//值可以是methods的方法名
    'example03.name': {
     //注意:当观察的数据为对象或数组时,curVal和oldVal是相等的,因为这两个形参指向的是同一个数据对象
      handler(newV, oldV) {
        console.log(`新值${newV},旧值${oldV}`);
      },
      deep: true
    }
  },
  methods: {
    myfun(newVV, oldVV) {
      console.log(`新值${newVV},旧值${oldVV}`);
    }
  }
};
</script>

注:对应一个对象,键是观察表达式,值是对应回调。值也可以是方法名,或者是对象,包含选项。在实例化时为每个键调用 $watch() ;

deep深度监听

deep的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器,但是这样性能开销就会非常大了,任何修改obj里面任何一个属性都会触发这个监听器里的 handler。

优化,我们可以是使用字符串形式监听。

watch: {
 'obj.a': {
  handler(newName, oldName) {
   console.log('obj.a changed');
  },
  immediate: true,
  // deep: true
 }
}```
这样Vue.js才会一层一层解析下去,直到遇到属性a,然后才给a设置监听函数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值