[Vue]組件編寫小結

前言

隨着js編程進入工程化紀元,代碼模塊化,組件化,成爲工程的具體落地方法。javascript

最近使用vue全家桶作了一個相似於iconfont的網站,在作的過程當中關於組件有了一些思考和總結,爲了鞏固,寫個小結。css

一 組件類型

根據我已知的組件的編寫方式,有四種介紹給你們:html

1.1 基本組件

最基本的組件由一個.vue文件構成,其中包含了基本的tempplate,script, style三大元素。前端

能夠經過props接收參數,$emit事件bus向父傳遞參數。vue

比較懶得我通常會在dev階段在components文件夾裏放置一個Demo.vue。寫好基本的元素以及組件註釋。java

import後在組件的compontents中聲明就能夠在模板裏標籤調用了。git

<template>
  <!-- 指南中推薦組件名應該始終爲多個單詞的,根組件App,<transition>、<component>之類除外 -->
  <Header></Header>
  <shop-cart></shop-cart>
</template>
components: { Header, ShopCart }複製代碼

這裏比較注意的是組件命名規範應該嚴格參考vue風格指南。讓駝峯和短橫線在該使用的地方使用。github

1.2 構造組件

構造類組件主要是用在想要經過js動態調用組件的場景裏,由一個該組件文件夾好比notice,中包含Notice.vue, index.js兩個文件組成。vuex

vue文件就是編寫基本的vue文件編程

index.js中

  • 使用vue的extend方法來返回一個Notice.vue的構造器對象,在對象原型上添加一些經常使用方法好比close
  • 編寫Notice函數對象,在函數中將構造器對象進行實例化(最基本的:創造一個div元素掛在el屬性上,你也能夠根據場景需求爲其配置上store,router,經過.$store獲取)
  • 將該實例的el屬性上的元素append到body(或者你想要的添加的元素)中
  • 將函數傳來的參數數據處理後對實例中數據進行賦值(等於props傳值,同時此處至關於作了每次打開組件時的週期。)
  • 將這個函數對象做爲default返回

/** 項目添加模態框 */
import Vue from 'vue'
import proModal from './ProModal.vue'
import store from '@/store/index'
import router from '@/router/index'
let proModalInstance
export default {
  open (modalType, packageInfoDatail) {
    if (!proModalInstance) {
      proModalInstance = new ProModalCreater({
        el: document.createElement('div'),
        store: store,
        router: router
      })
      document.body.appendChild(proModalInstance.$el)
    }
    proModalInstance.$data.modalType = modalType
    proModalInstance.$data.options4 = []
    proModalInstance.visible = true
    modalType === 'modify'
      ? (() => {
        proModalInstance.$data.packageInfoDetailTemp = packageInfoDatail
        proModalInstance.$data.headerName = '修改項目'
        proModalInstance.$data.value9 = []
        packageInfoDatail.coUsers.map((item) => {
          proModalInstance.$data.value9.push(item)
          proModalInstance.$data.options4.push(item)
        })
      })()
      : proModalInstance.init()
    if (modalType === 'create' && packageInfoDatail) {
      proModalInstance.fromPath = packageInfoDatail
    }
    // proModalInstance.$data.callback = callback
  }
}複製代碼

調用:

  • 能夠經過在main.js中調用而後將其掛載在Vue原型上再去組件this中調用方式調用

Vue.prototype._message = obj => {
  obj.duration = messageDurationTime
  ElementUI.Message(obj)
}

this._message.info('why so serious?')複製代碼

  • 也能夠在不一樣組件中引入而後再去調用

import ProModal from '@/components/common/proModal'
methods: {
  createPro () {
    // 打開模態框    
    ProModal.open('create')  
  },
}複製代碼

1.3 全局組件

全局組件主要是用在一些通用組件想要在各處組件裏使用標籤調用的場景,組成與構建組件相同。

vue文件就是編寫基本的vue文件(該注意的點仍是多注意下,全局對通用,顆粒的要求更高一些

index.js中

  • 引入組件ButtonComponent而且編寫一個組件對象用於導出,該組件對象中有一個install方法
  • install方法中核心:Vue.component("Button", ButtonComponent);
  • 返回該組件對象

import NoContentComponent from './NoContent.vue'
// 添加install方法 (插件方法)
const NoContent = {
  install: function (Vue) {
    Vue.component('NoContent', NoContentComponent)
  }
}
// 導出Buttonexport 
default NoContent複製代碼

在全局main.js中引入組件對象使用Vue.use()註冊該組件

Vue.use(NoContent)複製代碼

在各個組件中經過標籤直接調用

<no-content v-if="!Array.isArray(iconLibNowDetail.icons)">
  <template slot="default"> <span>尚未上傳圖標哦</span> <upload-btn :toPath="'/upload?type=iconLib&id=' + libId"></upload-btn> </template> </no-content>複製代碼

1.4 指令類組件

指令類主要是使用Vue.directive方法註冊一個指令,在指令中bind的方法中去實例組件並添加到響應dom處。這裏很少說,由於我沒用到。(想看怎麼用的去看參考Vue組件的三種調用方式

其結構相似於全局組件,只是調用是經過在某個元素上的指令屬性進行調用。

二 組件設計原則

好了,知道怎麼寫一個基本的組件了,路程剛剛開始,那麼如何寫好一個組件呢。若是你寫的組件是爲了目的而寫不考慮設計原則,相信很快就會被你本身所拋棄,而後重構組件。(小夥伴說我這一節寫的步驟有些亂不太好,後面會改進)

先說下個人組件設計思路:

  1. 思考組件類型:是基礎組件,仍是業務組件
  2. 思考組件核心:該組件核心是什麼,核心表明着極低的變更,甚至不變
  3. 思考組件顆粒度(複用性): 該組件是基礎組件會被多處複用 ?設計時儘可能最小化,減小ui數據綁定使其靈活輕巧 : 業務組件則能夠適當ui和數據綁定,只經過一部分傳參進行update
  4. 思考組件插槽:插槽的存放位置,後備內容,數據等
  5. 思考組件數據傳遞(可配置性): 是否須要數據傳遞 ?是否會深層傳參 ?採用vuex :注意props數據不要被組件內直接改變,$emit向上傳遞數據 :無數據傳遞,僅做爲ui層複用
    組件通訊這裏能夠再更多考慮,局部組件處嵌套通訊是否可使用bus來通訊,深層傳參是否使用inject來傳入,包括是否使用this.$refs.parent.xxData來獲取數據。這些都須要去考慮。
  6. 思考組件數據健康(內存管理,watcher下儘可能扁平數據存放,動態請求刷新)
  7. 思考組件性能(優化,提取)

三 複雜組件設計

這一節起的有點節題黨,這裏只是分享一點點點總結,不敢談設計,後續有好的總結會更新上來,大佬們輕拍哈哈

組件在一些場景中會變得複雜,其複雜性分爲組件自己的複雜和被應用場景的複雜。

自己比較複雜的組件如dataTimerPicker,Form之類的擁有複雜的配置項屬性以及methods,events,而且其中會包含子組件,子組件的slot,attributes,methods也會不少。

這裏僅僅分享三個場景:

1. 我在作一個IconList,當時想要一次性在組件中所有作好,就不想再多抽出子組件,結果發現會寫的很冗餘。因而很快就抽出了icon組件,IconList接受icons數組數據,在v-for中將item對象再傳入icon組件,icon中經過props拿到iconData,最終用來渲染出最終顯示的icon。

固然還能夠再對icon進行子組件抽取的,我目前仍是採用配置參數iconModalType方式+v-if來區分項目中和圖標庫內在不一樣權限下,三種modal層的顯示。後面能夠繼續使用mixIn(IconModal.vue中使用)+調用時<icon-modal :modalType="icon.modalType">方式來加載。

組合大於繼承,不用一次性去寫一個龐然大物,這樣會在複用的時候束手束腳失去靈活性。

2. 我在作一個FilterGroup,肯定了其核心是InputSearch結果到了後面發現仍是會遇到核心不肯定場景。因而這個時候FilterGroup只爲ui服務,子元素能夠經過slot來加載,slot中經過name將子組件放置到對應位置。下面是個demo,我當時就將InputSearch和Sort只做爲了FilterGroup中的元素來處理了,致使了後續須要經過很長的配置項在group上去肯定groupElement上的屬性,使Group自己屬性被混淆減弱了自身含義,增長了複用時理解難度。


<!-- group合理設計應該爲使用slot插入須要的groupElement而不是直接去集成div,即便是很是固有化的元素,如其中的兩個元素:排序和搜索元素 -->
<btn-group inputPlaceVal="請搜索圖標" :useSort="true" @sort="proSort" :sortOptions="options" @search="searchIcon" >
   <template slot="body">
       <div class="radius-btn" v-if="_isProManager() >= 2" @click="createPro">
           <img :src="iconAddLib" alt="">
       </div>
   </template>
</btn-group>複製代碼


正確的是應該去考衡抽出的必要性,假如該元素不復雜不須要傳遞數據自身無複雜方法,固定爲ui項,就能夠經過配置屬性來取決其是否顯示,好比element的input的icon,使用prefix-iconsuffix-icon 屬性在 input 組件首部和尾部增長顯示圖標,固然在句尾說清了:也能夠經過 slot 來放置圖標 。由於slot伴隨着子組件的編寫,也是有代價的,因此對於一些默認最小項,我的認爲能夠內置編寫好,經過配置屬性來顯示。

固然,能夠看到,slot對於一個組件是多麼的重要,一個複雜的子組件,一定不是一次性在組件內寫好的,而是通過提取優化思考獲得的一個組合結果,而且經得起復用和靈活擴展。

3. 我在作一個BatchOperate,批量操做組件時發現本身須要經過得到兄弟組件iconlist中被批量選擇的icon的id數據,而且將這些icon加入ShopCart,這個時候對於數據以及狀態的考量就來了。

最後選用了vuex加LocalStorage方式來解決了這個數據通訊的問題。(有點晚了,先不細說...)

這幾個場景事最想表達的是:

在模塊化思想的今天,這種抽出組合的思惟是很靈活的,能夠在寫組件的時候多去思考下模塊化,包括公共方法,公共樣式,vue的mixIn,scss的mixIn,公共變量倉庫store集中處理,組件最下化,讓重複性代碼模塊化抽出,再經過配置靈活組合。這種作法可讓代碼在後續的維護中很是清爽,一鍵修改專制各類公共改動,不再用跑到各個地方去作一下下的修改,而且避免了耦合帶來的深層代碼纏繞,能夠說真的很好用了。

今天先寫到這,第三節總結的不是很好,只是先羅列出本身以前想到的一些問題和處理,具體的優化想法會和組內小夥伴討論後再更新的。



參考

Vue組件實現tips的總結

[譯] 前端組件設計原則

前端工程化、模塊化、組件化看法

Vue組件的三種調用方式

vue 組件的三種使用方式教程

element

相關文章
相關標籤/搜索