• Tags
  •         
  • www.breakyizhan.com
  •    

    Vue.js 的计算属性computed

    Vue.js模板内的表达式在设计的初衷是要非常简洁的。但是有时候模板内会放入很多复杂的逻辑计算。我们可以看一下,不使用computed的例子:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
      {{ message.split('').reverse().join('') }}
    </div>
    
    <script>
    new Vue({
      el: '#app',
      data: {
        message: 'Runoob!'
      }
    })
    </script>
    </body>
    </html>
    

    Vue.js模板变的很复杂起来,也不容易看懂理解。那么,Vue.js 的计算属性computed就可以处理这部分复杂的逻辑计算。

    Vue.js 的计算属性computed基础例子

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
      <p>原始字符串: {{ message }}</p>
      <p>计算后反转字符串: {{ reversedMessage }}</p>
    </div>
    
    <script>
    var vm = new Vue({
      el: '#app',
      data: {
        message: 'breakyizhan!'
      },
      computed: {
        // 计算属性的 getter
        reversedMessage: function () {
          // `this` 指向 vm 实例
          return this.message.split('').reverse().join('')
        }
      }
    })
    </script>
    </body>
    </html>
    

    尝试一下 >>

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

    Vue.js 的计算属性computed对比方法methods

    我们可以将同一函数定义为一个方法而不是一个计算属性。我们可以通过在表达式中调用方法来达到同样的效果,这两种方式的最终结果确实是完全相同的。可以看一下下面这个例子:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
      <p>原始字符串: {{ message }}</p>
      <p>计算后反转字符串: {{ reversedMessage }}</p>
      <p>使用方法后反转字符串: {{ reversedMessage2() }}</p>
    </div>
    
    <script>
    var vm = new Vue({
      el: '#app',
      data: {
        message: 'breakyizhan!'
      },
      computed: {
        // 计算属性的 getter
        reversedMessage: function () {
          // `this` 指向 vm 实例
          return this.message.split('').reverse().join('')
        }
      },
      methods: {
        reversedMessage2: function () {
          return this.message.split('').reverse().join('')
        }
      }
    })
    </script>
    </body>
    </html>
    

    尝试一下 >>
    然而,computed和methods不同的是计算属性是基于它们的依赖进行缓存的。只在相关依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。假设我们有一个性能开销比较大的计算属性 A,那么用缓存就减少性能消耗;如果不希望有缓存,请用方法来替代。

    Vue.js 的计算属性computed对比侦听器watch

    Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。有时候侦听属性会被滥用,但是很多地方,用computed会比用watch更加简洁,对比下面两段代码就知道了,(代码可以复制之后,在线运行)

    使用Vue.js侦听器watch:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="demo">{{ fullName }}</div>
    <script>
    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.firstName + ' ' + val
        }
      }
    })
    </script>
    </body>
    </html>
    

    使用Vue.js 的计算属性computed:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="demo">{{ fullName }}</div>
    <script>
    var vm = new Vue({
      el: '#demo',
      data: {
        firstName: 'Foo',
        lastName: 'Bar'
      },
      computed: {
        fullName: function () {
          return this.firstName + ' ' + this.lastName
        }
      }
    })
    </script>
    </body>
    </html>
    

    使用Vue.js 的计算属性computed会比用侦听器watch简洁多了,损耗也少多了,不是么?

    Vue.js 的计算属性computed setter

    Vue.js的计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter ,用来更新数据:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
      <p>{{ site }}</p>
    </div>
    
    <script>
    var vm = new Vue({
      el: '#app',
      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 = names[0]
            this.url = names[names.length - 1]
          }
        }
      }
    })
    // 调用 setter, vm.name 和 vm.url 也会被对应更新
    vm.site = 'Break易站 https://www.breakyizhan.com';
    document.write('name: ' + vm.name);
    document.write('<br>');
    document.write('url: ' + vm.url);
    </script>
    </body>
    </html>
    

    尝试一下 >>

    Vue.js 的侦听器watch

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

    Vue.js 的侦听器watch实现计算器

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    </head>
    <body>
    <div id = "app">
     <p style = "font-size:25px;">计数器: {{ counter }}</p>
     <button @click = "counter++" style = "font-size:25px;">点我</button>
    </div>
    <script type = "text/javascript">
     var vm = new Vue({
        el: '#app',
        data: {
           counter: 1
        }
     });
     vm.$watch('counter', function(nval, oval) {
        alert('计数器值的变化 :' + oval + ' 变为 ' + nval + '!');
     });
    </script>
    </body>
    </html>
    

    尝试一下 >>

    Vue.js 的侦听器watch实现米和千米的转换

    <!DOCTYPE html>
    <html>
    <head>
    	<meta charset="utf-8">
    	<title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    	<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    </head>
       <body>
          <div id = "computed_props">
             千米 : <input type = "text" v-model = "kilometers">
             米 : <input type = "text" v-model = "meters">
          </div>
    	   <p id="info"></p>
          <script type = "text/javascript">
             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;
    		})
          </script>
       </body>
    </html>
    

    尝试一下 >>

    Vue.js 的侦听器watch官网动态问题例子

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    </head>
    <body>
    <div id="watch-example">
      <p>
        Ask a yes/no question:
        <input v-model="question">
      </p>
      <p>{{ answer }}</p>
    </div>
    <script type = "text/javascript">
     <!-- 因为 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>
    </body>
    </html>
    

    注:可以复制上述代码在线执行。
    TIPS:这篇文章主要讲的是Vue.js 的计算属性computed和侦听器watch,两个部分,可以点击文章右下角的图标,打开文章目录,按章节查看。
    Vue.js 的计算属性computed和侦听器watch

     
    转载请保留页面地址:https://www.breakyizhan.com/vue/6684.html