国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

關于Vue組件庫開發詳析

2019-11-19 13:35:07
字體:
來源:轉載
供稿:網友

前言

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

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

腳手架選擇

盡管我們團隊的這些Vue技術棧項目的腳手架大都使用的是webpack,在為組件庫選擇腳手架的時候我們還是在webpack與Rollup中猶豫了一下。

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

打包

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

“var”(默認值)輸出為一個變量

var MyLibrary = _entry_return_ ;

“this” 輸出為this的一個屬性

this["MyLibrary"] = _entry_return_ ;

“window” 輸出為window對象的一個屬性

window["MyLibrary"] = _entry_return_ ;

“global” 輸出為global對象的一個屬性

global["MyLibrary"] = _entry_return_ ;

“commonjs” 輸出為exports 的一個屬性

exports["MyLibrary"] = _entry_return_ ;

“commonjs2” 以module.exports形式輸出

module.exports = _entry_return_ ;

“amd” 輸出為AMD模塊

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

很顯然,我們需要把output.libraryTarget的值設為“umd”,以使我們的庫可以工作在各種場景下。

另一個與庫打包有關的設置項是output.umdNamedDefine,在output.libraryTarget 設為umd,且output.library 也設置了的情況下,把此選項值設為true,將會為AMD模塊命名。

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

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

externals: { vue: 'vue'}

這樣Vue就不會被打包。不過,有個問題,就是用script標簽的形式引用Vue的時候,掛在window上的變量名是“Vue”,而不是我們需要的”vue”,因此使用時會報vue未定義的錯誤。

還好,webpack的externals配置項支持傳入一個對象,可以為不同導出形式指定不同名稱。所以下面這種寫法可以解決這個問題。

組件類型

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

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

參考了Element UI等優秀組件庫的做法,我們把Modal類型的組件掛到了Vue.prototype上,使之成為Vue的實例方法,一次安裝、全局調用。

this.$dialog(options);

因此,我們的組件庫組件類型還包括“實例方法”。

組件CSS作用域

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

編譯后:

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

經過權衡,我們在組件里移除了scoped屬性,改用class策略來避免組件內樣式影響外部。當然,scoped屬性也不是沒有存在的意義,它更適合在具體應用中使用,對于復用性高的組件來說,不是最佳選擇。

按需使用與自定義構建

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

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

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

片刻之后,只包含用戶所選組件的構建包會出現在dist目錄下,文件體積比完整版本小很多。

這種方式下,所選組件會經歷組件庫腳手架完整的構建流程,自動處理組件依賴關系,對ES6/SCSS/Vue等語法也進行了編譯,構建出的文件也支持AMD/CMD/script標簽直接引用等場景,能比較好的滿足按需使用的需求。

圖標

組件庫UI組件難免會包含一些小圖標,需要尋找一種合適的方式處理這些圖標。

在應用開發中有時會把一些圖片轉成Base64編碼放在代碼里,這會使數據量增大30%左右,所以這種方式不適合較大圖片。而對于小圖標來說,增加的絕對數據量并不大,卻能減少一個http請求,也不失為一種優化方案。不過,組件庫較普通應用對數據量更為敏感,這種方式不是上策。

另一種處理小圖標的經典方案是雪碧圖(CSS Sprite),但這種基于精準位置信息的圖標引用方式在移動端基于rem的布局中并不是那么受歡迎,因為rem布局自身就難以精確,如果用于組件庫也會給按需引用帶來一些不便。

對于小圖標,在移動端更需要的是矢量方案,天然適配各種像素密度的屏幕。

在組件庫中,比較流行的是采用基于CSS3字體(@font-face)的ICON FONT方案,也就是把圖標放在一個自定義字體文件中。有很多優點,比如:

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


我們并沒有選擇ICON FONT方案,我們認為SVG方案更適合移動端組件庫:

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


SVG Sprite也不是必須手動去組合,借助webpack的 svg-sprite-loader 可以輕松實現SVG Sprite的動態生成,圖標的按需加載不是夢。

擴展閱讀

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

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 岑溪市| 西华县| 郑州市| 建昌县| 会同县| 慈利县| 太仆寺旗| 江阴市| 保定市| 夏津县| 仲巴县| 黄骅市| 安达市| 乃东县| 甘谷县| 神木县| 安顺市| 新竹县| 三河市| 沾益县| 东明县| 共和县| 宁城县| 油尖旺区| 儋州市| 肃宁县| 大余县| 色达县| 闽侯县| 白玉县| 成都市| 汉沽区| 浮山县| 分宜县| 武宁县| 乳源| 新绛县| 平南县| 寿阳县| 呼玛县| 辽中县|