Badge組件主要用於數字或狀態的標記,對於消息類的提醒功能,使用這組件仍是很常見的。具體顯示效果以下圖:css
無論組件複雜仍是簡單,編碼實現這個組件的都不是源碼分析目的。
源碼分析,在於經過一步步的實現這個功能,在這個過程當中,看本身能學到什麼,發現哪些問題。
而後經過這些問題,去擴展知識點,最終完成 實踐 - 思考 - 擴展
這三步。html
demo-1連接vue
第一步的實現很簡單,具體的能夠看示例代碼,主要點在於css的思路。api
仔細看,標記相對於父元素,badge的顯示區域定位時只有左上角的一小部分和父元素重疊。經過下面的css能夠實現這個功能。源碼分析
<div class="al-badge"> <slot></slot> <span class="al-badge--content">{{value}}</span> </div>
.al-badge { display: inline-block; position: relative; } .al-badge--content { position: absolute; right: 10px; top: 0; transform: translateX(100%) translateY(-50%); }
開始的時候,我還想着怎麼經過right + margin屬性實現。可是看源碼發現這種實現方式,感受也是很簡潔。那麼問題就來了,對於css的百分比單位,哪些屬性能夠設置呢?設置後他們的百分比又是相對於哪一個元素?post
發現一篇寫的很好的總結,能夠看一下:詳述css中的百分比值
總結一下:this
widht & heiht
屬性,百分比值相對於包含塊的寬高
margin & padding
屬性,百分比值相對於包含塊的寬度
font-size
屬性,百分比值相對於直接父元素的font-size
line-height
屬性,百分比值相對於自身元素的font-size
vertical-align
屬性,百分比值相對於自身元素的line-height
top/left/right/bottom
屬性,百分比值相對於包含塊寬高
translate
中,百分比值相對於自身元素border-box盒模型的寬高
demo-2連接編碼
一開始,對於這個需求,個人實現思路是這樣的:spa
<div class="al-badge"> <slot></slot> <span class="al-badge--content" v-if="value <= max">{{value}}</span> <span class="al-badge--content" v-if="value > max">{{max+}}</span> </div>
這算是本身在初期常常容易犯的一個問題吧。濫用v-if v-else。
一個好的組件,實現起來,模板一眼看過去,就應該是很簡潔的。過多的v-if只會越讀越糟心,後期維護以及增長新的需求時,也容易各類踩坑。.net
ok,咱們來從新梳理一下上面這段html,兩個v-if的模板,只是針對於不一樣條件下,內容顯示不一樣而已。因此,可不能夠增長一個computed屬性,在js這一層進行簡化?看下面這一段簡化後的:
let ElBadge = { name: 'ElBadge', //..... computed: { content: function() { if(typeof this.value === 'number' && typeof this.max === 'number') { return this.value > this.max ? `${this.max}+` : this.value; } return this.value; } } };
對於這個功能,首先須要解決的是,怎麼判斷組件是單獨使用,仍是包裹了一個子元素?
看下Vue關於內容分發的文檔:https://cn.vuejs.org/v2/api/#...
好,這樣經過$slots.default
能夠解決這個問題了,那麼模板上怎麼體現這個區別呢?v-if新增單獨使用的狀況?和上一點相似,咱們須要保證html模板的簡潔,因此經過css類名來作區別,當單獨使用的時候,就不想對於左上角進行定位了。
<div class="al-badge"> <slot></slot> <span v-show="!hidden" class="al-badge--content" :class="[ isDot && 'is-dot', $slots.default && 'is-fixed' ]"> {{content}} </span> </div>
.al-badge--content { //..... &.is-fixed { position: absolute; right: 10px; top: 0; transform: translateX(100%) translateY(-50%); } &.is-dot { right: 5px; width: 8px; height: 8px; padding: 0; } }
經過Badge組件
參考文獻: