iview 在今年 7 月 28 號發佈了 3.0.0 版本,大版本升級每每意味着功能、接口的大變動。
雖然官網已經有長長的 更新日誌,但看起來仍是有些抽象了,
因此我決定作個新舊版本的比較,盤點新版本到底爲咱們帶來了什麼新特性。這一篇給你們講解的,是一個很經常使用的組件 ——
Button
javascript
新版 Button
有以下新特性:html
to
屬性啓動ghost
屬性,樣式上可與其餘的 type
值複合Button
的升級相對仍是比較平滑的,須要注意兩點:vue
type="ghost"
,但可使用獨立的 ghost
屬性,因此升級前,建議全局搜索 type="ghost"
的調用default
樣式有些不一樣舊版本的 Button
組件只單純包裹了一個 button
標籤。
新版本 Button
新增了一個關鍵屬性:to
—— 通常狀況下,組件會渲染爲 button
標籤;
假如 to
有值,則組件會渲染爲 a
標籤。java
雖然破壞了 Button
的語義,但這個特性還挺方便的,在過去,爲了給 a
標籤應用 Button
樣式,每每須要本身寫上 class:ios
<!-- 普通 a 標籤 --> <a class="ivu-btn ivu-btn-primary" href="/foo/bar">這是一個 a 連接</a> <!-- router-link --> <router-link class="ivu-btn ivu-btn-primary" to="/foo/bar">這是一個 router-link</router-link>
雖然能夠複用按鈕樣式,但卻喪失了 Button
的行爲,好比 loading、icon 等。新版本支持連接模式後就沒有這個問題了,一樣的邏輯,能夠寫成:git
<Button type="primary" to="/foo/bar">這是一個連接</Button> <!-- 最終渲染爲 --> <a class="ivu-btn ivu-btn-primary" href="/foo/bar">這是一個連接</a>
to
屬性值支持 string
、object
兩種類型,iview 會優先使用 vue-router
的相關函數處理連接跳轉;當應用環境中沒有 vue-router
時,則會退化成普通的 window.location.href = this.to;
調用。
除了 to
, Button
還新增了 replace
、target
兩個屬性,用於補充連接的定義。replace
屬性語義與 router-link
的 replace 屬性的語義相同;target
屬性則與 a
標籤的 target 屬性相同。github
總的來講,在連接模式下,你能夠把 Button
理解爲一個閹割版的 router-link
組件。vue-router
ghost
屬性幽靈按鈕是一個曾經被普遍討論的話題,如今已是一種很常規的設計了。這種設計指定按鈕的背景色必須是透明的,而並無定義字體、邊框樣式,但舊版本 Button
只支持一種灰色調調的 ghost:api
新版本在這方面作了很大改進,將 ghost
樣式獨立爲一類 class,配合其餘 type
類型做爲按鈕字體、邊框顏色的補充,相得益彰,能夠看看 iview 官網提供的 示例:antd
多種色值形態的幽靈按鈕確實能夠大大提升提高實用性。曾經 1.x 版本 的 antd 也把 ghost 做爲一種 type 看待,到了2.x 版本 也抽出來作爲一個獨立特性,iview 這個改進,看來也算是有依有據,亦步亦趨了。
不過,尷尬的是,iview 順手把 default
的樣式也給改了,對於設計有較高要求的團隊得注意了:
好了,特性與變動都聊完了,最後咱們來看看代碼。 新版 Button
的代碼只有 116 行卻有很多值得玩味的地方:
新版 Button
的模板是這樣的:
<template> <a v-if="to" ...> <Icon class="ivu-load-loop" type="ios-loading" v-if="loading"></Icon> <Icon :type="icon" :custom="customIcon" v-if="(icon || customIcon) && !loading"></Icon> <span v-if="showSlot" ref="slot"><slot></slot></span> </a> <button v-else ...> <Icon class="ivu-load-loop" type="ios-loading" v-if="loading"></Icon> <Icon :type="icon" :custom="customIcon" v-if="(icon || customIcon) && !loading"></Icon> <span v-if="showSlot" ref="slot"><slot></slot></span> </button> </template>
oh,a
與 button
包裹的內容塊完徹底全重複了, 徹底如出一轍誒。其實這一塊代碼能夠抽成一個獨立的組件,下降重複的。
另外, size
的定義,也挺尷尬的:
... export default { ... props: { ... size: { validator (value) { return oneOf(value, ['small', 'large', 'default']); }, default () { return this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size; } } ... }, ... };
從單個組件看,是沒啥毛病,但居然能夠在代碼裏找到 16 處徹底相同的代碼,分別爲:AutoComplete
、Avatar
、ButtonGroup
、Cascader
、CheckboxGroup
、Checkbox
、ColorPicker
、Picker
、InputNumber
、Input
、RadioGroup
、Radio
、Select
、Spin
、Switch
、Table
...這一塊是能夠抽成一個 mixin,這錯誤犯得有點低級了。
舊版本 Button
只是簡單包裝了 button
標籤,因此它的事件處理 很是簡單。新版本兼容連接模式後,看起來就有些繞了:
<template> <!-- linkUrl 是從 mixinsLink 混入的屬性 --> <a :href="linkUrl" @click.exact="handleClickLink($event, false)" @click.ctrl="handleClickLink($event, true)" @click.meta="handleClickLink($event, true)">...</a> <button ... @click="handleClickLink">...</button> </template> <script> ... export default { mixins: [ mixinsLink ], ... methods: { handleClickLink (event, new_window = false) { this.$emit('click', event); // handleCheckClick 是從 mixinsLink 混入進來的屬性 this.handleCheckClick(event, new_window); } } ... }; </script>
handleClickLink
在 a
標籤下被綁定了 3 次,分別帶了 exact
、ctrl
、meta
修飾符,
用於模擬普通 a
標籤的點擊效果,可是爲何不用 $event
對象的 ctrlKey
、metaKey
屬性作判斷呢?我仔仔細細看了 mixinsLink
的代碼,惋惜仍是太過才疏學淺了,無法得出靠譜的結論,作了個簡單 demo 對比各類實現的效果,也沒看出個因此然。
另一個有問題的地方是 new_window
變量,其餘變量名都是駝峯的,忽然來個下劃線命名,有些突兀了。
最後提一點, type="ghost"
已通過期了,源碼的 validator
函數也作了相應修改,如今傳進 type="ghost"
會報錯:
這錯誤信息,有點「硬」了?這裏其實徹底能夠多花些心思,報個 deprecated
警告,對升級者而言會更容易分辨出該作些什麼修改。
附錄: