從零實現Vue的元件庫(十五)- Checkbox-Group 實現
1. 例項

程式碼
<!-- 基礎用法 --> <fat-checkbox-group v-model="anotherValue"> <fat-checkbox value="あらがき ゆい"> <fat-hover-tip type="right-center"> <template slot="hover-part">あらがき ゆい</template> <template slot="tip-part"> <img src="/static/img/gakki.jpg" style="width: 100px" alt="示意圖"> </template> </fat-hover-tip> </fat-checkbox> <fat-checkbox value="石原さとみ"> <fat-hover-tip type="right-center"> <template slot="hover-part">石原さとみ</template> <template slot="tip-part"> <img src="/static/img/u=4046980169,286278015&fm=26&gp=0.jpg" style="width: 100px" alt="示意圖" > </template> </fat-hover-tip> </fat-checkbox> </fat-checkbox-group> 複製程式碼
例項地址:CheckboxGroup 例項
程式碼地址: Github UI-Library
2. 原理
Checkbox
首先單獨實現 Checkbox 元件,它是由 label
和 input
兩部分構成,主要區分兩個狀態, checked
以及 disabled
。
<template> <label :class="[ 'checkbox-item', { 'is-checked': isChecked }, { 'is-disabled': isDisabled } ]" @click.stop="handleClick" > <span class="checkbox-input"> <fat-icon name="check"/> </span> <input v-if="false" type="checkbox" v-bind="$attrs" :value="model" @click.stop > <slot></slot> </label> </template> <script> export default { props: { value: { type: [String, Number], required: true }, disabled: { type: [Boolean], default: false }, propValue: { type: [String, Number, Boolean] } }, model: { prop: "propValue", event: "select" }, computed: { isGroup() { return this.$parent.$options._componentTag === "fat-checkbox-group"; }, isDisabled() { return this.$parent.disabled || this.disabled; }, isChecked() { const { isGroup, model } = this; if (!isGroup) return model; const { value, $parent: { value: selectItems } } = this; return selectItems.some(item => item === value); }, model: { get() { return this.isGroup ? this.$parent.value : this.propValue; }, set(newValue) { const { isGroup, isChecked } = this; if (isGroup) { isChecked ? this.$parent.deleteItem(newValue) : this.$parent.selectItem(newValue); } else { this.$emit("select", newValue); } } } }, methods: { handleClick(event) { const { isDisabled, isGroup, model, value } = this; if (!isDisabled) { this.model = isGroup ? value : !model; } } } }; </script> 複製程式碼
同 Radio
一樣,由於需要實現 Checkout
可以單獨使用的,所以不採用 provide / inject
api,而是利用 this.$parent.$options._componentTag
判斷,當前元件是否為 Group
。
同時,依據當前元件是否為 Group
來定義 isDisabled
、 isChecked
等狀態的判斷條件,例如
isChecked() { const { isGroup, model } = this; if (!isGroup) return model; const { value, $parent: { value: selectItems } } = this; return selectItems.some(item => item === value); } 複製程式碼
如果當前為多選組,就會利用 some
來判斷當前 Checkout 的 value 是否在其中,然後如果單獨使用,則直接返回 model
。
同樣, model
的值也是依據 isGroup
進行區分
model: { get() { return this.isGroup ? this.$parent.value : this.propValue; }, set(newValue) { const { isGroup, isChecked } = this; if (isGroup) { isChecked ? this.$parent.deleteItem(newValue) : this.$parent.selectItem(newValue); } else { this.$emit("select", newValue); } } } 複製程式碼
CheckboxGroup
則是在 Checkbox 的外部包裹一層 Group 用於,實現組的概念
<template> <div class="checkbox-group-wrapper" name="checkbox-group"> <slot></slot> </div> </template> <script> export default { name: "checkbox-group", props: { value: { type: Array, required: true }, disabled: { type: Boolean } }, model: { prop: "value", event: "select" }, watch: { value(newValue) { this.$emit("change", newValue); } }, methods: { selectItem(item) { const { value } = this; this.$emit("select", [...value, item]); }, deleteItem(item) { const { value: selectItems } = this; this.$emit( "select", selectItems.filter(selectitem => selectitem !== item) ); } } }; </script> 複製程式碼
在 Checkbox-Group
內維護了
methods: { selectItem(item) { const { value } = this; this.$emit("select", [...value, item]); }, deleteItem(item) { const { value: selectItems } = this; this.$emit( "select", selectItems.filter(selectitem => selectitem !== item) ); } } 複製程式碼
用於和 Checkbox
通訊,如果當前是多選組的形式,則需要利用 selectItem
以及 deleteItem
來對其進行增減。