cube-ui 是滴滴去年末開源的一款基於 Vue.js 2.0 的移動端組件庫,主要核心目標是作到體驗極致、靈活性強、易擴展以及提供良好的周邊生態—後編譯。css
自 17 年 11 月開源至今已有 5 個月,在這個過程當中 cube-ui 受到了很多的關注,同時從社區中也收到了不少很好的反饋和建議。咱們也一直在迭代更新,從最初的 1.0 版本到最近發佈的 1.7 的版本,除了對原有組件作一些加強優化,咱們也提供了不少新的組件。此外,周邊後編譯技術生態也作了不少優化,知足於更多場景需求,官網也作了一次升級。 接下來就重點介紹下 cube-ui 在這個過程當中的有哪些成果以及一些設計細節。前端
cube-ui 的組件數已經從最初的 14 個增加了 28 個,足足翻了一倍,已有的組件生態: vue
除了上述的組件外,cube-ui 還對外暴露了三個模塊: ● style ● create-api ● better-scrollwebpack
並且 cube-ui 也已經支持了以下特性: ● 自定義主題 ● rem 佈局 ● SSR 支持web
此外,cube-ui 的周邊生態也有了進一步豐富: ● vue-cli 腳手架模板 cube-template ● 快速上手教程 cube-application-guide ● 後編譯 webpack 插件 webpack-post-compile-plugin ● 按需引用 webpack 插件 webpack-transform-modules-plugin,依賴 babel 插件 babel-plugin-transform-modulesvue-cli
針對於上邊所介紹的關鍵成果,咱們來聊聊具體設計上的細節。json
● 滾動 & Picker 類組件 在移動端,因爲手機尺寸以及交互特性,咱們須要處理不少滾動類需求:下拉刷新、上拉更多、輪播等以及 Picker 選擇等場景。cube-ui 底層滾動類組件以及 Picker 類依賴於咱們團隊的移動端利器 better-scroll 實現,基於其出色的體驗進而保證了咱們上層封裝的滾動類、Picker 類組件的出色的交互體驗。 ● 彈出層類組件 在實際開發中咱們會遇到不少彈出層類組件,由於咱們設計了一個基礎彈出層組件 Popup,它主要解決移動端最爲常見的居中(Tip:文本換行位置也很重要哦)、置底以及是否有蒙層效果,藉助於它來實現絕大多數的彈出層組件。 另外一個常見的痛點就是因爲彈出類組件每每是全屏的狀態,若是咱們按照 Vue 推薦的聲明式的語法在子組件裏使用彈出層組件,因爲嵌套層級問題,很容易受到父級元素的樣式影響。爲此咱們單獨開發了 create-api 模塊,經過 API 的形式將實例化的彈出層組件動態掛載到 Body 元素下,所以擺脫了父級元素樣式的影響,同時會隨着使用它的組件的銷燬而自動銷燬,且爲了下降開銷成本,根據須要有些彈出層類組件都被設計成了單例模式。它是一個很通用的能力,咱們把這樣的一個便捷的 API 對外暴露出去,開發者也能夠根據實際場景將本身開發的組件經過 createAPI 進行註冊,進而也可解決上述痛點。 ● 表單類組件 表單類需求每每特應性比較大,交互也很難作到統一,可是仍然能夠有主流的表單設計交互,在 cube-ui 中表單能夠設置 layout 來決定樣式甚至是交互,知足平常場景需求。在表單設計中有兩個很重要的組件:Validator 和 Form。Validator 成爲獨立的組件主要基於校驗場景不肯定性,同時還須要知足各類形式的校驗,因此 Validator 就只作了兩件核心的事情,對數據源進行校驗以及對應的錯誤信息的展現。考慮到開發者開發表單的便利性,咱們參考 vue-form-generator 的設計,把表單設計成了根據 Schema 配置自動生成表單,這樣開發表單的成本就下降了不少;同時爲了兼顧靈活性,也支持經過插槽來自定義開發者須要的結構交互。 後編譯api
後編譯是 cube-ui 的一個重要的生態,藉助於後編譯,整個的 web 應用的開發均可以直接基於 ES2015+ 進行開發,而項目依賴的一些 NPM 包也是能夠直接使用 ES2015+ 進行開發,而且無需編譯可直接發佈到 NPM 平臺上(也能夠是本身 NPM 私服)。這樣,這些組件庫或者工具就能夠有更多的想象空間、能夠作更多有意思的事情。 cube-ui 支持的兩個特性自定義主題以及 rem 佈局都是基於咱們主推的後編譯技術實現。 接下來一塊兒來看下這兩個特性實現的細節。 自定義主題 通常而言,組件庫都是有默認主題的,而每每還會搭配有多套主題(PC 類組件庫比較常見)。如今藉助於 CSS 預處理器,咱們能夠給組件定義一些變量(通常都是顏色值),而後在組件對應的樣式中使用。 對於自定義主題這種需求,主流的作法有:樣式覆蓋和修改變量。babel
若是咱們想要把項目中使用的按鈕的背景色該換掉,那麼能夠修改 theme.styl 的文件內容: // 若是你須要使用 cube-ui 自帶的顏色值 須要 require 進來app
@require "~cube-ui/src/common/stylus/var/color.styl"
// button
$btn-bgc := #409eff
$btn-bdc := #409eff
$btn-active-bgc := #66b1ff
$btn-active-bdc := #66b1ff
複製代碼
配合咱們的 webpack 配置,刷新後的樣子爲:
這樣咱們就能夠輕鬆作本身想要的主題定製,所要作的就是修改 cube-ui 已經定義好的變量值便可。對於 cube-ui 組件庫自身,則不會有任何修改,且對於應用開發者而言,用不用自定義主題,自己的源代碼不用修改,只須要建立一個主題文件(無需手工引入)配合 webpack 插件配置便可。其實對於主題定製,還能夠更進一步,將來 cube-ui 會考慮藉助於 CSS 自身支持的變量(自定義屬性)達到主題定製的目的,例如能夠把處理器變量改成原生的變量,編譯的話能夠經過 post-css-variables 插件把默認變量值作替換,能夠實現和現有編譯後功能相同的效果,同時在後編譯的狀況下不失原生 CSS 變量的動態優點。這樣,不只能夠作到主題定製,也能夠作到多主題的自由切換,由於 CSS 原生變量能夠直接修改變量值而不須要經過事先寫死而後切換 class 覆蓋的方式作多主題切換。
在移動端仍是有不少設計師、產品或者開發者偏心用縮放來達到不一樣尺寸屏幕適配目的,而縮放的實現通常都是採用 rem 進行佈局,業內比較出名的方案就是手機淘寶前端團隊開源的 lib-flexible。 如今實際上是不推薦使用 rem 進行佈局的,若是真的要縮放的效果,能夠考慮 vw vh 等 CSS 單位來實現。 rem 佈局有兩個核心的點:
能夠看出總體的效果,當尺寸較小時,Button 和 Toast 都是比較小的,而當尺寸比較大時,相對應的都會更大,達到了縮放的目的。
這裏上層擴展主要是指基於組件庫進行二次封裝,例如在滴滴內部,咱們的不少業務組件庫就是在開源的 cube-ui 組件庫之上作加強而來的。 這個能力是很是重要的,由於移動端組件庫和 PC 組件庫最大的區別是移動端可能是 to C 的業務場景,不一樣的業務場景下的設計是不同的,因此 cube-ui 專一於通用組件和基礎能力的建設,並不會在佈局和業務組件方面大作文章;而 PC 組件庫通常都是用於 to B 的場景,如內部 MIS 類的系統,對於設計的要求並無特別苛刻,因此基礎的樣式,組件都是能夠統一的。所以 cube-ui 的定位並非要提供一個「大而全」的組件庫,而是提供了二次擴展的能力,目標是任何移動端的業務場景均可以基於 cube-ui 提供的能力作二次擴展。 以咱們的快速上手教程爲例,咱們要開發以下圖的彈窗組件。
咱們基於 cube-ui 提供的能力開發它就很是方便了。首先能夠基於 Popup 組件開發一個 subscribe-dialog.vue 組件:<template>
<div class="subscribe-dialog-view">
<cube-popup ref="popup" @mask-click="hide">
<div class="subscribe-dialog-wrapper">
<span class="close" @click="hide"><i class="cubeic-close"></i></span>
<div class="title">開啓推送通知</div>
<img src="./subscribe.png">
<p class="desc">第一時間獲取最新鮮出爐的新聞攻略、賽事諮詢、數據專題、精彩視頻</p>
<cube-button class="button" @click="start">如今開啓</cube-button>
</div>
</cube-popup>
</div>
</template>
<script>
export default {
name: 'subscribe-dialog',
methods: {
show () {
this.$refs.popup.show()
this.$emit('show')
},
hide () {
this.$refs.popup.hide()
this.$emit('hide')
},
// ...
}
}
</script>
複製代碼
接着使用 createAPI 模塊把它變成一個 API 式的組件:
import SubscribeDialog from './components/subscribe-dialog/subscribe-dialog'
createAPI(Vue, SubscribeDialog, [], true)
複製代碼
而後調用它就很是方便了:
this.subscribeDialog = this.$createSubscribeDialog()
this.subscribeDialog.show()
複製代碼
周邊生態 周邊生態有兩個核心:後編譯 + 按需引入。爲此,咱們開發了兩個 webpack 的插件來幫助咱們更好的去使用、開發。 ● 後編譯 webpack 插件 webpack-post-compile-plugin ● 按需引用 webpack 插件 webpack-transform-modules-plugin webpack-post-compile-plugin 這個插件主要是讀取應用 package.json 中的 compileDependencies 字段的值(用於指定應用須要後編譯哪些依賴包),並且還能解決嵌套後編譯包的問題,由於開發者只須要關注本身依賴須要後編譯的包,而不須要關注依賴的依賴包,這樣就能構成一條生態鏈。
爲何不是一個 NPM 包本身聲明需不須要後編譯,而是由使用者去聲明? 主要考慮整個 NPM 生態,例如 lodash-es 並不在咱們控制範圍以內,爲了更好的使用整個 NPM 生態圈的包,咱們決定由使用者去聲明須要後編譯的 NPM 包。 webpack-transform-modules-plugin 這個插件主要解決更方便、友好地使用按需引入的問題,爲了更好的統一應用使用後編譯和不使用的狀況,咱們在本來 babel-transform-imports 的基礎上作了升級優化產出了 babel-plugin-transform-modules 插件,可是和後編譯的場景相似,這個是不能解決後編譯場景下 NPM 包嵌套按需引入的問題的,爲此纔開發了 webpack-transform-modules-plugin 這個插件,和 compileDependencies 字段相似,咱們新增了 transformModules 字段來聲明按需引入的 NPM 包的的轉換規則,例如:
"transformModules": {
"cube-ui": {
"transform": "cube-ui/src/modules/${member}",
"kebabCase": true
}
}
複製代碼
固然在後編譯的場景下,咱們藉助於 webpack 4 Tree shaking 中新增的 side-effects 也能夠達到目的,這個是將來咱們去優化的方向。
腳手架 & 教程 任何的技術都是有成本的,咱們新增了 webpack 插件,也有一些須要配合的改動,因此爲了下降開發者成本,咱們提供了適用於 vue-cli 腳手架的模板 cube-template,固然對應的也會新增一些配置項,感興趣的能夠了解下cube-template wiki。 同時爲了初次使用 cube-ui 的開發者快速上手,咱們還有一個簡單的上手教程 cube-application-guide。
展望 cube-ui 目前還處於初步的階段,還缺乏不少組件,可是咱們一直在努力,但願在很快的將來能夠提供更多更好用的組件。不只如此,咱們但願的是除去組件庫自己,額外還會豐富周邊的整個生態建設,給開發者一個良好的生態環境,進一步提高開發體驗,提高應用性能等。固然,咱們也但願社區的小夥伴也能參與進來,一塊共同建設,共同進步。 將來 cube-ui 會朝着以下方面繼續前行: ● 豐富組件 ● 組件優化 ● 文檔優化 ● 示例優化 ● 周邊建設 但願感興趣的同窗能夠一塊兒共建或者加入咱們團隊,一塊兒玩技術!