複習Vue中的方法,計算和偵聽者

富途web開發團隊發表於2019-03-02

歡迎關注富途web開發團隊,缺人從眾

最近一直在Vue和angualr.js 1.x之間切換。大腦都快切換不過來了。

趁著週末,還是把Vue的基本知識複習一下。

檢視原文 連結

正文

工作中我喜歡用Vue的原因之一就是因為方法,計算屬性和偵聽者非常有用,並且他們之前差異的可讀性很好。在理解這三者之前,我很難充分的利用Vue的全部功能。儘管如此,大多數人對這個框架感到困惑的也多集中在這三者之間的差異,所以讓我們一起來深入研究下。

如果你想得到一個直接結論,或者你沒有時間閱讀整篇文章,這裡給一些略長的小總結:

  • Methods(方法):顧名思義,就是方法的意思。這些方法是能操作物件的函式-通常是Vue例項本身或者Vue元件。

  • Computed(計算):這些計算屬性可能乍看起來就像方法一樣使用,但其實不是的。在Vue中,我們需要用data去響應我們想要的一個特定屬性的變化。計算屬性不僅可以定義一個與data使用方式相同的屬性,並且可以有一些基於其依賴關係進行快取的自定義邏輯。你可以將計算屬性視為資料的另一個檢視。

  • Watchers(偵聽者):偵聽者可以窺視資料變化。我們提供了一些鉤子函式來監視Vue儲存的一些屬性。如果你想在資料變化時新增一些功能,或者對一些特定的更改做出響應,我們可以偵聽這個屬性並應用一些邏輯。這意味著偵聽者的名字必須要與我們偵聽的內容相匹配。

如果這麼說讓你聽起來有些困惑,不要擔心!我們將在下面進行更多的探討希望能解答你的困惑。如果你已經熟悉vanilla Javascript,那麼除了一兩個注意事項外,方法對你來說是比較重要的。這可能會讓你跳過ComoutedWatchers這兩個部分。

Methods(方法)

方法可能是你在使用Vue時經常用到的。其實它就是我們把一些函式方法掛到一個物件上,所以它實質上就是這樣被命名的。它對於將功能連線到事件指令非常有用,甚至只要建立一小段邏輯就可以像其他函式一樣複用。例如,你可以在另一個方法中呼叫方法。你也可以在生命週期鉤子函式中呼叫這個方法。這是非常靈活的。

這裡有一個簡單的演示:點選連結

//HTML
<code class="language-css"><div id="app">
  <button @click="tryme">Try Me</button>
  <p>{{ message }}</p>
</div>
複製程式碼
//JS
new Vue({
  el: `#app`,
  data() {
    return {
      message: null
    }
  },
  methods: {
    tryme() {
      this.message = Date()
    }
  }
})
複製程式碼

我們也可以直接在指令本身中執行這個邏輯,如<button @click="message = Date()">Try Me</button>
這在小示例中是非常有效的。但是,隨著應用程式越來越複雜,對於上面這種常見的方法是將其分解出來更加清晰。Vue允許你在指令中表達邏輯也是有限制的-例如,表示式可以,但語句不行。

你可能會注意到,我們可以在該元件或Vue例項中訪問這個方法,並且可以呼叫任何一條資料,在本例中就是this.message.你不需要用像在指令中呼叫函式的方法。例如:不需要這樣@click=”methodName()”,除非你要傳一個引數,像這樣@click=”methodName(param)”

使用指令呼叫方法也挺好的,因為我們有一些事件修飾符。其中一個常用的例子就是.prevent,它將在提交事件中阻止頁面重新載入。

//HTML
<form v-on:submit.prevent="onSubmit"></form>
複製程式碼

還有更多可以學習下

Computed (計算屬性)

計算屬性對於處理已存在的資料非常有價值。無論何時,當你需要對大量資料進行排序並且不想在每次按鍵時重新進行運算,請考慮使用計算屬性。

一些常用的場景例如:

  • 在使用者輸入時更新大量的資訊,例如過濾列表。
  • 從Vuex商店中收集資訊
  • 表單驗證
  • 資料視覺化需要依賴於使用者檢視的內容而變化

計算屬性是理解學習Vue的一個重要部分。它們是基於依賴關係進行快取的計算,並且在依賴關係變化時進行更新。如果使用得當會非常高效。有很多大型的元件庫都是為了處理這種邏輯,然而現在只需要幾行程式碼就能解決。

計算屬性並不想方法那樣使用,儘管起初它們長的差不多-你在函式中宣告一些邏輯並返回-但是這個函式的名字變成了一個屬性,然後你將在程式中應用它,如data

如果我們需要根據使用者輸入的內容來篩選這些人的名單,那麼我們將如何做到這一點。為了看起來簡單些,你可以減少一些基本概念。首先,列表資料將會把儲存在資料中的名稱在模板中輸出:

//JS
new Vue({
  el: `#app`,
  data() {
    return {
      names: [
        `Evan You`,
        `John Lindquist`,
        `Jen Looper`,
        `Miriam Suzanne`,
        ...
      ]
    }
  }
})
複製程式碼
//HTML
<div id="app">
  <h1>Heroes</h1>
  <ul>
    <li v-for="name in names">
      {{ name }}
    </li>
  </ul>
</div>
複製程式碼

效果見 連結

現在讓我們為這些名稱建立一個過濾器。我們先建立一個有v-model的input,該輸入起初回事個空字串,但是我們將使用它來匹配和過濾我們的列表。我們將呼叫findName這個屬性,你可以在輸入和data中看到這個引用。

//HTML
<label for="filtername">Find your hero:</label>
<input v-model="findName" id="filtername" type="text" />
複製程式碼
//JS
data() {
  return {
    findName: ``,
    names: [
      `Evan You`,
      `John Lindquist`,
      ...
    ]
  }
}
複製程式碼

現在我們可以建立計算屬性,根據使用者輸入的內容來過濾名稱,因此我們的findName屬性中的任何內容都會被使用。你會注意這裡我用了正規表示式來確保使用者輸入大小寫都沒關係,因為使用者輸入時通常不會大寫。

//JS
computed: {
  filteredNames() {
    let filter = new RegExp(this.findName, `i`)
    return this.names.filter(el => el.match(filter))
  }
}
複製程式碼

現在我們將更新模板中使用的內容輸出:

//HTML
<ul>
  <li v-for="name in names">
    {{ name }}
  </li>
</ul>
複製程式碼

變成這樣

//HTML
<ul>
  <li v-for="name in filteredNames">
    {{ name }}
  </li>
</ul>
複製程式碼

這將會在每次按鍵時為我們進行過濾,我們只需要新增幾行程式碼就能達到這個效果,而不必載入任何其他的庫。

效果如下 連結

我在使用它時,不知道節省了多少時間,如果你在用Vue但是還沒有探索過這個功能,那麼趕緊去使用吧,你會感謝我的。

Watchers(偵聽者)

Vue具有很好的抽象性,任何一個曾經做過程式設計師的都會告訴你,抽象是一種痛,因為最終你會遇到一個他們無法解決的用例。然而,這種情況是可以解釋的,因為Vue能夠更深入的訪問反應系統,我們可以利用它來偵聽正在改變的事物。這個可能是很有用的,因為作為應用程式開發人員,我們負責的大部分事情都是變化的。

Watchers還允許我們編寫更多的宣告性程式碼。你不用再去追蹤一切。Vue已經在做這件事了,所以你可以訪問它所追蹤的任何屬性的變化,例如:data,computed或者props

當一個屬性發生變化時,偵聽者非常適合執行適用於別的東西的邏輯(我第一次聽到這個是從Chris Fritz那裡,他說他也是從別人那裡聽到的☺️)這不是一個硬性的原則-你完全可以使用偵聽者來引用屬性本身的邏輯,但是這是區別偵聽者和計算屬性不同的一個很好的方式,當我們將要用到的引用屬性改變時。

我們來看看最簡單的例子,就能瞭解這其中發生了啥。

視訊連結

//JS
new Vue({
  el: `#app`, 
  data() {
    return {
      counter: 0
    }
  },
  watch: {
    counter() {
      console.log(`The counter has changed!`)
    }
  }
})
複製程式碼

正如上面程式碼中看到的那樣,我們將counter儲存在data中,並且使用該屬性名稱作為函式名稱,我們就可以偵聽它了,當我們在watche中引用counter時,就可以觀察到這個屬性的變化了。

Watchers的過度狀態

如果狀態足夠相似,你甚至可以簡單的將狀態轉換為偵聽者。這裡看下我用Vue畫的一個表格。當資料發生變化時,觀察者將更新它並且能在兩者之間簡單的轉換。

SVG對於這樣的場景也使用,因為它也是用數學建立的。

效果連結

//JS
watch: {
  selected: function(newValue, oldValue) {

    var tweenedData = {}

    var update = function () {
      let obj = Object.values(tweenedData);
      obj.pop();
      this.targetVal = obj;
    }

    var tweenSourceData = { onUpdate: update, onUpdateScope: this }

    for (let i = 0; i < oldValue.length; i++) {
      let key = i.toString()
      tweenedData[key] = oldValue[i]
      tweenSourceData[key] = newValue[i]
    }

    TweenMax.to(tweenedData, 1, tweenSourceData)
  }
}
複製程式碼

這裡發生了什麼呢?

  • 首先我們建立了一個虛擬物件,它將跟隨動畫庫變化更新。

  • 然後我們有一個更新的函式,在tween step中呼叫這個函式。我們用這個來推動資料。

  • 然後我們建立一個物件來儲存後設資料和更新事件的函式

  • 我們建立一個for迴圈,然後將當前索引變成一個字串。

  • 然後我們可以在目標虛擬物件上進行tween ,但是我們只會對特定的關鍵點執行這個操作。

我們也可以在觀察者中使用動畫來建立類似於這個時間差的錶盤。我旅行了一段時間,我所有的同事都在不同的地方,所以我想要用一種方式來追蹤我們當地的時間,以及白天時間/晚上時間變化的意義。

效果連結

在這裡,我們正在偵聽checked屬性,並且我們將使用包含時間線動畫的不同方法來改變色調和飽和度以及基於與當前時間的相對關聯的一些其他元素。正如前面提到的那樣 – 變化發生在下拉選單上,但我們正在執行的是在其他地方應用的邏輯。

//JS
watch: {
  checked() {
    let period = this.timeVal.slice(-2),
      hr = this.timeVal.slice(0, this.timeVal.indexOf(`:`));

    const dayhr = 12,
      rpos = 115,
      rneg = -118;

    if ((period === `AM` && hr != 12) || (period === `PM` && hr == 12)) {
      this.spin(`${rneg - (rneg / dayhr) * hr}`)
      this.animTime(1 - hr / dayhr, period)
    } else {
      this.spin(`${(rpos / dayhr) * hr}`)
      this.animTime(hr / dayhr, period)
    }

  }
},
複製程式碼

關於watchers還有一些其他有趣的事情,例如:我們可以將屬性的新版本和舊版本作為引數進行訪問,如果我們想偵聽巢狀物件,我們可以指定deep。更多詳情看指引,本指南中提供了許多有用的資訊

您可以看到偵聽者對於實時更新的任何內容-無論是表單輸入,非同步更新還是動畫都可以發揮非常有用的作用。如果你很好奇Vue是如何做到的,那麼這部分指南是非常有用的。如果你想了解更多的響應,推薦我喜歡的Andre Staltz的博文和Mike Bostock的更好的編碼方式

總結

我希望這是一個關於如何使用的指引,並且能提高你使用Vue進行應用程式開發的效率。有一個資料統計,我們用70%的時間去閱讀程式碼,而只用了30%的時間來寫。個人而言,作為一個維護者我喜歡這一點,我可以看之前沒有見過的程式碼庫,並且能夠通過methods,computedwatchers的區別用法來了解作者的意圖。

原文:Methods, Computed, and Watchers in Vue.js

作者:SARAH DRASNER

譯者:Diandian

相關文章