计算属性和观察者

计算属性

​ 直接在模板内的嵌入表达式是非常便利的,但他们实际上是用于简单运算的,在实际开发中很少使用,因为在模板中嵌入太多逻辑会让模板过重且难以维护。例如:

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

    ​ 在这里,模板不再简单和清晰,并且如果要在多处地方重复使用此处的翻转字符串时,会更加难以处理。 因此,对于复杂逻辑,vue引入了计算属性(computed)

方法

​ 我们可能将同计算属性相同的函数定义为一个方法,一般情况下,2种方法的作用效果是相同的。然而,不同的是计算属性是基于他们的依赖进行缓存的,计算属性只有在他的相关依赖发生改变时才会重新求值,而方法不同,每当触发重新渲染时,方法的调用方式总是再次执行函数。

  • 举个简单的例子:假设B依赖与A,要获取B的值,只要A的值不发生改变,每次访问B,计算属性都会立即返回之前的计算结果,而不会再次执行函数。如果是方法的话,只要页面一刷新,便会再次执行函数。
  • 为什么需要缓存?假设我们有一个性能开销比较大的的计算属性 A,它需要遍历一个极大的数组和做大量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。
  • <div id="example">
        <p>Original message: "{{ message }}"</p >
      <!--计算属性实现翻转字符串-->
        <p>Computed reversed message:"{{ reversedMessage_1 }}"</p >
          <!--方法实现翻转字符串-->
        <p>Revered message: "{{ reversedMessage_2() }}"</p >
    </div>
    
  • let vm = new Vue({
        el:'#example',
        data:{
            message:'hello',
        },
        computed:{ 
          //此函数相当于 vm.reversedMessage属性的getter函数
            reversedMessage_1: function () {
                return this.message.split('').reverse().join('');
            },
        },
        methods:{
            reversedMessage_2: function () {
                return this.message.split('').reverse().join('');
            },
        }
    });
    
  • 因为 Date.now() 不是响应式依赖,下面再举个简单的栗子:

  • <div id="example">
        <p>Time:"{{ now_1 }}"</p >
        <p>Time:"{{ now_2() }}"</p >
    
    </div>
    
  • let vm = new Vue({
        el:'#example',
        data:{
            message:'hello',
        },
        computed:{
            now_1: function () {
                return new Date().toLocaleString();
            }
        },
        methods:{
            now_2: function () {
                return new Date().toLocaleString();
            },
        }
    });
    

    ​ 打开控制台(console),分别调用方法vm.now_2()和计算属性vm.now_1,查看输出状态如下:

  • image.png

    ​ 可以看出,调用方法,获取到的是更新后的值,调用计算属性,获取到的是缓存的值。

观察者

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

    <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>

<div id="watch-example">
    <p>
        Ask a yes/no question:
        <input v-model="question">
    </p >
    <p>{{ answer }}</p >
</div>
let watchVM = new Vue({
    el:'#watch-example',
    data:{
        question:'',
        answer:'I can not give you an answer untile you ask a question!'
    },
    watch:{
        //如果question发生改变,这个函数就会执行
        question: function () {
            this.answer = 'waitting for you to stop typing...';
            this.getAnswer();
        }
    },
    methods:{
        // _.debounce 是一个通过 lodash 限制操作频率的函数。
        // 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
        // ajax 请求直到用户输入完毕才会发出
        // 学习更多关于 _.debounce function (and its cousin
        // _.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...';
                let vm = this;
                axios.get('https://yesno.wtf/api')
                    .then(function (response) {
                        vm.answer = _.capitalize(response.data.answer);
                    })
                    .catch(function (err) {
                        vm.answer = 'Error!could not reach the API' + err;
                    })
            },
            //这是为用户停止输入等待的毫秒数
            500
        )}
});
  • ​ 在这个示例中,使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这是计算属性无法做到的。

番外:什么是 axios

​ axios 是一个基于 Promise 的,为浏览器和 Node.js 设计的 HTTP 客户端。它尽可能简化封装了 HTTP 相关的各种操作,在 Web App 中使用非常方便。Vue 2 官方建议在由 Vue 构建的 SPA 中使用 axios 进行 HTTP 操作。

​ 传送门:mzabriskie/axios

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容