《Vue-进阶属性之computed》

289 阅读1分钟

由数据响应式我们知道,Vue会在data变化时更新UI。

那么data变化时,除了更新UI之外,还可以做点什么?

computed:计算属性

就是由其他属性计算得来的属性

例1:展示用户名

new Vue({
  data: {
    user: {
      email: "1234567@qq.com",
      nickname: "小七",
      phone: "13812312312"
    }
  },
  template: `
    <div>
     {{user.nickname || user.email || user.phone}}
    </div>
  `,
}).$mount("#app");

需求:div里展示用户的昵称。

可是,用户有可能没填昵称,所以就优先展示昵称,如果没有昵称,就展示email,没有email,就展示电话号。

问题是,如果有一百个用户,这句代码就要重复一百次。重复的缺点是,如果有一天需求变了,要你优先展示email,你就要改一百个地方。

computed的函数形式

所以,不如使用计算属性:

computed:{
    displayName(){
      const user=this.user
      return user.nickname || user.email || user.phone
    }
 },
 template: `
    <div>
     {{displayName}}
    </div>
 `,

displayName以函数的形式定义,在div里展示displayName,直接以属性的形式调用,不需要加括号。会默认读取它的返回值。

computed:使由其他属性计算而来的属性成为一个属性

我能不能设置计算属性呢?比如点击按钮,就改变昵称。

设getter,setter

computed: {
    displayName: {
      get() {
        const user = this.user;
        return user.nickname || user.email || user.phone;
      },
      set(val) {
        this.user.nickname = val;
      }
    }
},
template: `
    <div>
        {{displayName}}
        <button @click="displayName='小八'">set</button>
    </div>
`,

displayName改为对象形式,里边定义get(){},set(){}函数。

如果直接展示:{{displayName}},就会调用get函数。

set函数会把val赋给data里的用户对象。点击按钮,会执行:displayName='小八'。页面中的昵称就会更新。

例2:列表按需展示

页面中有三个按钮,点击‘全部’,显示全部用户;点击‘男’,只显示男性用户。。。

let id = 0;
const createUser = (name, gender) => {
  id += 1;
  return { id: id, name: name, gender: gender };
};

new Vue({
  data() {
    return {
      users: [
        createUser("小四", "男"),
        createUser("小五", "女"),
        createUser("小六", "男"),
        createUser("小七", "女")
      ],
      gender: ""
    };
  },
  computed: {
    displayUsers() {
      const { users, gender } = this;
      const hash={
        'male':"男",
        "female":'女'
      }
      if (gender === "") {
        return users;
      } else if (gender === "male" || gender === "female") {
        return users.filter(u => u.gender === hash[gender]);
      } 
    }
  },
  template: `
    <div>
      <div>
      <button @click='gender = ""'>全部</button>
      <button @click='gender = "male"'>男</button>
      <button @click='gender = "female"'>女</button></div>
      <ul>
        <li v-for="(u,index) in displayUsers" :key="index">{{u.name}} - {{u.gender}}</li>
      </ul>
    </div>
  `
}).$mount("#app");

点击‘全部’:

点击‘男’:
点击‘女’同理。

通过计算属性displayUsers来完成。我们的需求是根据不同的gender,展示不同的用户。所以就是根据users和gender得到不同的结果,就是通过其他属性计算别的属性。

计算属性里,根据不同的gender,返回各自的结果。template里根据这个计算属性的返回值展示用户数组。然后点击按钮时,只需要改变gender就可以。至于改变完gender之后,如何展示不同的结果,就是计算属性的任务了。

所以计算属性的使用可以使代码逻辑很清晰。

缓存

如果计算属性依赖的属性没有发生变化,那么这个计算属性就不会重新计算。

以2为例,我在displayUsers里第一句加console.log。点击男,有打印值。再点一次男,发现没有打印值了。说明,计算属性没有执行。displayUsers依赖users,gender两个属性,再次点击男时,发现他俩都没变,那就不会再计算一次。

(缓存原理没有)