深入浅出 Computed

Vue.js 的自我介绍中,只有说自己接近 MVVM 但不是严格的 MVVM。

我觉得只要会「自动更新画面」就算是有 MVVM 的效果至於有没有达到 MVVM pattern 的结构不用太计较。XDDD

接下来,我们来挑战一个 computed 和 watch 的解释,但是不一起比较,这次我们各别介绍,以免两个人又再度难分难舍。

从资料开始了解 computed

今天的文章比较短,为了避免观念混淆,所以特别缩短篇幅,集中一个概念的方式介绍。

参考自官网的例子: https://vuejs.org/v2/guide/computed.html

这个例子很好,只是分开讲更清楚,避免不细节用扫视的,想快速学习的朋友们,看图说故事时造成误会。

<template>
  <div>
    <div><input type="text" v-model="user.firstName"></input></div>
    <div><input type="text" v-model="user.lastName"></input></div>
    <div>{{ fullName }}</div>
  </div>
</template>
export default {
  name: 'demo',
  data() {
    return {
      user: {
        firstName: 'Foo',
        lastName: 'Bar',
      },
    };
  },
  computed: {
    fullName() {
      return this.user.firstName + this.user.lastName;
    },
  }
}

在这个时候,想像一下 user 是来自 API 的 data。

fullName 对 API 来说是一个不存在的栏位。并且,这一个衍生资料只拿来显示,不会写入的资料,只透过其它栏位来改它。

整理一下重点

  • 衍生的栏位
  • 只显示,不可写入

至於它会连动画面这件事,不用开发者操心,这件事就交给尤雨渓吧。我们只要负责看好文件写 code 就好了。

以物件的设计来说

如果,我们要设计一个 User 的物件

class User {
    constructor() {
        this.firstName = 'Foo';
        this.lastName = 'Bar';
    }
    getFullName() {
        return this.firstName + this.lastName
    }
}

以物件的设计来理解,computed 是一种 getter 并且只能读。
所以,在概念上,computed 属於一种无法修改的回传值。

不过实际上,它是一个被快取起来的值,所以依然存在着修改它的可能性,但是这是千千万万不要做的事情。要小心。

v-model 加上 computed 缩短在 html 上面的变数

原本

<div><input type="text" v-model="user.firstName"></input></div>

可以改成让 v-model 里的文字变少的写法。

<div><input type="text" v-model="firstName"></input></div>

整体的程序码如下面这样

<template>
  <div>
    <div><input type="text" v-model="firstName"></input></div>
    <div><input type="text" v-model="lastName"></input></div>
    <div>{{ fullName }}</div>
  </div>
</template>
export default {
  name: 'demo',
  data() {
    return {
      user: {
        firstName: 'Foo',
        lastName: 'Bar',
      },
    };
  },
  computed: {
    firstName: {
      set(firstName) {
        this.user.firstName = firstName;
      },
      get() {
        return this.user.firstName;
      },
    },
    lastName: {
      set(lastName) {
        this.user.lastName = lastName;
      },
      get() {
        return this.user.lastName;
      },
    },
  }
}

如果 data 在 vuex

https://vuex.vuejs.org/guide/forms.html#two-way-computed-property

照着文件介绍,可以把 computed 的 get/set 让 v-model 绑着一个名字,并且将 vuex 存取的方式 mutation 的 commit 和 getters (的 getters) 放在 computed 的 get/set 里面。

会照着文件的指示,明明只是绑两个栏位而已,却写得很多程序码。如下:

<template>
  <div>
    <div><input type="text" v-model="firstName"></input></div>
    <div><input type="text" v-model="lastName"></input></div>
    <div>{{ fullName }}</div>
  </div>
</template>
export default {
  name: 'demo',
  computed: {
    firstName: {
      set(firstName) {
        this.$store.commit('firstName', firstName)
      },
      get() {
        return this.$store.getters.firstName;
      },
    },
    lastName: {
      set(lastName) {
        this.$store.commit('lastName', lastName)
      },
      get() {
        return this.$store.getters.lastName;
      },
    },
  }
}

若在这时候使用 pure component 就会出现在 pure component 里面直接改 props 这样做是不对的,这个之後会另外写一篇专门介绍

也有另外一派,觉得如果要写这多,也许就要槙重考虑是不是不要把所有的资料放在 vuex 里面,必要的再放。这样对状态管理上来说是一件麻烦的事情,因为你只要用方便的 vuex 就会需要很麻烦的写一堆 code

所以,在这个时候,我有延续着我那大胆的猜想,衍生出来的想法「 v-model 不是这麽必要使用呢?」

如果不用 v-model 呢?

这是我偏好的写法,若把 v-model 解开,就可以不要靠 computed 的 get/set 串资料,直接把语法写在 html 上面,省掉这些一对一栏位串接的写法,允许 :value@input 的写法不一样,可以拥有不少弹性

这样一来,上述的两个麻烦就不再是麻烦了。所以把资料放进 vuex 里面不是麻烦事,也不会担心 pure component 的资传递是不是光绑栏位就超级麻烦。

而且 script 就可以放进真正复杂的程序码,一行搞定的,都放 html 里面

Components Basics — Vue.js中,除了前述的「v-model 可以拆开写」之外,拆开写还有提醒两个要注意的事情。

  1. 接收到的值,在 html 中要用 $event 这个关键字
  2. 如果是 <input type="text" @input="$event">$event 要注意它是什麽样的物件。如果是原生的 input 就可能是原生的 event 物件,如果是 UI component 套件提供的 input 像是 Bootstrap 的 <b-input> 就是 value 本身。
<template>
  <div>
    <div><input
      type="text"
      :value="$store.getters.firstName"
      @input="$store.commit('firstName', $event.target.value)"
    ></div>
    <div><input
      type="text"
      :value="$store.getters.lastName"
      @input="$store.commit('lastName', $event.target.value)"
    ></div>
    <div>{{ fullName }}</div>
  </div>
</template>
export default {
  name: 'demo',
  computed: {
    fullName() {
      return this.user.firstName + this.user.lastName;
    },
  }
}

万一 @input 出现复杂的情况或非同步的情况。都可以再写成 mehotd 处理。就会让复杂的情况进入 script 处理。

在之後 debug 扫视程序码,也比较快找到容易出错的复杂程序码。

这是第一步,让我感受到不用 v-model 的好处。script 的 code 就变得,让我感觉不会杂杂的,简单程序码不会出现在这。


<<:  [DAY 6] 建立Spring boot

>>:  Day 6 Odoo的Form View

Day 28 | 状态管理-从官方范例来看如何使用BLoC

那今天我们就来使用bloc及flutter_bloc 这两个来实作范例,基本上我们在实作BLoC p...

Day 8 规划用户的个资自主权

全球个资保护如雨後春笋般的出现,各国对於个资保护的意识更加积极主动,且也陆续参考GDPR进行个资隐私...

[Day-5] 指令cin以及小练习

上次练习了变数的宣告以及如何使用变数去做简单的相加 这次则是要用cin这个指令 结合过去所学到的做几...

[Day6] 词性标注(一)-前言

一. 前言 词性标注 Part Of Speech(後面皆简称POS),简单来说就是将文章、句子中,...

【Day06】提升(Hoisting)

我们在进到主题前先来看一段程序码,随後在开发人员工具中观察执行过程 function doSomet...