1. 程式人生 > >打造 Vue.js 可複用元件

打造 Vue.js 可複用元件

Vue.js 是一套構建使用者介面的漸進式框架。我們可以使用簡單的 API 來實現響應式的資料繫結和組合的檢視元件。

從維護檢視到維護資料,Vue.js 讓我們快速地開發應用。但隨著業務程式碼日益龐大,元件也越來越多,元件邏輯耦合嚴重,使程式碼維護變得十分困難。

同時,Vue.js 的介面和語法十分自由,實現同一功能有若干種方法。每個人解決問題的思路不一樣,寫出來的程式碼也就不一樣,缺乏團隊內的規範。

本文旨在從元件開發的不同方面列舉出合理的解決方法,作為建立元件規範的一個參考。

導航

  • 構成元件
  • 元件間通訊
  • 業務無關
  • 名稱空間
  • 上下文無關
  • 資料扁平化
  • 使用自定義事件實現資料的雙向繫結
  • 使用自定義 watcher 優化 DOM 操作
  • 專案骨架

構成元件

元件,是一個具有一定功能,且不同元件間功能相對獨立的模組。元件可以是一個按鈕、一個輸入框、一個視訊播放器等等。

可複用元件,高內聚、低耦合。

那麼,什麼構成了元件呢。以瀏覽器的原生元件 video 為例,分析一下元件的組成部分。

<video
  src="example.mp4"
  width="320"
  height="240"
  onload="loadHandler"
  onerror="errorHandler">
  Your browser does not support the video tag.
</video>

例項中能看出,元件由狀態

事件和巢狀的片斷組成。狀態,是元件當前的某些資料或屬性,如 video 中的 src、width 和 height。事件,是元件在特定時機觸發一些操作的行為,如 video 在視訊資源載入成果或失敗時會觸發對應的事件來執行處理。片段,指的是巢狀在元件標籤中的內容,該內容會在某些條件下展現出來,如在瀏覽器不支援 video 標籤時顯示提示資訊。

在 Vue 元件中,狀態稱為 props,事件稱為 events,片段稱為 slots。元件的構成部分也可以理解為元件對外的介面。良好的可複用元件應當定義一個清晰的公開介面。

  • Props 允許外部環境傳遞資料給元件
  • Events 允許元件觸發外部環境的副作用
  • Slots 允許外部環境將額外的內容組合在元件中。

使用 vue 對 video 元件做拓展,構造出一個支援播放列表的元件 myVideo:

<my-video
  :playlist="playlist"
  width="320"
  height="240"
  @load="loadHandler"
  @error="errorHandler"
  @playnext="nextHandler"
  @playprev="prevHandler">
  <div slot="endpage"></div>
</my-video>

myVideo 元件有著清晰的介面,接收播放列表、播放器寬高等狀態,能夠觸發載入成功或失敗、播放上一個或下一個的事件,並且能自定義播放結束時的尾頁,可用於插入廣告或顯示下一個視訊資訊。

元件間通訊

在 Vue.js 中,父子元件的關係可以總結為 props down, events up 。父元件通過 props 向下傳遞資料給子元件,子元件通過 events 給父元件傳送訊息。看看它們是怎麼工作的。


業務無關

命名

元件的命名應該跟業務無關。應該依據元件的功能為元件命名。

例如,一個展示公司部門的列表,把每一項作為一個元件,並命名為 DepartmentItem。這時,有一個需求要展示團隊人員列表,樣式跟剛剛的部門列表一樣。顯然,DepartmentItem 這個名字就不適合了。

因此,可複用元件在命名上應避免跟業務扯上關係,以元件的角色、功能對其命名。Item、ListItem、Cell。可以參考 Bootstrap、ElementUI 等一些 UI 框架的命名。

業務資料無關

可複用元件只負責 UI 上的展示和一些互動以及動畫,如何獲取資料跟它無關,因此不要在元件內部去獲取資料,以及任何與服務端打交道的操作。可複用元件只實現 UI 相關的功能。

元件職責

約束好元件的職責,能讓元件更好地解耦,知道什麼功能是元件實現的,什麼功能不需要實現。

元件可以分為通用元件(可複用元件)和業務元件(一次性元件)。

可複用元件實現通用的功能(不會因元件使用的位置、場景而變化):

  • UI 的展示
  • 與使用者的互動(事件)
  • 動畫效果

業務元件實現偏業務化的功能:

  • 獲取資料
  • 和 vuex 相關的操作
  • 埋點
  • 引用可複用元件

可複用元件應儘量減少對外部條件的依賴,所有與 vuex 相關的操作都不應在可複用元件中出現。

元件應當避免對其父元件的依賴,不要通過 this.$parent 來操作父元件的示例。父元件也不要通過 this.$children 來引用子元件的示例,而是通過子元件的介面與之互動。

名稱空間

可複用元件除了定義一個清晰的公開介面外,還需要有名稱空間。名稱空間可以避免與瀏覽器保留標籤和其他元件的衝突。特別是當專案引用外部 UI 元件或元件遷移到其他專案時,名稱空間可以避免很多命名衝突的問題。

<xl-button></xl-button>
<xl-table></xl-table>
<xl-dialog></xl-dialog>
...

業務元件也可以有命令空間,跟通用元件區分開。這裡用 st (section) 來代表業務元件。

<st-recommend></st-recommend>
<st-qq-movie></st-qq-movie>
<st-sohu-series></st-sohu-series>

上下文無關

還是上面那句話,可複用元件應儘量減少對外部條件的依賴。沒有特別需求且單個元件不至於過重的的前提下,不要把一個有獨立功能的元件拆分成若干個小元件。

<table-wrapper>            
  <table-header slot="header" :headers="exampleHeader"></table-header>            
  <table-body slot="body" :body-content="exampleContents"></table-body>          
</table-wrapper>

TableHeader 元件和 TableBody 元件依賴當前的上下文,即 TableWrapper 元件巢狀的環境下。你可以有更好的解決辦法:

<xl-table :headers="exampleHeader" :body-content="exampleContents"></xl-table>

上下文無關原則能夠降低元件使用的門檻。

資料扁平化

定義元件介面時,儘量不要將整個物件作為一個 prop 傳進來。

<!-- 反例 -->
<card :item="{ title: item.name, description: item.desc, poster: item.img }></card>

每個 prop 應該是一個簡單型別的資料。這樣做有下列幾點好處:

  • 元件介面清晰
  • props 校驗方便
  • 當服務端返回的物件中的 key 名稱與元件介面不一樣時,不需要重新構造一個物件
<card
  :title="item.name"
  :description="item.desc"
  :poster="item.img">
</card>

扁平化的 props 能讓我們更直觀地理解元件的介面。

使用自定義事件實現資料的雙向繫結

有時候,對於一個狀態,需要同時從元件內部和元件外部去改變它。

例如,模態框的顯示和隱藏,父元件可以初始化模態框的顯示,模態框元件內部的關閉按鈕可以讓其隱藏。一個好的辦法是,使用自定義事件改變父元件中的值:

<modal :show="show" @showchange="show = argument[0]"></modal>
<!-- Modal.vue -->

<template>
  <div v-show="show">
    <h3>標題</h3>
    <p>內容</p>
    <a href="javascript:;" @click="close">關閉</a>
  </div>
</template>

<script>
  export default {
    props: {
      show: String
    },
    methods: {
      close () {
        this.$emit('input', false)
      }
    }
  }
</script>

使用者點選關閉按鈕時,Modal 元件傳送一個 input 自定義事件給父元件。父元件監聽到 input 事件時,把 show 設定為事件回撥的第一個引數。

特別地,當狀態名稱為 value,事件名稱為 input 時,可以使用 v-model 指令語法糖:

<modal :value="show" @input="show = argument[0]"></modal>

等價於

<modal v-model="show"></model>

要讓元件的 v-model 生效,它必須:

  • 接受一個 value 屬性
  • 在有新的 value 時觸發 input 事件

注意:由於每個元件的 input 事件只能用來對一個數據進行雙向繫結,所以當存在多個需要向上同步的資料時,請不要使用 v-model,請使用多個自定義事件,並在父元件中同步新的值。

<modal
  :show="show" @showchange="show = argument[0]"
  :content="content" @contentchange="content = argument[0]">
</model>

使用自定義 watcher 優化 DOM 操作

在開發中,有些邏輯無法使用資料繫結,無法避免需要對 DOM 的操作。例如,視訊的播放需要同步 Video 物件的播放操作及元件內的播放狀態。可以使用自定義 watcher 來優化 DOM 的操作。

<!-- MyVideo.vue -->

<template>
  <div>
    <video ref="video" src="src"></video>
    <a href="javascript:;" @click="togglePlay">{{ playing ? '暫停' : '播放' }}</a>
  </div>
</template>

<script>
  export default {
    props: {
      src: String // 播放地址
    },
    data () {
      return {
        playing: false // 是否正在播放
      }
    },
    watch: {
      // 播放狀態變化時,執行對應操作
      playing (val) {
        let video = this.$refs.video
        if (val) {
          video.play();
        } else {
          video.pause();
        }
      }
    },
    method: {
      // 切換播放狀態
      togglePlay () {
        this.playing = !this.playing
      }
    }
  }
</script>

示例中,自定義 watcher 在監聽到 playing 狀態變化時,會執行播放或暫停操作。遇到對視訊播放狀態的處理時,只需要關注 playing 狀態即可。

專案骨架

單元件不異過重,元件在功能獨立的前提下應該儘量簡單,越簡單的元件可複用性越強。當你實現元件的程式碼,不包括CSS,有好幾百行了(這個大小視業務而定),那麼就要考慮拆分成更小的元件。

當元件足夠簡單時,就可以在一個更大的業務元件中去自由組合這些元件,實現我們的業務功能。因此,理想情況下,元件的引用層級,只有兩級。業務元件引用通用元件。

我們可以得到一個扁平化的結構。


在一個龐大的專案當中,元件間的引用關係會更復雜一些。當單頁應用有多個路由,每個路由元件過重,需要拆分模組時。元件結構會變成下圖這樣。


按照這個思路構建我們的專案,最後的原始碼目錄結構(不包括構建流程檔案):

│  App.vue          # 頂級元件
│  client-entry.js  # 前端入口檔案config.js        # 配置檔案
│  main.js          # 主入口檔案
│  
├─api               # 介面 API
├─assets            # 靜態資源
├─components        # 通用元件
├─directives        # 自定義指令
├─mock              # Mock 資料
├─plugins           # 自定義外掛
├─router            # 路由配置
├─sections          # 業務元件
├─store             # Vuex Store
├─utils             # 工具模組
└─views             # 路由頁面元件

在通用元件中還可以區分容器元件、佈局元件和其他功能性元件等。

轉載:http://www.jianshu.com/p/79a37137e45d

個人建了前端學習群,旨在一起學習前端。純淨、純粹技術討論,非前端人員勿擾!入群加我微信iamaixiaoxiao。


相關推薦

打造 Vue.js 元件

Vue.js 是一套構建使用者介面的漸進式框架。我們可以使用簡單的 API 來實現響應式的資料繫結和組合的檢視元件。 從維護檢視到維護資料,Vue.js 讓我們快速地開發應用。但隨著業務程式碼日益龐大,元件也越來越多,元件邏輯耦合嚴重,使程式碼維護變得十分困難。

Vue.js元件開發流程

本文由蔡述雄發表 接下來我們會詳細分析下如何完成由多個元件組成一個複用元件的開發流程。 下面先看看我們的需求 列表元件quiList.vue 本節我們主要要完成這樣一個列表功能,每一行的列表是一個元件,列表內可能出現按鈕元件或者箭頭元件,點選按鈕元件可以自定義事件,同時可以根據不同的引數來決

元件

類——class——函式、資料成員以及其生命週期管理描述(解構函式和建構函式)的集合 名稱空間——namespace——類、函式及其靜態成員的宣告的集合,可能會分佈在多個檔案中。 標頭檔案——.h——類定義、模板定義、函式宣告(帶有預設實參定義)、inline函式定義、靜態

做一個的 echarts-vue 元件(延遲動畫載入)

在 vue 專案使用 echarts 的場景中,以下三點不容忽視:1. 視覺化的資料往往是非同步載入的;2. 若一個頁面存在大量的圖表( 尤其當存在關係圖和地圖時 ),往往會導致該頁面的渲染速度很慢並可能在幾秒內卡死,產生極差的使用者體驗。3. 引入 echarts 元件導致編譯後的檔案過大從而使得首次訪

vue中封裝元件

本次封裝的元件以toast元件為例 以前使用移動端ui外掛時,通過一句程式碼比如 $.toast( ‘ 需要顯示的內容 ’ ),從而在頁面上展示這段文字,並在一定時間後消失。 現在我們也嘗試自己封裝toast元件。 準備工作:vue-cli腳手架工程 先看一下涉及到的檔案目錄截圖:

Vue.jsKey值來管理元素

Vue 會盡可能高效地渲染元素,通常會複用已有元素而不是從頭開始渲染。這麼做除了使 Vue 變得非常快之外,還有其它一些好處。1.那麼在上面的程式碼中切換type將不會清除使用者已經輸入的內容。因為兩個模板使用了相同的元素,input不會被替換掉——僅僅是替換了它的place

vue重新整理當前路由:router-view 元件時不重新整理的3種解決方案總結

vue-router是Vue.js官方的路由外掛,它和vue.js是深度整合的,適合用於構建單頁面應用。vue的單頁面應用是基於路由和元件的,路由用於設定訪問路徑,並將路徑和元件對映起來。傳統的頁面應用,是用一些超連結來實現頁面切換和跳轉的。在vue-router單頁面應用中,則是路徑之間的切換,也

小程式學習--JS點選按鈕得到使用者授權得到資訊(元件)

首先,第一步,建立一個按鈕的元件,方便複用,當點選按鈕時候,會跳出是否授權的對話方塊: 元件的wxml程式碼: <button bind:getuserinfo="onGetUserInfo" open-type="{{openType}}" plain="{{true}}" cla

Vue性&組合

  二、自定義指令 除了核心功能預設內建的指令(v-model和v-show),Vue也允許註冊自定義指令。在Vue2.0中,程式碼複用和抽象的主要形式是元件,然而有的情況下,你仍然需要對普通DOM元素進行底層操作,這時會用到自定義指令。如當頁面載入時,輸入框將獲得焦點,只要你

Vue性&組合

二、自定義指令 除了核心功能預設內建的指令(v-model和v-show),Vue也允許註冊自定義指令。在Vue2.0中,程式碼複用和抽象的主要形式是元件,然而有的情況下,你仍然需要對普通DOM元素進行底層操作,這時會用到自定義指令。如當頁面載入時,輸入框將獲得焦點,只

原生態js選框的美化並且

原生態js美化複選框,當去掉js之後,還可以保留原有的複選框效果,最難得的是它可以在一個網頁中多次複用~,感興趣的程式猿可以看看。 css: .checkbox{ display:inline-block; width:20px;height:20px; border-ra

原生態js對單選框的美化並且

基於純js對單選框的美化,不僅可以設定想設定的顏色,也可以在同一頁面複用多個。還會對程式碼進行詳細的解析,對剛入門的你有一定的幫助哦~ css:     .radio{         display:

SpringMVC 基本配置及部分元件配置

整理一下今年用過的SpringMVC及相關元件的配置 Spring版本4.2.0.RELEASE web.xml版本3.0 GroupId為personal.cat 第一部分、基本配置 1、Spring+SpringMVC的骨架 依賴jar包 <!--Spring核心容器beans

iOS 高效靈活地配置檢視元件的主題

  本文首發於 [Ficow Shen's Blog](https://ficow.cn),原文地址: [iOS 高效靈活地配置可複用檢視元件的主題](https://blog.ficow.cn/post/19)。   ## 內容概覽 - 前言 - 如何配置主題? - 如何更高效地配

Vue.js 排序列表 (Sortable & Searchable Tables) 元件

可排序表格 (Sortable & Searchable Tables) 在網頁和表單設計中非常常用。使用者可以通過點選表頭對將表格以該列做順序或降序排列,也可以利用 Search Box 對錶格內容進行篩選。這個元件曾被運用於 X-Ray Diffraction Analysis App 和 Ext

基於vue.js的簡單戶管理

-c png -h search prev hour pad includes pattern 功能描述:添加、修改、搜索過濾 效果圖: 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head&

js程式碼

原文連結:https://github.com/TooBug/javascript.patterns/blob/master/chapter6.markdown 程式碼複用模式 程式碼複用是一個既重要又有趣的話題。如果你面對自己或者別人已經寫好的程式碼,而這些程式碼又是經過測試的、可維護的、

Vue.js框架--Vuex實現元件裡資料持久化(二十八)

主要操作技能:      Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式      新聞頁面每次切換路由時,再次訪問就會請求資料;那麼如何直接從vuex中持久化資料呢?      

Vue.js(六)—— 元件:slot用法

目錄 一、預設情況下(不使用slot) 二、單個slot 三、具名slot 四、編譯作用域 五、預設插槽的內容 六、作用域插槽 七、訪問slot Vue 實現了一套內容分發的 API,將 <slot> 元素作為承載分發內容的

Vue.js的復組件開發流程

調用 vuejs 現在 png 特定 emp template 查看 按鈕組件 本文由蔡述雄發表 接下來我們會詳細分析下如何完成由多個組件組成一個復用組件的開發流程。 下面先看看我們的需求 列表組件quiList.vue 本節我們主要要完成這樣一個列表功能,每一行的列表是