手把手教你寫 Vue UI 組件庫@vue2.0

手把手教你寫 Vue UI 組件庫

最近在研究 muse-ui 的實現,發現網上不多有關於 vue 插件具體實現的文章,官方的文檔也只是一筆帶過,對於新手來講並不算友好。javascript

筆者結合官方文檔,與本身的摸索總結,以最簡單的 FlexBox 組件爲例子,帶你們入門 vue 的插件編寫,若是您是大牛,不喜勿噴~css

項目結構html

| src
| ---| plugin
| ---| ---| flexbox                # 組件文件夾
| ---| ---| ---| flexbox.vue       # flex 佈局的父組件
| ---| ---| ---| flexboxItem.vue   # flex 佈局的子組件
| ---| ---| ---| flexbox.scss      # 樣式文件,我使用的是 sass
| ---| ---| ---| index.js          # 組件的出口
| ---| ---| styles                 # 公用的 css 樣式文件
| ---| ---| index.js               # 插件的出口
| ---| App.vue
| ---| main.js

<一> 讓項目裝載插件

首先,咱們不去理會組件的具體實現,先讓咱們的項目可以正常裝載一個咱們自定義的插件vue

如今,咱們的目標,是讓項目可以正常顯示這兩個組件,能顯示文本 flexbox demo 就能夠啦!java

./src/plugin/flexbox/flexbox.vuegit

<template>
  <div>flexbox demo</div>
</template>

<script>
export default {
    // 這是該組件的自定義名稱,
    // 以後引用組件時就會用到這個名稱。
    name: 'my-flexbox'
}
</script>

./src/plugin/flexbox/flexboxItem.vuegithub

<template>
    <div>flexboxItem demo</div>
</template>

<script>
export default {
    name: 'my-flexbox-item'
}
</script>

./src/plugin/flexbox/index.jsvue-router

這是整個 flexbox 組件的出口文件。\
由於這個組件有兩個子組件,因此咱們將引入的 default 更名爲該組件的名稱。{ default as flexbox }sass

// 引用 scss 文件
import './flexbox.scss'  

// 引用組件
export { default as flexbox } from './flexbox.vue'
export { default as flexboxItem } from './flexboxItem.vue'

./src/plugin/index.jsbash

如今,咱們來到插件的出口文件。

// ----- 1
import * as flexbox from './flexbox'

// ----- 2
const components = {
    ...flexbox
}

// ----- 3
const install = function (Vue, Option) {
    // ----- 4
     Object.keys(components).forEach((key) => {
        Vue.component(components[key].name, components[key])
    })
}

// ----- 5
export default {
    install
}
  1. 引入組件

  2. 定義 components 變量

  3. 這裏是重點,vue 爲編寫插件提供了一個 install(Vue, Option) 方法,該方法爲 vue 添加全局功能;

    該方法有兩個參數,第一個是 Vue構造器,第二個是可選的參數;

  4. 使用 vue 的全局方法 Vue.component(Name, Object) 定義組件,第一個參數是組件名,第二參數是組件對象;

  5. 最後將組件默認導出。

./src/main.js

咱們來到 main.js,在這裏,咱們將進行插件的最後配置啦。

使用 vue 的全局方法 Vue.use(PluginName, Options),第一個參數是插件的名字,第二個是可選的參數。

import plugin from './plugin'
Vue.use(plugin)

./src/App.vue

終於,咱們能夠在項目中引用咱們定義的組件啦!

<template>
    <my-flexbox></my-flexbox>
    <my-flexbox-item></my-flexbox-item>
</template>

<二> Flexbox 組件的實現

組件的具體實現,就和平時本身寫組件的方法是同樣的了。

這裏先貼出代碼,我會將具體原理寫在代碼註釋裏面。

./src/plugin/flexbox/flexbox.vue

<template>
    <!-- 爲組件綁定一個類,這個類的值經過計算屬性來得出 -->
    <div class="my-flexbox"
         :class="classObj">
        <!-- slot 用來裝載子組件,my-flexbox-item -->
        <slot></slot>
    </div>
</template>

<script>
export default {
    name: 'my-flexbox',
    props: {
        // 子組件 my-flexbox-item 之間是否存在間隙,
        // 默認,8px 的間隙。
        gutter: {
            type: Number,
            default: 8
        },
        // 子組件的排列方式,水平,或垂直排列。
        orient: {
            type: String,
            default: 'horizontal'
        },
        justify: {
            type: String
        },
        align: {
            type: String
        },
        wrap: {
            type: String,
            default: 'nowrap'
        }
    },
    computed: {
        // 咱們經過父級傳遞過來的參數,
        // 來判斷該組件須要應用哪些樣式
        // 如:<my-flexbox orient="vertical" justify="flex-start"></my-flexbox>
        classObj () {
            let classObj = {};

            // orient
            if (this.orient === 'vertical') classObj['flex-vertical'] = true;

            // wrap
            if (this.wrap === 'wrap') {
                classObj['flex-wrap'] = true
            } else {
                classObj['flex-nowrap'] = true
            }

            // justify
            switch (this.justify) {
                case 'flex-start':
                    classObj['justify-start'] = true;
                    break;
                case 'flex-end':
                    classObj['justify-end'] = true;
                    break;
                case 'center':
                    classObj['justify-center'] = true;
                    break;
                case 'space-between':
                    classObj['justify-space-between'] = true;
                    break;
                case 'space-around':
                    classObj['justify-space-around'] = true;
                    break
            };

            // align
            switch (this.align) {
                case 'flex-start':
                    classObj['align-start'] = true;
                    break;
                case 'flex-end':
                    classObj['align-end'] = true;
                    break;
                case 'center':
                    classObj['align-center'] = true;
                    break;
                case 'baseline':
                    classObj['align-baseline'] = true;
                    break;
                case 'stretch':
                    classObj['align-stretch'] = true;
                    break;
            };

            return classObj;
        }
    }
}
</script>

./src/plugin/flexbox/flexbox.scss

scss 中定義須要使用到的樣式

.my-flexbox {
    width: 100%;
    display: flex;
}
.flex-vertical {
    flex-direction: column;
}
.flex-wrap {
    flex-wrap: wrap;
}
.flex-nowrap {
    flex-wrap: nowrap;
}

/* justify */
.justify-start {
    justify-content: flex-start
}
.justify-end {
    justify-content: flex-end
}
.justify-center {
    justify-content: center
}
.justify-space-between {
    justify-content: space-between
}
.justify-space-around {
    justify-content: space-around
}

/* align */
.align-start {
    align-items: flex-start
}
.align-end {
    align-items: flex-end
}
.align-center {
    align-items: center
}
.align-baseline {
    align-items: baseline
}
.align-stretch {
    align-items: stretch
}

./src/App.vue

好了!咱們能夠在項目中用到這個組件了!

<template>
    <div id="app">
        <my-flexbox>
            <p>demo</p>
            <p>demo</p>
        </my-flexbox>
    </div>
</template>

你也可讓他們垂直排列!

<template>
    <div id="app">
        <my-flexbox orient="vertical">
            <p>demo</p>
            <p>demo</p>
        </my-flexbox>
    </div>
</template>

<三> FlexboxItem 組件的實現

flexbox-item 組件和 flexbox 組件實現原理大同小異,直接貼代碼了!

./src/plugin/flexbox/flexbox.vue

<template>
    <div class="my-flexbox-item"
         :style="styleObj">
        <slot></slot>
    </div>
</template>

<script>
export default {
    name: 'my-flexbox-item',
    props: {
        grow: {
            type: [String, Number],
            default: 0
        },
        shrink: {
            type: [String, Number],
            default: 1
        },
        basis: {
            type: [String, Number],
            default: 'auto'
        },
        order: {
            type: [String, Number],
            default: 0
        }
    },
    computed: {
        styleObj () {
            let styleObj = {};

            // gutter
            let gutter = this.$parent.gutter,
                orient = this.$parent.orient;
            
            let marginName = orient === 'horizontal'?'marginLeft':'marginTop';
            styleObj[marginName] = gutter + 'px';

            // grow
            styleObj['flex-grow'] = this.grow;

            // shrink
            styleObj['flex-shrink'] = this.shrink;

            // basis
            styleObj['flex-basis'] = this.basis;

            // order
            styleObj['order'] = this.order;

            return styleObj;
        }
    }
}
</script>

./src/App.vue

<template>
    <div id="app">
        <my-flexbox>
            <my-flexbox-item grow="1">
                demo
            </my-flexbox-item>
            <my-flexbox-item>
                demo
            </my-flexbox-item>
        </my-flexbox>
    </div>
</template>

總結

這只是 vue 中編寫插件的其中一個方法,還有更多的,例如:

  1. 使用 Vue.directive(Name, [Define]),自定義指令,添加全局資源,如 vue-touch能夠看我總結的這篇文章

  2. 添加 Vue 實例方法,經過把它們添加到 Vue.prototype 上實現。

  3. 添加全局方法或者屬性,如: vue-element

  4. 一個庫,提供本身的 API,同時提供上面提到的一個或多個功能,如 vue-router

本文的案例,只講解了最簡單的如何配置插件,意在幫助你們儘快上手。

以爲有幫助,就打賞打賞吧。

img

相關文章
相關標籤/搜索