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

Vue.js — 注意事項和技巧

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

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

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

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


1. 爲何 Vue.js 不使用開箱即用的 ES 類組件?

若是你來自相似 Angular 的框架或一些後端 OOP 的強類型語言,你的第一個問題將是 - 爲何不是組件類?android

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

不將類做爲默認機制有三個主要的緣由:ios

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

2. 如何構建本身的抽象組件?

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

可是不要懼怕,經過對插槽的充分理解,你能夠構建本身的抽象組件。這有一篇很是好的博客文章來解釋如何作到這一點。github

但在你這樣作以前仍是要三思而行。咱們一直依靠 mixins 和 plain 函數來解決一些極端狀況。只需將 minxins 視爲您的抽象組件:web


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前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索