# 文档初探(二): 计算属性和方法

# 计算属性

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
1
2
3
4
var vm = new Vue({
  el: "#example",
  data: {
    message: "Hello"
  },
  computed: {
    // a computed getter
    reversedMessage: function() {
      // `this` points to the vm instance
      return this.message
        .split("")
        .reverse()
        .join("");
    }
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Vue 在解析时看见message就会在data里找, 在解析reversedMessagedata里并不存在, 于是会在methods里找, 如果还没有则在computed里找.computed里的函数不带参数, 并且必定有一个返回值.

# methods

同样的功能, methods也能实现:

<div id="app">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage() }}"</p>
</div>
1
2
3
4
let vm = new Vue({
  el: "#app",
  data: {
    message: "hello"
  },
  methods: {
    reversedMessage() {
      return this.message
        .split("")
        .reverse()
        .join("");
    }
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# computedmethods的区别

<div id="app">
  <p>Original message: "{{ message }}"</p>
  <p>"{{ reversedMessage() }}"</p>
  <p>"{{computedReversedMessage}}"</p>
  <p>{{n}}</p>
  <button @click="add">+1</button>
</div>
1
2
3
4
5
6
7
let vm = new Vue({
  el: "#app",
  data: {
    message: "hello",
    n: 0
  },
  methods: {
    reversedMessage() {
      console.log("methods被调用");
      return (
        "methods:" +
        this.message
          .split("")
          .reverse()
          .join("")
      );
    },
    add() {
      this.n += 1;
    }
  },
  computed: {
    computedReversedMessage() {
      console.log("computed 被调用");
      return (
        "computed:" +
        this.message
          .split("")
          .reverse()
          .join("")
      );
    }
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

computed

从截图里可以看见, 每当data更新时, methods里的方法都会重新调用一次, 而computed没有. 因为computed会在每次data更新时查看自己的属性是否与更新的data有关, 有则重新调用, 没有则保存上次调用的结果.

# setter & getter

每个计算属性里有getset两种方法.默认情况下没有setter, 只有getter. 如果我们需要setter, 则要将代码写成如下格式:

computed: {
    computedReversedMessage: {
      get() {
        return (
          "computed:" +
          this.message
            .split("")
            .reverse()
            .join("")
        );
      },
      set(newValue) {
        this.message = newValue
          .split("")
          .reverse()
          .join("");
      }
    }
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

调用setter的方法是this.computedReversedMessage = newValue, this指向 Vue 实例.

# watch

watch用于监听数据的改动, 并对改动的数据执行相应的函数.

var vm = new Vue({
  data: {
    a: 1,
    b: 2,
    c: 3,
    d: 4,
    e: {
      f: {
        g: 5
      }
    }
  },
  watch: {
    a: function(val, oldVal) {
      //接受新的值和旧值
      console.log("new: %s, old: %s", val, oldVal);
    },
    // 接受字符串方法名
    b: "someMethod",
    // handler属性的值是一个函数, 它是监听到改动的操作函数; deep属性为true表示无论对象内嵌的属性多深, 只要有变化也会被监听并触发handler
    c: {
      handler: function(val, oldVal) {
        /* ... */
      },
      deep: true
    },
    // watch属性的key在初始化后才会开始监听变化, immediate属性默认为false, 设置为true就能在初始化时触发handler
    d: {
      handler: "someMethod",
      immediate: true
    },
    e: [
      "handle1",
      function handle2(val, oldVal) {
        /* ... */
      },
      {
        handler: function handle3(val, oldVal) {
          /* ... */
        }
        /* ... */
      }
    ],
    // 监听对象的属性也是可行的
    "e.f": function(val, oldVal) {
      /* ... */
    }
  }
});
vm.a = 2; // => new: 2, old: 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50