最近在研究 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.vue
git
<template> <div>flexbox demo</div> </template> <script> export default { // 這是該組件的自定義名稱, // 以後引用組件時就會用到這個名稱。 name: 'my-flexbox' } </script>
./src/plugin/flexbox/flexboxItem.vue
github
<template> <div>flexboxItem demo</div> </template> <script> export default { name: 'my-flexbox-item' } </script>
./src/plugin/flexbox/index.js
vue-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.js
bash
如今,咱們來到插件的出口文件。
// ----- 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 }
引入組件
定義 components
變量
這裏是重點,vue 爲編寫插件提供了一個 install(Vue, Option)
方法,該方法爲 vue 添加全局功能;
該方法有兩個參數,第一個是 Vue
構造器,第二個是可選的參數;
使用 vue 的全局方法 Vue.component(Name, Object)
定義組件,第一個參數是組件名,第二參數是組件對象;
最後將組件默認導出。
./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 中編寫插件的其中一個方法,還有更多的,例如:
使用 Vue.directive(Name, [Define])
,自定義指令,添加全局資源,如 vue-touch
。能夠看我總結的這篇文章
添加 Vue 實例方法,經過把它們添加到 Vue.prototype 上實現。
添加全局方法或者屬性,如: vue-element
。
一個庫,提供本身的 API,同時提供上面提到的一個或多個功能,如 vue-router
。
本文的案例,只講解了最簡單的如何配置插件,意在幫助你們儘快上手。
以爲有幫助,就打賞打賞吧。