關(guān)于Vue組件庫(kù)開發(fā)詳析

前言

創(chuàng)新互聯(lián)建站主要從事成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)城區(qū),10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):028-86922220

2017年是Vue.js大爆發(fā)的一年,React迎來了一個(gè)強(qiáng)有力的競(jìng)爭(zhēng)對(duì)手,王者地位受到挑戰(zhàn)(撰寫此文時(shí)github上Vue與React的star數(shù)量已逼近)。我們團(tuán)隊(duì)這一年有十多個(gè)大型項(xiàng)目采用了Vue技術(shù)棧,在開發(fā)效率、頁面性能、可維護(hù)性等方面都有不錯(cuò)的收效。 我們希望把這些項(xiàng)目中可復(fù)用的功能組件提取出來,給后續(xù)項(xiàng)目使用,以減少重復(fù)開發(fā),提高效率,同時(shí)也為了致敬前端界“出一個(gè)框架,造一遍輪子”的行規(guī), 一個(gè)基于Vue 2的移動(dòng)端UI組件庫(kù)被提上日程。

組件庫(kù)的開發(fā)過程總的來說還是比較順利的,這里與大家分享一些問題與思考。

腳手架選擇

盡管我們團(tuán)隊(duì)的這些Vue技術(shù)棧項(xiàng)目的腳手架大都使用的是webpack,在為組件庫(kù)選擇腳手架的時(shí)候我們還是在webpack與Rollup中猶豫了一下。

Rollup看起來更適合組件庫(kù)的開發(fā),它把所有模塊構(gòu)建在一個(gè)函數(shù)內(nèi),執(zhí)行效率更高,它支持Tree Shaking,只打包需要的代碼,輸出文件更?。╳ebpack后來也支持了)。但綜合考慮之后,我們還是選擇了webpack作為打包工具。首先,按照規(guī)劃,demo演示和文檔頁面也在這個(gè)腳手架中,所以對(duì)代碼分割、熱加載等功能是有需求的,而這方面能力Rollup遠(yuǎn)不及webpack。另外,這個(gè)組件庫(kù)由多人開發(fā)維護(hù),基于現(xiàn)有webpack腳手架開發(fā)成本更低、效率更高。選擇webpack,讓我們可以更專注于造輪子。

打包

即便選擇了webpack作為打包工具,我們也并不希望這個(gè)庫(kù)的使用場(chǎng)景局限在webpack項(xiàng)目中,通過AMD/CMD方式、甚至通過script標(biāo)簽直接引用等場(chǎng)景都應(yīng)該得到支持。為了達(dá)到這個(gè)目的,我們需要在webpack配置文件中設(shè)置輸出格式,需要配置的選項(xiàng)是output.libraryTarget,有以下可選值:

“var”(默認(rèn)值)輸出為一個(gè)變量

var MyLibrary = _entry_return_ ;

“this” 輸出為this的一個(gè)屬性

this["MyLibrary"] = _entry_return_ ;

“window” 輸出為window對(duì)象的一個(gè)屬性

window["MyLibrary"] = _entry_return_ ;

“global” 輸出為global對(duì)象的一個(gè)屬性

global["MyLibrary"] = _entry_return_ ;

“commonjs” 輸出為exports 的一個(gè)屬性

exports["MyLibrary"] = _entry_return_ ;

“commonjs2” 以module.exports形式輸出

module.exports = _entry_return_ ;

“amd” 輸出為AMD模塊

“umd” 暴露給所有模塊定義,允許它和CommonJS/AMD/全局變量一起工作

很顯然,我們需要把output.libraryTarget的值設(shè)為“umd”,以使我們的庫(kù)可以工作在各種場(chǎng)景下。

另一個(gè)與庫(kù)打包有關(guān)的設(shè)置項(xiàng)是output.umdNamedDefine,在output.libraryTarget 設(shè)為umd,且output.library 也設(shè)置了的情況下,把此選項(xiàng)值設(shè)為true,將會(huì)為AMD模塊命名。

webpackConfig.output = {
 path: path.resolve(__dirname, 'dist'),
 publicPath:"/",
 filename: '[name].js',
 library: 'xxx', //模塊名稱
 libraryTarget: 'umd', //輸出格式
 umdNamedDefine: true //是否把模塊名作為AMD輸出的命名空間
};

Vue組件庫(kù)只提供組件,Vue文件自身需要組件庫(kù)使用者在項(xiàng)目中自行引入,庫(kù)中無需打包。所以我們可以把Vue加到externals中。

externals: {
 vue: 'vue'
}

這樣Vue就不會(huì)被打包。不過,有個(gè)問題,就是用script標(biāo)簽的形式引用Vue的時(shí)候,掛在window上的變量名是“Vue”,而不是我們需要的”vue”,因此使用時(shí)會(huì)報(bào)vue未定義的錯(cuò)誤。

關(guān)于Vue組件庫(kù)開發(fā)詳析

還好,webpack的externals配置項(xiàng)支持傳入一個(gè)對(duì)象,可以為不同導(dǎo)出形式指定不同名稱。所以下面這種寫法可以解決這個(gè)問題。

關(guān)于Vue組件庫(kù)開發(fā)詳析

組件類型

規(guī)劃中的Vue組件庫(kù)包含組件(Component)、指令(Directive)和過濾器(Filter)三種類型的存在。

比較特殊的是模態(tài)彈窗類(Modal)組件,如Dialog、Toast等等。頁面中可能存在很多個(gè)Modal,而很多場(chǎng)景下用戶的行為只會(huì)觸發(fā)其中一部分,如果把所有可能彈出的Modal(特別是異步的、結(jié)構(gòu)內(nèi)容復(fù)雜的Modal)全部寫在頁面上,是否妥當(dāng)?對(duì)于多頁面應(yīng)用,每個(gè)頁面都寫一遍或者再封裝一層組件是否繁瑣而冗余?這個(gè)問題在知乎上引發(fā)過討論,尤大(Vue.js作者尤雨溪)本人在參與討論時(shí)給出建議,組件多層嵌套時(shí),應(yīng)該把Modal放在根組件里,然后在子組件里通過事件觸發(fā)。在具體應(yīng)用里,應(yīng)該這么用,這符合Vue提倡的“狀態(tài)驅(qū)動(dòng)”。不過在組件庫(kù)里,我們還是希望提供一種更便捷更通用的方式來使用Modal類型的組件。

參考了Element UI等優(yōu)秀組件庫(kù)的做法,我們把Modal類型的組件掛到了Vue.prototype上,使之成為Vue的實(shí)例方法,一次安裝、全局調(diào)用。

this.$dialog(options);

因此,我們的組件庫(kù)組件類型還包括“實(shí)例方法”。

組件CSS作用域

對(duì)于一個(gè)組件,我們希望它的CSS只作用于當(dāng)前組件內(nèi)的元素,所以我們給每個(gè)組件的Vue單頁面文件的style標(biāo)簽加上了scoped屬性。編譯后,HTML標(biāo)簽會(huì)被自動(dòng)添加一個(gè)隨機(jī)生成的唯一屬性 (比如 data-v-f3f3eg9) ,同時(shí)對(duì)應(yīng)的CSS選擇器也會(huì)增加同名的屬性選擇器(如.example[data-v-f3f3eg9]),這樣組件內(nèi)的 CSS 便指定了作用域。

關(guān)于Vue組件庫(kù)開發(fā)詳析

編譯后:

關(guān)于Vue組件庫(kù)開發(fā)詳析

通過scoped屬性的確能達(dá)到給組件樣式設(shè)置作用域的目的,基本能避免組件內(nèi)的樣式影響外部,但是它也帶來了另外一個(gè)問題,就是給外部覆蓋內(nèi)部樣式帶來了不便。無論組件功能多么通用,接口多么靈活,只要涉及到UI,就難免無法滿足所有項(xiàng)目樣式需求,所以應(yīng)該允許在具體的項(xiàng)目中根據(jù)需要覆蓋組件部分甚至全部樣式。而scoped隨機(jī)生成屬性名提高了覆蓋樣式的難度。

經(jīng)過權(quán)衡,我們?cè)诮M件里移除了scoped屬性,改用class策略來避免組件內(nèi)樣式影響外部。當(dāng)然,scoped屬性也不是沒有存在的意義,它更適合在具體應(yīng)用中使用,對(duì)于復(fù)用性高的組件來說,不是最佳選擇。

按需使用與自定義構(gòu)建

隨著項(xiàng)目推進(jìn),組件庫(kù)里的組件越來越多,目前已超過40個(gè),構(gòu)建之后的文件也越來越大。如果某個(gè)應(yīng)用只用到了庫(kù)里的少數(shù)幾個(gè)組件,完全沒有必要使用完整的構(gòu)建包,所以我們需要提供一種按需使用的方式。早期,我們是讓用戶通過私有npm安裝組件庫(kù)之后,根據(jù)應(yīng)用自身需要直接引用src目錄下組件源碼的方式來實(shí)現(xiàn)按需加載。這種方式有較大局限性,因?yàn)橐玫脑创a沒有經(jīng)過編譯,需要用戶自己去處理組件的依賴關(guān)系,ES6/SCSS/Vue模板等編譯工作也需要用戶在自己的項(xiàng)目里完成,繁瑣、易出錯(cuò),也難以支持webpack外的其他場(chǎng)景。 我們?cè)O(shè)想提供一種自定義構(gòu)建的方式,來實(shí)現(xiàn)按需打包。首先讓用戶選擇需要哪些組件,然后基于這些信息生成一個(gè)個(gè)性化的配置文件,再基于這個(gè)文件進(jìn)行構(gòu)建,最終只打包編譯用戶指定的這些組件。

那么,通過哪種方式與用戶交互,收集用戶指令呢?比較友好的方式是通過web,比如在項(xiàng)目主頁中提供一個(gè)頁面,讓用戶在線選擇組件,然后下載構(gòu)建之后的文件。而根據(jù)我們組件庫(kù)目前的定位,推薦的使用方式是通過私有npm安裝,所以我們首先推出的是通過命令行界面(CLI)方式來完成自定義構(gòu)建。

用戶只需要在終端執(zhí)行命令“npm run custom”,即可得到全部組件的列表,通過鍵盤選擇需要的組件,然后按下回車,腳手架便開始自動(dòng)完成剩余的個(gè)性化構(gòu)建工作。

關(guān)于Vue組件庫(kù)開發(fā)詳析

片刻之后,只包含用戶所選組件的構(gòu)建包會(huì)出現(xiàn)在dist目錄下,文件體積比完整版本小很多。

關(guān)于Vue組件庫(kù)開發(fā)詳析

這種方式下,所選組件會(huì)經(jīng)歷組件庫(kù)腳手架完整的構(gòu)建流程,自動(dòng)處理組件依賴關(guān)系,對(duì)ES6/SCSS/Vue等語法也進(jìn)行了編譯,構(gòu)建出的文件也支持AMD/CMD/script標(biāo)簽直接引用等場(chǎng)景,能比較好的滿足按需使用的需求。

圖標(biāo)

組件庫(kù)UI組件難免會(huì)包含一些小圖標(biāo),需要尋找一種合適的方式處理這些圖標(biāo)。

在應(yīng)用開發(fā)中有時(shí)會(huì)把一些圖片轉(zhuǎn)成Base64編碼放在代碼里,這會(huì)使數(shù)據(jù)量增大30%左右,所以這種方式不適合較大圖片。而對(duì)于小圖標(biāo)來說,增加的絕對(duì)數(shù)據(jù)量并不大,卻能減少一個(gè)http請(qǐng)求,也不失為一種優(yōu)化方案。不過,組件庫(kù)較普通應(yīng)用對(duì)數(shù)據(jù)量更為敏感,這種方式不是上策。

另一種處理小圖標(biāo)的經(jīng)典方案是雪碧圖(CSS Sprite),但這種基于精準(zhǔn)位置信息的圖標(biāo)引用方式在移動(dòng)端基于rem的布局中并不是那么受歡迎,因?yàn)閞em布局自身就難以精確,如果用于組件庫(kù)也會(huì)給按需引用帶來一些不便。

對(duì)于小圖標(biāo),在移動(dòng)端更需要的是矢量方案,天然適配各種像素密度的屏幕。

在組件庫(kù)中,比較流行的是采用基于CSS3字體(@font-face)的ICON FONT方案,也就是把圖標(biāo)放在一個(gè)自定義字體文件中。有很多優(yōu)點(diǎn),比如:

  • ICON在字體中是矢量存在,受移動(dòng)端歡迎
  • 良好的瀏覽器兼容性,web字體并非CSS3發(fā)明,更早之前的瀏覽器(包括IE6)也都事實(shí)上支持,雖有些許差異,終歸是有辦法兼容的
  • 可通過CSS控制ICON顏色和透明度等樣式,甚至可以實(shí)現(xiàn)顏色漸變效果

關(guān)于Vue組件庫(kù)開發(fā)詳析

我們并沒有選擇ICON FONT方案,我們認(rèn)為SVG方案更適合移動(dòng)端組件庫(kù):

  • SVG雖在PC端個(gè)別古董瀏覽器中兼容較差,但在移動(dòng)端兼容良好
  • ICON FONT被認(rèn)為是文本,所以一些瀏覽器會(huì)對(duì)其進(jìn)行抗鋸齒處理,這可能導(dǎo)致圖標(biāo)不那么銳利,清晰度打折扣
  • SVG樣式控制比ICON FONT更靈活,甚至可以控制圖標(biāo)各個(gè)部分的顏色,實(shí)現(xiàn)彩色圖標(biāo)。而這對(duì)ICON FONT來說是不可能實(shí)現(xiàn)的
  • ICON FONT通常是用偽對(duì)象或偽類插入頁面,其展示受到“l(fā)ine-height”、“vertical-align”、“l(fā)etter-spacing”、“word-spacing”及字體相關(guān)CSS屬性影響,也受到字體字符設(shè)計(jì)本身影響。而SVG在頁面中就是一個(gè)標(biāo)簽,更方便控制,語義化也更好
  • 結(jié)合symbol元素可以實(shí)現(xiàn)所謂“SVG Sprite”,也就是把很多SVG圖標(biāo)整合在一起,通過ID引用指定圖標(biāo),可以復(fù)用。這種方式比CSS Sprite還要方便,因?yàn)椴恍枰P(guān)心圖標(biāo)具體位置信息

關(guān)于Vue組件庫(kù)開發(fā)詳析

SVG Sprite也不是必須手動(dòng)去組合,借助webpack的 svg-sprite-loader 可以輕松實(shí)現(xiàn)SVG Sprite的動(dòng)態(tài)生成,圖標(biāo)的按需加載不是夢(mèng)。

擴(kuò)展閱讀

  • NutUI組件庫(kù) - https://nutui.jd.com
  • webpack output.libraryTarget - https://webpack.js.org/configuration/output/#output-librarytarget
  • umd - https://github.com/umdjs/umd

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)創(chuàng)新互聯(lián)的支持。

文章標(biāo)題:關(guān)于Vue組件庫(kù)開發(fā)詳析
路徑分享:http://bm7419.com/article8/gihcip.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、網(wǎng)站設(shè)計(jì)做網(wǎng)站、ChatGPT、云服務(wù)器、定制開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)