概述:Dropdown 下拉菜單與 Select 的區別在於它是包含了一部分操做,因此它的 Option 下拉項要對其進行支持。javascript
publish:2019-03-31css
自從我寫了關於中後臺系統組件的第一篇文章以來,已經三個月了。因爲業務場景的較爲簡單,因此它沒有其餘組件庫的功能那麼強大,可是總體結構較爲相似,代碼結構清晰,容易擴展。html
將 Dropdown 分爲兩個模塊,父組件 Dropdown,子組件 Dropdown-option。其中Dropdown 負責控制總體的顯示,Drop-option 負責下拉菜單的每個選項。java
├── Dropdownide
├── Dropdown-optionpost
父組件主要負責的是選中項的顯示以及下拉菜單狀態(開、合)的控制。ui
具體的代碼以下this
<template>
<div :class="['dropdown', { 'is-hover': trigger === 'hover' && isOpen }]" tabindex="0" @click.stop="isOpen = !isOpen" @blur="trigger !== 'hover' && (isOpen = false)" >
<div :class="['dropdown__label']">
<slot name="label">
<span class="c-color-success">{{ placeholder }}</span>
</slot>
<fat-icon name="expand_more" class="c-color-success" />
</div>
<div class="dropdown__menu" v-if="trigger === 'hover' || isOpen">
<slot name="menu"></slot>
</div>
</div>
</template>
<script> export default { name: "dropdown", provide() { return { Dropdown: this }; }, props: { placeholder: { type: String, default: "下拉菜單" }, trigger: { type: String, default: "hover" }, selectValue: { type: [String, Number] }, optionKey: { type: String, default: "value" } }, data() { return { isOpen: this.trigger === "hover", selectItem: {} }; }, model: { prop: "selectValue", event: "select" } }; 複製代碼
首先對處理下拉菜單開關狀態的控制,依據 trigger
也就是觸發方式的不一樣,能夠分爲兩類 hover
|| click
。spa
trigger = 'hover'
時,對最外層的 div
添加 is-hover
的類名,它主要是負責添加 :hover
僞類來顯示下拉菜單&.is-hover {
&:hover {
.dropdown__menu {
display: block;
}
}
.dropdown__menu {
display: none;
}
}
複製代碼
同時依據 trigger
初始化 isOpen
狀態爲 true
。雙向綁定
trigger = 'click'
時,利用 isOpen
的狀態來控制下拉菜單的開、合。主要是依據事件來觸發,利用 @click.stop="isOpen = !isOpen"
,來完成下來菜單的展開操做。以後,對最外層的 div
添加 tabindex="0"
屬性使得它可以觸發失焦事件 blur
,同時添加 @blur="trigger !== 'hover' && (isOpen = false)"
,意味着當它失效的時候,自動關閉下拉菜單。以上完成了 Dropdown 對下拉菜單控制的功能,利用 provide
,完成它與 Dropdown-option 的通信,傳遞 selectValue
、selectItem
、optionKey
。
Dropdown-option 是下拉菜單的每一個選項,其基本結構
<template>
<div :class="[ 'dorpdown-option', { 'is-disabled': disabled }, { 'is-selected': isSelected } ]" @mousedown="handleClick" >
<slot>
{{ label }}
</slot>
</div>
</template>
複製代碼
主要是利用默認插槽,和 label
屬性來構建每一項,而且包含着兩種狀態,是否 disabled 或 selected。disabled 狀態是依據 props: disabled
來改變的,而 selected 則是由 computed
來完成的
<script>
export default {
inject: {
Dropdown: { default: "Dropdown" }
},
computed: {
isSelected() {
const {
Dropdown: { optionKey, selectValue }
} = this;
const key = this[optionKey] || this.$attrs[optionKey];
return key === selectValue;
}
},
...
};
</script>
複製代碼
首先利用 inject
將父組件 Dropdown 注入,這樣能夠經過 this.Dropdown
來訪問它的狀態、屬性。
而後在 isSelected()
中獲取 selectValue
,與當前 Dropdown-option 的 key
值進行比對,查看是否爲選中項。
爲了要引入 optionKey,是由於在實際的業務中,有的場景會以 label 做爲去區分項,有的則是以 value,故引入,方便自定義。
每一個 Dropdown-option 具有選中功能,可是從 @mousedown="handleClick"
能夠看出,利用 mousedown 來代替 click 事件
因爲咱們利用 Dropdown 的 blur 事件來控制下拉列表的展開與關閉,此時若是利用 click 事件,則會在 blur 以後觸發,因此沒法選中。故採用 mousedown 來完成該功能。
methods: {
handleSelect(key) {
let {
Dropdown: { multiple, trigger },
value,
label
} = this;
this.Dropdown.$emit("change", key);
this.Dropdown.$emit("select", key);
if (trigger !== "hover") {
this.Dropdown.isOpen = false;
}
},
handleClick() {
let {
Dropdown: { optionKey },
disabled
} = this;
const key = this[optionKey] || this.$attrs[optionKey];
if (!disabled) {
this.$slots.default[0].elm.click && this.$slots.default[0].elm.click();
key && this.handleSelect(key);
}
}
}
複製代碼
這一份部分的邏輯就比較簡單了,只有一處須要解釋下
this.$slots.default[0].elm.click && this.$slots.default[0].elm.click();
複製代碼
因爲咱們利用 mousedown 來代替原來的 click 事件,但咱們利用 slot
插槽來完成下拉菜單的開發時,就沒法觸發 slot
的點擊時間,因此利用上述代碼來手動觸發。
因爲 Dropdown 組件中,使用了 v-model
來完成數據的雙向綁定
model: {
prop: "selectValue",
event: "select"
}
複製代碼
因此在 Dropdown-option 中則須要利用 this.Dropdown.$emit("select", key);
來完成雙向綁定。
代碼地址:Dropdown Github
實例:Fat-UI lib