Vue核心知識-computed和watch的使用場景和方法

littlebirdflying發表於2018-09-06

computed

不使用 computed

通過簡單的字串拼接

import Vue from 'vue'

new Vue({
  el: '#root',
  template: `
    <div>
      <span>Name: {{firstName + ' ' + lastName}}</span>
    </div>
  `,
  data: {
    firstName: 'Jokcy',
    lastName: 'Lou'
  }
})
複製程式碼

使用 computed

new Vue({
  el: '#root',
  template: `
    <div>
      <span>Name: {{name}}</span>
    </div>
  `,
  data: {
    firstName: 'Jokcy',
    lastName: 'Lou'
  },
  computed: {
    name () {
      return `${this.firstName} ${this.lastName}`
    }
  }
})

複製程式碼

使用 methods

顯示結果和使用 computed 相同

new Vue({
  el: '#root',
  template: `
    <div>
      <span>Name: {{name}}</span>
      <span>Name: {{getName()}}</span>
    </div>
  `,
  data: {
    firstName: 'Jokcy',
    lastName: 'Lou'
  },
  computed: {
    name () {
      return `${this.firstName} ${this.lastName}`
    }
  },
  methods: {
    getName () {
      return `${this.firstName} ${this.lastName}`
    }
  }
})

複製程式碼

使用 computed 的好處

當我們改變 number 時,整個應用會重新渲染,vue 會被資料重新渲染到 dom 中。這時,如果我們使用 getName 方法,隨著渲染,方法也會被呼叫,而 computed 不會重新進行計算,從而效能開銷比較小。當新的值需要大量計算才能得到,快取的意義就非常大。

如果 computed 所依賴的資料發生改變時,計算屬性才會重新計算,並進行快取;當改變其他資料時,computed 屬性 並不會重新計算,從而提升效能。

當我們拿到的值需要進行一定處理使用時,就可以使用 computed。

import Vue from 'vue'

new Vue({
  el: '#root',
  template: `
    <div>
      <p>Name: {{name}}</p>
      <p>Name: {{getName()}}</p>
      <p>Number: {{number}}</p>
      <p><input type="text" v-model="number"/></p>
	  <p>FirsName: <input type="text" v-model="firstName"/></p>
      <p>LaseName: <input type="text" v-model="lastName"/></p>
    </div>
  `,
  data: {
    firstName: 'Jokcy',
    lastName: 'Lou',
    number: 0
  },
  computed: {
    name () {
      console.log('new name')
      return `${this.firstName} ${this.lastName}`
    }
  },
  methods: {
    getName () {
      console.log('getName invoked')
      return `${this.firstName} ${this.lastName}`
    }
  }
})

複製程式碼

computed 設定的操作

通過 computed 的 set 方法,可以進行設定的操作。

如下例,通過改變 name 的值,也可以改變 computed 屬性 name 所以來的 firstName 和 lastName 的值。

不推薦這樣做,一般 computed 屬性資料是根據多重資料組合成的新的資料,組合容易,但拆開重新設定並不容易

template: `
    <div>
      <p>Name: <input type="text" v-model="name"/></p>
    </div>
  `,
  data: {
    firstName: 'Jokcy',
    lastName: 'Lou',
  },
  computed: {
    name: {
      get () {
        console.log('new name')
        return `${this.firstName} ${this.lastName}`
      },
      set (name) {
        const names = name.split(' ')
        this.firstName = names[0]
        this.lastName = names[1]
      }
    }
  },
複製程式碼

watch

例如,監聽 firstName 資料,並根據改變得到的新值,進行某些操作。

new Vue({
  template: `
    <div>
      <p>FullName: {{fullName}}</p>
      <p>FirsName: <input type="text" v-model="firstName"/></p>
    </div>
  `,
  data: {
    firstName: 'Jokcy',
    lastName: 'Lou',
    fullName: ' '
  },
  watch: {
    firstName (newName, oldName) {
      this.fullName = newName + ' ' + this.lastName
    }
  }
})

複製程式碼

注意:上例中,初始 fullName 是沒有值的,只有當資料改變時,才會顯示。因為 watch 的方法預設是不會執行的,只有當監聽資料變化,才會執行。

immerdiate 屬性

通過宣告 immediate 選項為 true,可以立即執行一次 handler。

watch: {
    firstName: {
      handler (newName, oldName) {
        this.fullName = newName + ' ' + this.lastName
      },
      immediate: true
    }
  },
複製程式碼

watch 並不適用於顯示某一個資料以及資料的拼裝等。watch 用在監聽資料變化,做某些指令操作(給後臺發資料請求)

deep屬性

不使用 deep 時,當我們改變 obj.a 的值時,watch不能監聽到資料變化,預設情況下,handler 只監聽屬性引用的變化,也就是隻監聽了一層,但改物件內部的屬性是監聽不到的

new Vue({
  template: `
    <div>
      <p>Obj.a: <input type="text" v-model="obj.a"/></p>
    </div>
  `,
  data: {
    obj: {
      a: '123'
    }
  },
  watch: {
    obj: {
      handler () {
        console.log('obj.a changed')
      },
      immediate: true
      // deep: true
    }
  }
})

複製程式碼

通過使用 deep: true 進行深入觀察,這時,我們監聽 obj,會把 obj 下面的屬性層層遍歷,都加上監聽事件,這樣做,效能開銷也會變大,只要修改 obj 中任意屬性值,都會觸發 handler。

如何優化?

在字串中,寫 obj 深入的屬性呼叫,vue 會層層解析,找到 a,並進行監聽。

watch: {
    'obj.a': {
      handler () {
        console.log('obj.a changed')
      },
      immediate: true
      // deep: true
    }
  }
複製程式碼

注意

不要在 computed 或 watch 中,去修改所依賴的資料的值,尤其是 computed;如果這樣做,可能導致一個無線迴圈的觸發。

相關文章