經過 自建vue組件 air-ui (4) -- air-ui 環境搭建和目錄結構 咱們已經搭好了 air-ui
項目,接下來就是開始寫組件了。javascript
常見的 ui 組件有三種類型:css
這個是最多見的組件類型,好比 button
, checkbox
等等, 使用的時候是這樣子的:html
<air-button>這是一個按鈕</air-button>
複製代碼
內置服務類型的組件,其實就是綁定到 VUE
的全局對象中,好比 message
, notification
, loading
,使用方式是這樣子的:vue
this.$message({
message: '警告哦,這是一條警告消息',
type: 'warning'
});
複製代碼
指令方式的組件,好比 loading
, 使用方式是這樣子的 v-xxx
:java
<air-button type="primary" @click="openFullScreen1" v-loading.fullscreen.lock="fullscreenLoading">
指令方式
</air-button>
複製代碼
可是標籤方式的組件是最多見的。 因此本節就以標籤方式的 button
組件來講明。 另外兩種方式後面有時間再講。node
首先在建立一個組件的時候,必定要考慮清楚所要建立組件的表現形式,好比 button
按鈕,組件的表現方式可能有兩種:element-ui
air-button
air-button-group
這邊多個單詞要用中劃線_
分隔開。 因此目錄結構就是這樣子:sass
components/
| |--- button/
| | |--- src/
| | | |--- button.vue
| | | |--- button-group.vue
| | |--- index.js
複製代碼
目錄結構很簡單,事實上後面全部的組件的目錄結構都是這樣子的, 一個 index.js
用來導出對象, src
主要寫組件的邏輯和定義,以本例來講, button.vue
就是 air-button
標籤的實現文件, 而 button-group.vue
就是 air-button-group
標籤的實現文件。bash
具體代碼以下: src/components/button/src/button.vue
:post
<template>
<button class="air-button" @click="handleClick" :disabled="buttonDisabled || loading" :autofocus="autofocus" :type="nativeType" :class="[ type ? 'air-button--' + type : '', buttonSize ? 'air-button--' + buttonSize : '', { 'is-disabled': buttonDisabled, 'is-loading': loading, 'is-plain': plain, 'is-round': round, 'is-circle': circle } ]" >
<i class="air-icon-loading" v-if="loading"></i>
<i :class="icon" v-if="icon && !loading"></i>
<span v-if="$slots.default"><slot></slot></span>
</button>
</template>
<script> export default { name: 'AirButton', inject: { elForm: { default: '' }, elFormItem: { default: '' } }, props: { type: { type: String, default: 'default' }, size: String, icon: { type: String, default: '' }, nativeType: { type: String, default: 'button' }, loading: Boolean, disabled: Boolean, plain: Boolean, autofocus: Boolean, round: Boolean, circle: Boolean }, computed: { _elFormItemSize () { return (this.elFormItem || {}).elFormItemSize }, buttonSize () { return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size }, buttonDisabled () { return this.disabled || (this.elForm || {}).disabled } }, methods: { handleClick (evt) { this.$emit('click', evt) } } } </script>
複製代碼
src/components/button/src/button-group.vue
的實現代碼:
<template>
<div class="air-button-group">
<slot></slot>
</div>
</template>
<script> export default { name: 'AirButtonGroup' } </script>
複製代碼
事實上,整個邏輯的大部分實現幾乎跟 element-ui
如出一轍,只有一些小細節不同,好比:
el-
改爲 air-
name
的 El
改爲 Air
ps: 並且
air-ui
最後完成的時候,從功能上來講,絕大部分組件的功能都跟element-ui
的對應組件如出一轍,只有某些組件,好比color-picker
,table
等由於業務需求,有再進行了一些參數和方法的擴展。
並且 index.js
其實就是組件的導出,代碼以下,src/components/button/index.js
:
import AirButton from './src/button'
AirButton.install = function (Vue) {
Vue.component(AirButton.name, AirButton)
}
export default AirButton
複製代碼
若是排除掉那個 install
, 這個文件簡直能夠去掉了,由於它就是把 button.vue
導出的對象,從新又導出了一次。 而 install
的存在才顯得這個文件有意義。 install
這個方法定義是由於後續若是這個組件是要容許單獨被 vue 引用的,也是單獨被打包成文件出來的。 vue 設置全局組件的話,是這個 API:
Vue.component(yourModule.name, yourModule)
複製代碼
可是若是 vue 加載第三方庫的話,是這個 API:
Vue.use(yourModule)
複製代碼
這時候就會去執行 yourModule
對象的 install
方法。 因此 index.js
文件實現 install
方法,只是爲了後面讓 vue 單獨設置全局組件的時候,除了能夠用標準 component
語法以外,還能夠用 use
語法,而 use
語法會觸發 install
方法,而後再在 install
方法去實現 component
語法。因此對於 button 組件來講,若是要用 vue 設置爲全局組件的話,有這兩種引用方式:
import Vue from 'vue';
import Button from './components/button'
Vue.component(Button.name, Button)
複製代碼
或者是
import Vue from 'vue';
import Button from './components/button'
Vue.use(Button);
複製代碼
這兩個效果實際上是同樣的。最後都實現了用 component
方法註冊成全局組件。
既然邏輯代碼寫好了,接下來是測試了。 因此修改首頁 hoome.vue
改爲這樣子
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<air-button disabled>默認按鈕</air-button>
<air-button type="primary">主要按鈕</air-button>
<br>
<air-button-group>
<air-button type="primary">主要按鈕</air-button>
<air-button type="success">成功按鈕</air-button>
<air-button type="info">信息按鈕</air-button>
<air-button type="warning">警告按鈕</air-button>
<air-button type="danger">危險按鈕</air-button>
</air-button-group>
</div>
</template>
<script> import AirButton from '../components/button/src/button' import AirButtonGroup from '../components/button/src/button-group' export default { data () { return { msg: `AIR-UI - 基於vue2.x,可複用UI組件` } }, components: { AirButton, AirButtonGroup }, } </script>
複製代碼
有效果了,可是發現並無樣式:
因此咱們寫好樣式: src/styles/button.scss
, 寫好以後把樣式加上去:
import AirButton from '../components/button/src/button'
import AirButtonGroup from '../components/button/src/button-group'
import '../styles/button.scss'
複製代碼
可是發現編譯的時候,報錯:
看起來是 sass
模塊和對應的 loader
沒有裝的緣故, 這時候要手動安裝:
yarn add sass-loader node-sass --dev
複製代碼
可是發現仍是報錯:
網上查了一下資料,發現原來是sass-loader
的版本太高致使,因其最新版本爲 8.0.0
,此會致使編譯出錯, 我從新換成 6.0.7
就能夠了:
yarn remove sass-loader
yarn add sass-loader@6.0.7 --dev
複製代碼
這樣子,編譯就能夠了。
這樣子這個組件就完成了。可是發現好像還能夠再優化:
上面雖然組件已經作好了,可是能夠看到再引用的時候,是做爲局部組件來使用的,每次都要在 home.vue
引入 vue 文件和 css 文件。因此咱們要註冊成 vue 的全局組件,這樣子在寫 demo 的時候,就不用引入資源了。 因此 src/main.js
要改一下,加上如下代碼:
import Button from './components/button/src/button'
import ButtonGroup from './components/button/src/button-group'
import './styles/button.scss'
Vue.component(Button.name, Button)
Vue.component(ButtonGroup.name, ButtonGroup)
複製代碼
這樣子 button
和 button-group
就會被註冊成全局組件了。 因此這時候我 home.vue
就能夠簡寫爲這樣子, src/views/home.vue
:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<air-button disabled>默認按鈕</air-button>
<air-button type="primary">主要按鈕</air-button>
<br>
<air-button-group>
<air-button type="primary">主要按鈕</air-button>
<air-button type="success">成功按鈕</air-button>
<air-button type="info">信息按鈕</air-button>
<air-button type="warning">警告按鈕</air-button>
<air-button type="danger">危險按鈕</air-button>
</air-button-group>
</div>
</template>
<script> export default { data () { return { msg: `AIR-UI - 基於vue2.x,可複用UI組件` } }, } </script>
複製代碼
去掉了組件的導入 和 components
的聲明。直接默認使用全局組件。
雖然能夠註冊全局組件了。可是仍是不夠優雅(明明是兩個組件的聲明,可是引入的路徑居然是在 button
的src 目錄下,都沒有分開), 並且也不能使用 vue.use
語法,接下來咱們來兼容一下 use
語法,咱們知道要使用 use
語法,一個很重要的方式就是組件要有定義 install
方法,好比 button
的 src/components/button/index.js
就有:
import AirButton from './src/button'
AirButton.install = function (Vue) {
Vue.component(AirButton.name, AirButton)
}
export default AirButton
複製代碼
可是 button-group
沒有啊,因此咱們要爲 button-group 再建立一個獨屬於他的組件目錄:而且在目錄下建立一個 index.js
文件,完整的文件路徑就是 src/components/button-group/index.js
, 內容以下:
import AirButtonGroup from '../button/src/button-group'
AirButtonGroup.install = function (Vue) {
Vue.component(AirButtonGroup.name, AirButtonGroup)
}
export default AirButtonGroup
複製代碼
是的,咱們不須要再去寫 button-group
組件的邏輯代碼了,由於 button
組件的 src 裏面幫咱們寫好了,咱們只須要引用這個 vue 文件,而且定義好 install
方法,最後導出就好了。 最後再調整一下 main.js
的寫法:
import Button from './components/button'
import ButtonGroup from './components/button-group'
import './styles/button.scss'
Vue.use(Button)
Vue.use(ButtonGroup)
複製代碼
寫成這樣子,就更優雅了。
固然這邊還有一個細節,還能夠再優化一下,由於咱們從目錄結構上來講, button
和 button-group
這兩個是單獨的組件,那麼 button-group
也應該也有本身的 scss 文件,可是事實上 button-group
相關的樣式都寫在 button.scss
上了,因此咱們爲了一致性,咱們就新建了一個空的 scss 文件 button-group.scss
, 因此main.js
能夠再加上引入 button-group.scss
:
import Button from './components/button'
import ButtonGroup from './components/button-group'
import './styles/button.scss'
import './styles/button-group.scss'
Vue.use(Button)
Vue.use(ButtonGroup)
複製代碼
如今咱們有兩個組件了,button
和 button-group
, 後面咱們還會增長很是多的組件。總不可能咱們後面在註冊組件的時候,都要在 main.js
中導入這些組件的 js 和 css 文件吧,那但是太多了。因此這些組件合起來應該是一個組件庫,就像 element-ui
同樣,咱們只須要引入這個組件庫對象,那麼就可使用到這個組件庫所包含的全部組件。
air-ui
也是同樣的作法,所以咱們也要作本身的組件庫,而後將咱們寫的這些組件都放到這個組件庫裏面,而後再到 main.js
中去引用這個組件庫,就至關於註冊了這個組件庫的全部的組件了。
因此 src/components
增長了一個文件 src/components/index.js
:
import Button from './button'
import ButtonGroup from './button-group'
const components = {
Button,
ButtonGroup
}
const install = function (Vue) {
Object.keys(components).forEach(key => {
Vue.component(components[key].name, components[key])
})
}
export default {
install
}
複製代碼
這個很好理解,由於要用 vue.use
來加載這個組件庫,因此導出的對象,要有 install
方法,而且由於要把這些組件都註冊成 vue 全局組件,因此這一步就在 install
方法裏面來處理。
而後在 main.js
將以前的去掉,改爲這樣子:
import AirUI from './components/index'
Vue.use(AirUI)
複製代碼
這樣就更完美了,不事後面調試的時候,發現沒有樣式,查了一下,發現樣式沒有導入, 因此咱們樣式的導入方式也應該改一下,換成導入組件庫樣式的方式,而不是在 main.js
中一個組件樣式一個組件樣式的導入。 因此咱們在 src/styles
目錄新增長了 index.scss
, 而後把當前的組件的樣式都導入進去, src/styles/index.scss
:
@import "./button.scss";
@import "./button-group.scss";
複製代碼
而後在 main.js 中導入這個總的組件庫的 scss 文件便可了。
import AirUI from './components/index'
import './styles/index.scss'
Vue.use(AirUI)
複製代碼
哇,這樣就真的很完美了。 基本上一個最小規模的組件庫的雛形就出來了。
咱們如今已經能夠很好的寫一些標籤組件了,下節咱們講一下怎麼寫 指令組件和內置服務組件。
系列文章: