vue.js基础(4)

计算属性和侦听器

计算属性

<div id="example">
  {{message.split('').reverse().join('')}}
</div>

在这里,模版不再是简单的声明式逻辑

对于任何复杂逻辑,都应当使用计算属性

例:
<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:{
    //计算属性的getter
    reverseMessage:function(){
      //'this'指向VM实例
      return this.message.split('').reverse.join('')
    }
  }
});

这里我们声明了一个计算属性 ++reversedMessage++。我们提供的函数将作用属性++vm.reversedMessage++的++getter++函数

console.log(vm.reverseMessage) //=>"olleH"
vm.message = "Goodbye"
console.log(vm.reversedMessage) //=>"eybdoG"

注:vm.reversedMessage的值始终取决于vm.message

计算属性缓存VS方法

可以通过在表达式中调用方法来达到同样的效果:

<p>Reversed message:"{{reversedMessage()}}"</p>

//在组件中
methods:{
  reversedMessage:function(){
    return this.message.split('').reverse().join('')
  }
}

可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

例:下面的计算属性将不再更新,因为 Date.now() 不是响应式依赖:

computed:{
    now:function(){
        return Date.now()
    }
}

每当触发重新渲染时,调用方法将总会再次执行函数。

计算属性VS监听属性

侦听属性:来观察和响应 Vue 实例上的数据变动。

当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。

<div id="demo">{{fullName}}</div>

var vm = new Vue({
    el:'#demo';
    data:{
        firstName:'Foo',
        lastName:'Bar',
        fullName:'Foo Bar'
    },
    watch:{
        firstName:function(val){
            this.fullName = val + ' ' + this.lastName  
        },
        lastName:function(val){
            this.fullName = this.flrstName  + ' ' +  val
        },
    }
});

将它与计算属性的版本进行比较:

var vm = new Vue({
    el:'#demo',
    data:{
        firstName:'foo',
        lastName:'Bar'
    },
    computed:{
        fullName:function(){
            return this.firstName + ' ' + this.lastName
        }
    }
});

现在再运行vm.fullName = “John Doe” 时,setter会被调用,vm.firstName和vm.lastName也会相应的被更新

侦听器

当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

例:

<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:'123abc'
        },
        watch:{
            //如果 `question` 发生改变,这个函数就运行
            question:function(newQuestion,oldQuestion){
                this.answer = "456efg",
                this.getAnswer()
            }
        },
        methods:{
            // `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
    // 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
    // AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
    // `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
    // 请参考:https://lodash.com/docs#debounce
             getAnswer: _.debounce(
      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
          })
      },
      // 这是我们为判定用户停止输入等待的毫秒数
      500
    )
        }
    });
</script>

结果:

Ask a yes/no question:

I cannot give you an answer until you ask a question!

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

除了 watch 选项之外,您还可以使用命令式的 vm.$watch API。


<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <div id="app1">
            <!--reverse() 方法用于颠倒数组中元素的顺序。
            split() 方法用于把一个字符串分割成字符串数组。-->
            {{ message.split('').reverse().join("") }}
        </div>
        <div id="app2">
            <p>原始字符串:{{message}}</p>
            <p>计算后反转字符串:{{reversedMessage}}</p>
        </div>
        <div id="app3">
            <p>原始字符串 :{{message}}</p>
            <p>计算后反转字符串:{{reversedMessage}}</p>
            <p>使用方法后反转字符串:{{reversedMessage2()}}</p>
        </div>
        <div id="app4">
            <p>{{site}}</p>
        </div>
        <div id="computed_props">
            千米:<input type="text" v-model="kilometers">
            米:<input type="text" v-model="meters">
        </div>
        <p id="info"></p>

        <div id="watch-example">
            <p>
                Ask a yes/no question:
                <input v-model="question">
            </p>
            <p>{{ answer }}</p>
        </div>

    </body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<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 type="text/javascript">
    new Vue({
        el:"#app1",
        data:{
            message:'Runoob!'
        }
    });
    new Vue({
        el:'#app2',
        data:{
            message:'Runoob!'
        },
        //计算属性
        computed:{
            //计算属性的getter
            reversedMessage:function(){
                //this指向Vm实例
                return this.message.split('').reverse().join("")
            }
        }
    });
    new Vue({
        el:'#app3',
        data:{
            message:'Runoob!'
        },
        computed:{
            reversedMessage:function(){
                return this.message.split("").reverse().join('')
            }
        },
        methods:{
            reversedMessage2:function(){
                return this.message.split('').reverse().join('')
            }
        }
    });
    var vm = new Vue({
        el:'#app4',
        data:{
            name:"Google",
            url:"http://www.google.com"
        },
        computed:{
            site:{
                //getter
                get:function(){
                    return this.name + " " + this.url
                },
                //setter
                set:function(newValue){
                    var names = newValue.split(' ');
                    this.name = name[0];
                    this.url = names[names.length - 1]
                }
            }
        }
    });
//  //调用setter,vm.name 和vm.url 也会被对应更新
//  vm.site = '菜鸟教程 http://www.runoob.com';
//  document.write('name:' + vm.name);
//  document.write('<br>');
//  document.write('url:'+vm.url);

//  var vm = new Vue({
//      el:'#computed_props',
//      data:{
//          kilometers:0,
//          meters:0
//      },
//      methods:{},
//      computed:{},
//      watch:{
//          kilometers:function(val){
//              this.kilometers = val;
//              this.meters = val * 1000;
//          },
//          meters:function(val){
//              this.kilometers= val/ 1000;
//              this.meters = val;
//          }
//      }
//  });
//  //$watch是一个实例方法
//  vm.$watch('kilometers',function(newValue,oldValue){
//      //这个回调函数将在vm.kilometers改变后调用
//      document.getElementById('info').innerHTML = '修改前值为:' + oldValue +"修改后的值:" + newValue;
//  })


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.getAnswer()
    }
  },
  methods: {
    // `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
    // 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
    // AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
    // `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
    // 请参考:https://lodash.com/docs#debounce
    getAnswer: _.debounce(
      function () {
        //indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
        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
          })
      },
      // 这是我们为判定用户停止输入等待的毫秒数
      500
    )
  }
})

</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值