手把手教你封裝 Vue 組件邑贴,并使用 npm 發(fā)布

源碼地址席里,如果對(duì)你有幫助的話希望不要吝嗇你的 Star

本文主要記錄一下如何基于 Vue 開(kāi)發(fā)組件,并在 npm 上發(fā)布拢驾。廢話不多說(shuō)奖磁,進(jìn)入正題

Vue 開(kāi)發(fā)插件

開(kāi)發(fā)之前先看看官網(wǎng)的 開(kāi)發(fā)規(guī)范

我們開(kāi)發(fā)的之后期望的結(jié)果是支持 import、require 或者直接使用 script 標(biāo)簽的形式引入繁疤,就像這樣:

// 這里注意一下包的名字前綴是 custom 咖为,組件的名字前綴是 moor
// 這是因?yàn)槟莻€(gè)名字發(fā)布包的時(shí)候被占用了(我做實(shí)驗(yàn)的時(shí)候叫 moor-ui)現(xiàn)在改成了custom-ui秕狰,但是組件的前綴懶得改
import CustomUI from 'custom-ui';

// 或者 const CustomUI = require('custom-ui');

// 或者 <script src="..."></script>

Vue.use(CustomUI);

構(gòu)建一個(gè) Vue 項(xiàng)目

開(kāi)發(fā)組件我們使用 webpack-simple

vue init webpack-simple <project-name>

PS: 這里我選擇了 use sass 因?yàn)椋箝_(kāi)發(fā)組件會(huì)用到

開(kāi)發(fā)組件的文件結(jié)構(gòu)如下躁染,參考了一下 element 不過(guò)我們這個(gè)是簡(jiǎn)易版鸣哀,僅供分享和自己使用

.
├── src/                           // 源碼目錄
│   ├── packages/                  // 組件目錄
│   │   ├── switch/                // 組件(以switch為例)
│   │   ├── moor-switch.vue        // 組件代碼
│   │   ├── index.js               // 掛載插件
│   ├── App.vue                    // 頁(yè)面入口
│   ├── main.js                    // 程序入口
│   ├── index.js                   // (所有)插件入口
├── index.html                     // 入口html文件
.

好了,到這里準(zhǔn)備工作做好了吞彤,我們可以開(kāi)始開(kāi)發(fā)組件了我衬,接著上面的例子,下面開(kāi)始開(kāi)發(fā)一個(gè) switch 組件饰恕。

開(kāi)發(fā)單個(gè)組件

先看一下目標(biāo)效果:

switch.gif

開(kāi)始開(kāi)發(fā):在 packages 文件夾下新建一個(gè) switch 文件夾用來(lái)存放 switch 組件的源碼挠羔,繼續(xù)在 switch 文件夾中新建 moor-switch.vue 和 index.js 文件

moor-switch.vue

這個(gè)文件是組件源碼,我這里就不放源碼了埋嵌,這里就說(shuō)一下我個(gè)人認(rèn)為最重要的點(diǎn)吧破加,這也是封裝表單類(lèi)組件最為重要的點(diǎn):

自定義組件綁定 v-model,官網(wǎng)地址

使用:

<!-- 使用父組件的值綁定 -->
<!-- isSwitch = false -->
<moor-switch 
  v-model="isSwitch">開(kāi)關(guān):
</moor-switch>

<!-- 子組件必須要有 input 來(lái)處理對(duì)應(yīng)的值 -->
<!-- 其中最重要的就是需要 :value="value" 用來(lái)綁定值 -->
<!-- @change="$emit('input', $event.target.value)" 事件觸發(fā)改變值 -->
<input
    type="checkbox"
    @change="$emit('input', $event.target.value)"
    :true-value="activeValue"
    :false-value="inactiveValue"
    :disabled="disabled"
    :value="value">

<!-- 當(dāng)然還需要使用 props 來(lái)接受這個(gè) value -->
<script> 
// ... 此處省略代碼    
props: {
  value: {
    type: [Boolean, String, Number],
    default: false
  }
}
// ... 此處省略代碼    
</script>    

index.js

這個(gè)文件沒(méi)什么好說(shuō)的就是將該組件作為 Vue 插件雹嗦,代碼就三行這里就放在這吧:

// MoorSwitch 是對(duì)應(yīng)組件的名字范舀,要記得在 moor-switch.vue 文件中還是 name 屬性哦
import MoorSwitch from './moor-switch';

MoorSwitch.install = Vue => Vue.component(MoorSwitch.name, MoorSwitch);

export default MoorSwitch;

好了基本完成了,但是為了將所有的組件集中起來(lái)比如我還有 select了罪、 input尿背、 button 等組件,那么我想要統(tǒng)一將他們放在一個(gè)文件這中便于管理

所以在 App.vue 同級(jí)目錄我新建了一個(gè) index.js 文件捶惜,內(nèi)容也沒(méi)啥好說(shuō)的看看就懂了:

import HelloWorld from './packages/hello-world/index.js';
import MoorSwitch from './packages/switch/index.js';
// ...如果還有的話繼續(xù)添加

const components = [
  HelloWorld,
  MoorSwitch
  // ...如果還有的話繼續(xù)添加
]

const install = function(Vue, opts = {}) {
  components.map(component => {
    Vue.component(component.name, component);
  })
}

/* 支持使用標(biāo)簽的方式引入 */
if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue);
}

export default {
  install,
  HelloWorld,
  MoorSwitch
  // ...如果還有的話繼續(xù)添加
}

本地運(yùn)行通過(guò) <script/> 標(biāo)簽的方式使用,修改 index.html 文件:

<!-- 省略部分代碼 -->
<div id="app">
  <moor-hello-world :color="color" :msg="msg"></moor-hello-world>
  <moor-switch
  v-model="lightSwitch">開(kāi)關(guān):</moor-switch>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script src="/dist/custom-ui.js"></script>
<script>
new Vue({
  el: '#app',
  data() {
    return {
      color: 'red',
      msg: 'hello world!',
      lightSwitch: false
    }
  }
})
</script>

然后運(yùn)行 npm run dev 你就可以看到效果了:

preview.png

好了到這里我們的組件就開(kāi)發(fā)完成了荔烧;下面開(kāi)始說(shuō)怎么打包發(fā)布到 npm 上

發(fā)布到 npm

打包之前吱七,首先我們需要改一下 webpack.config.js 這個(gè)文件;

// ... 此處省略代碼 
// 執(zhí)行環(huán)境
const NODE_ENV = process.env.NODE_ENV

module.exports = {
  // 根據(jù)不同的執(zhí)行環(huán)境配置不同的入口
  entry: NODE_ENV == 'development' ? './src/main.js' : './src/index.js',
  output: {
    // 修改打包出口,在最外級(jí)目錄打包出一個(gè) index.js 文件鹤竭,我們 import 默認(rèn)會(huì)指向這個(gè)文件
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'custom-ui.js',
    library: 'custom-ui', // 指定的就是你使用require時(shí)的模塊名
    libraryTarget: 'umd', // libraryTarget會(huì)生成不同umd的代碼,可以只是commonjs標(biāo)準(zhǔn)的踊餐,也可以是指amd標(biāo)準(zhǔn)的,也可以只是通過(guò)script標(biāo)簽引入的
    umdNamedDefine: true // 會(huì)對(duì) UMD 的構(gòu)建過(guò)程中的 AMD 模塊進(jìn)行命名臀稚。否則就使用匿名的 define
  },
  // ... 此處省略代碼 
}

修改 package.json 文件:

// 發(fā)布開(kāi)源因此需要將這個(gè)字段改為 false
"private": false,

// 這個(gè)指 import custom-ui 的時(shí)候它會(huì)去檢索的路徑
"main": "dist/custom-ui.js",

發(fā)布命令其實(shí)就是兩句話

// 這里需要你有一個(gè) npm 的賬號(hào)吝岭,文章開(kāi)頭有官網(wǎng)鏈接
npm login   // 登陸 
npm publish // 發(fā)布

完成之后我們就可以在項(xiàng)目中安裝使用了

npm install custom-ui -S 

main.js 中引入插件

import CustomUI from 'custom-ui'
Vue.use(CustomUI)

在組件中使用:

<!-- 直接使用腳手架的HelloWorld組件 -->
<!-- 此處有省略代碼,看對(duì)地方加入代碼哦 -->
<div class="moor-item">
  <label>Input: </label>
  <moor-input
  v-model="input1"
  placeholder="請(qǐng)輸入信息">
  </moor-input>

  <moor-input
    v-model="input2"
    placeholder="請(qǐng)輸入信息">
  </moor-input>

  <moor-input
    placeholder="輸入框禁用"
    :disabled="inputDisabled">
  </moor-input>
</div>

<div class="moor-item">
  <label>Switch: </label>

  <moor-switch
  v-model="lightSwitch">開(kāi)關(guān)(開(kāi)):</moor-switch>

  <moor-switch
  v-model="switchLight">開(kāi)關(guān)(關(guān)):</moor-switch>
</div>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      // HelloWorld
      msg: 'Welcome to moor UI!',
      color: 'red',
      // input
      input1: '',
      input2: '這是默認(rèn)值',
      inputDisabled: true,
      // switch
      lightSwitch: false,
      switchLight: true
    }
  },
  watch: {
    lightSwitch: newValue => console.log('開(kāi)關(guān):', newValue),
  }
}
</script>

<style scoped>
.moor-select, .moor-btn, .moor-switch, .moor-input {
  margin: 10px 6px;
}
.moor-item {
  display: flex;
  align-items: center;
}
.moor-item label {
  width: 100px;
  display: inline-block;
}
</style>

預(yù)覽效果如下:

test-preview.png

PS: 修改 .gitignore 去掉忽略dist,因?yàn)槲覀兇虬奈募残枰峤话伤拢幻看紊系絥pm上需要更改版本號(hào)窜管,package.json 里的 version 字段

寫(xiě)的比較簡(jiǎn)單,主要還是提供思路稚机。用習(xí)慣了開(kāi)源的組件自己總得了解一下嘛幕帆,有的時(shí)候在開(kāi)發(fā)的過(guò)程中我們找不到合適的開(kāi)源組件就需要自己開(kāi)發(fā)了,這個(gè)時(shí)候我們把自己寫(xiě)的一些精致的小插件開(kāi)源出來(lái)挺好的...

最后希望你給個(gè) Star 源碼地址

哦赖条,對(duì)了README失乾,不想寫(xiě)了...哈哈

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末常熙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子碱茁,更是在濱河造成了極大的恐慌裸卫,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纽竣,死亡現(xiàn)場(chǎng)離奇詭異墓贿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)退个,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)募壕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人语盈,你說(shuō)我怎么就攤上這事舱馅。” “怎么了刀荒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵代嗤,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我缠借,道長(zhǎng)干毅,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任泼返,我火速辦了婚禮硝逢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绅喉。我一直安慰自己渠鸽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布柴罐。 她就那樣靜靜地躺著徽缚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪革屠。 梳的紋絲不亂的頭發(fā)上凿试,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音似芝,去河邊找鬼那婉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛党瓮,可吹牛的內(nèi)容都是我干的吧恃。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼麻诀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼痕寓!你這毒婦竟也來(lái)了傲醉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤呻率,失蹤者是張志新(化名)和其女友劉穎硬毕,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體礼仗,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吐咳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了元践。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片韭脊。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖单旁,靈堂內(nèi)的尸體忽然破棺而出沪羔,到底是詐尸還是另有隱情,我是刑警寧澤象浑,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布蔫饰,位于F島的核電站,受9級(jí)特大地震影響愉豺,放射性物質(zhì)發(fā)生泄漏篓吁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一蚪拦、第九天 我趴在偏房一處隱蔽的房頂上張望杖剪。 院中可真熱鬧,春花似錦驰贷、人聲如沸摘盆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至狼渊,卻和暖如春箱熬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背狈邑。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工城须, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人米苹。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓糕伐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蘸嘶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子良瞧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容