[譯] Vue.js  —  注意事項和技巧

星期五發表於2019-02-07

Vue.js — 注意事項和技巧

[譯] Vue.js  —  注意事項和技巧

Vue.js 很棒。但是,當你開始構建大型 JavaScript 應用時,你將開始觸及 Vue.js 的邊界。實際上這些邊界並不是框架的限制;相反,這些邊界是 Vue.js 團隊不斷進步地重要設計決策。

與 React 或 Angular 不同,Vue.js 迎合不同級別的開發人員。對於初學者它友好,易用,並且對於專家它同樣靈活。它不會試圖避開 DOM。相反,它發揮得很好。

話雖如此,但這篇文章更像是我在 Vue.js 啟蒙途中遇到的一些重要 討論,問題和技巧 的目錄。瞭解這些關鍵的設計方面有助於我們構建大型的 web 應用程式。

同樣,這些討論在 2018 年 5 月 18 日的今天有效。當框架升級,底層瀏覽器和 JS API 將發生改變,它們可能無效和不直觀。


1. 為什麼 Vue.js 不使用開箱即用的 ES 類元件?

如果你來自類似 Angular 的框架或一些後端 OOP 的強型別語言,你的第一個問題將是 - 為什麼不是元件類?

Vue.js 作者,尤雨溪,在 GitHub 評論中已經很好地回答了這個問題:

不將類作為預設機制有三個主要的原因:

  1. ES 類不足以滿足 Vue.js 當前 API 的需求。ES 類沒有完全發展,經常被批評為錯誤方向的一步。具有私有欄位和裝飾器的類一旦穩定(至少第 3 階段)可能會有所幫助。
  2. ES 類只適用於熟悉基於類的語言的人。它很容易排除不使用複雜構建工具或轉換器的大型 web 社群。
  3. 構建出色的 UI 元件層次結構是關於出色的元件組成。它與偉大的繼承層次結構無關。不幸的是,ES 類在後者方面更勝一籌。

2. 如何構建自己的抽象元件?

如果構建大型 web 應用是不夠的,那麼你有一些瘋狂的想法來實現一個抽象元件,如 <transition><router-view>。這肯定有關於此的討論,但它真的沒有通過。

但是不要害怕,通過對插槽的充分理解,你可以構建自己的抽象元件。這有一篇非常好的部落格文章來解釋如何做到這一點。

但在你這樣做之前還是要三思而行。我們一直依靠 mixins 和 plain 函式來解決一些極端情況。只需將 minxins 視為您的抽象元件:


3. 我真的對用 Vue.js 單檔案元件 不舒服。我更喜歡把 HTML,CSS 和 JavaScript 分開。

沒有人阻止你這麼做。如果你是老派的 Separation of Concern 哲學家,喜歡將單獨的東西放在單獨的檔案中,或者你討厭程式碼編輯器圍繞 .vue 檔案的不穩定行為,那麼它肯定是可能的。所以你需要做的:

<!--https://vuejs.org/v2/guide/single-file-components.html -->

<!-- my-component.vue -->
<template src="./my-component.html"></template>
<script src="./my-component.js"></script>
<style src="./my-component.css"></style>
複製程式碼

但是,緊接著就出現了下一個問題 ——我的元件總需要四個檔案嗎?(vue + html + js + css)嗎。我可以以某種方式去掉 .vue 檔案嗎?答案肯定是可以,你可以這樣做。使用 vue-template-loader

我的同事寫了一篇關於它的很好的部落格:


4. 函式元件

感謝 React.js,函式元件是現在的熱潮,雖然有充分的理由。它們 快速,無狀態且易於測試。但是,它們有一些問題。

4.1 為什麼我不能為函式元件使用基於類的 @Component 裝飾器?

又回到類上,應該注意的是,類是旨在保持本地狀態的一種資料結構。如果函式元件是無狀態的,那麼 @Component 沒有意義。

相關討論可在以下網站查閱:

4.2 外部類和樣式不適用於函式元件

函式元件沒有像普通元件那樣的類和樣式繫結。必須在渲染函式中手動應用這些繫結。

4.3 函式元件總是重新渲染?

TLDR: 在函式元件中使用 有資料的 元件 時要小心

函式元件非常 渴望 直接使用元件的渲染函式。這也意味著你應該:

避免在渲染函式中直接使用有狀態的元件,因為這會在每一次呼叫渲染函式時建立不同的元件定義。

如果函式元件是子元件,它們會更好地被使用。應該注意的是,這種行為也適用於 React.js。

4.4 如何從 Vue.js 函式元件中觸發事件?

從函式元件中觸發事件並不是直接了當的。不幸的是,文件中沒有提到這一點。$emit 方法在函式元件中不可用。以下 stack overflow 問題將在這方面有所幫助:


5. Vue.js 透明包裝元件

透明包裝元件包裝一些 DOM 結構,但暴露該 DOM 結構的事件而不是根 DOM 元素。例如,

<!-- Wrapper component for input -->
<template>
    <div class="wrapper-comp">
        <label>My Label</label>
        <input @focus="$emit('focus')" type="text"/>
    </div>
</template>
複製程式碼

這裡,我們只是對 input 標籤 感興趣而不是 根 div 元素,因為它主要用於新增樣式和裝飾的。該元件的使用者可能對來自 input 的幾個事件感興趣,例如 blurfocusclickhover等。這意味著我們必須重新觸發每個事件。我們的元件看起來像這樣。

<!-- Wrapper component for input -->
<template>
    <div class="wrapper-comp">
        <label>My Label</label>
        <input type="text"
            @focus="$emit('focus')"
            @click="$emit('click')"
            @blur="$emit('blur')"
            @hover="$emit('hover')"
        />
    </div>
</template>
複製程式碼

現在是 anti-DRY 且看起來很亂。簡單的解決方案是使用 Vue 例項上的 vm.$listeners 屬性簡單地將事件偵聽重新繫結到所需的 DOM 元素:

<!-- Notice the use of $listeners -->
<template>
    <div class="wrapper-comp">
        <label>My Label</label>
        <input v-on="$listeners" type="text"/>
    </div>
</template>
<!-- Uses: @focus event will bind to internal input element -->
<custom-input @focus="onFocus"></custom-input>
複製程式碼

6. 為什麼你不能從插槽中 v-on 或 emit

我經常看到一些開發者試圖從插槽中觸發事件或者在一個插槽中監聽事件。

元件 slot 由呼叫父元件提供。這意味著所有事件都應與呼叫元件關聯。試圖監聽這些變化意味著你的父元件和子元件是緊密耦合的,還有另外一個方法可以做到這一點,Evan You 解釋得很漂亮:


7. 插槽中的插槽(讀取後代插槽)

在某些時候,你會遇到這種情況。想象一下,你有一個元件,比如 A,接受一些插槽。遵循組合原則,你會使用元件 A 建立另一個元件 B。現在你獲取元件 B 並在元件 C 中使用它。

問題是 — 如何將元件 C 中的插槽傳遞給 A

這個問題的答案取決於你使用的是什麼?如果你使用渲染函式,那麼它非常簡單。元件 B 的渲染函式將是:

// Render function for component B
function render(h) {
    return h('component-a', {
        // Passing slots as they are to component A
        scopedSlot: this.$scopedSlots
    }
}
複製程式碼

但是,如果你使用基於模板的渲染函式,那麼你就不走運了。幸運的是,這個問題正在取得進展,我們可能會為基於模板的元件提供一些東西:


希望這篇文章能夠深入瞭解 Vue.js 的設計要點和在 Vue.js 中使用高階場景的提示/技巧。

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章