[TOC]
>[success] # CheckboxGroup
~~~
1.無論是使用iview 還是element ui,都可以發現在'checkbox'這里他們都會提供一個組件叫
'CheckboxGroup',會將'checkbox' 數據統一管理,我們來以'iview' 為例:
<template>
<i-checkbox-group v-model="multiple">
<i-checkbox label="option1">選項 1</i-checkbox>
<i-checkbox label="option2">選項 2</i-checkbox>
<i-checkbox label="option3">選項 3</i-checkbox>
<i-checkbox label="option4">選項 4</i-checkbox>
</i-checkbox-group>
</template>
<script>
export default {
data () {
return {
multiple: ['option1', 'option3']
}
}
}
</script>
所以這章節就是封裝一個'CheckboxGroup' 組件
~~~
>[info] ## 上個章節分裝的checkbox組件和實際原生的區別
~~~
1.在封裝之前,給先知道原生的'checkbox' 和我們上個章節封裝的不同點
~~~
>[danger] ##### 原生
~~~
1.這里直接用了vue官方文檔的案例
2.可以發現原生"checkbox" 本身綁定的就是數組,是不是有點懵了,上個章節我們封裝的'checkbox'組件綁定
的只能是'String,Number,Boolean'這三種類型,其實上個章節案例將'value' 這個綁定值改為數組,在做一些
略微邏輯跳轉也可以實現類似原生的方法
~~~
~~~
<div id='example-3'>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>
~~~
~~~
new Vue({
el: '#example-3',
data: {
checkedNames: []
}
})
~~~
>[info] ## 為了可以和原生一樣綁定數組寫 -- CheckboxGroup 組件
~~~
1.寫組件從三個方面入手'props','events','slots',根據iview組件我們也可以簡單分析出來,
首先使用的時候用的是'v-model',那就一定有兩個一個是'value',一個是'input'事件,
再就是有一個'solt' 用來放置封裝好的'checkbox'組件
~~~
>[danger] ##### 改進我們的checkbox 組件讓更像原生用法
~~~
1.現在我們要將我們上一個章節的'checkbox'可以也綁定數組,對照iview我們大體設計如下:
~~~
* iview
~~~
<i-checkbox label="option1">選項 1</i-checkbox>
~~~
* 我們大體猜想
~~~
1.iview 中'<i-checkbox label="option1">選項 1</i-checkbox>' label 作為封裝組件的'props'中的屬性傳遞給
'label',在就保證這一組的input中'v-model'綁定都是相同的數組
~~~
~~~
<input
type="checkbox"
:disabled="disabled"
:value="label"
v-model="model"
@change="change"
/>
~~~
>[danger] ##### 改造checkbox組件
~~~
1.我們將checkbox組件通過if分割成了兩組,一組是我們之前的用綁定是'String,Number,Boolean'這三種類型,
一組是我們為了讓他像原生一樣綁定的是數組
2.我們現在可以確定一點的思路就是如果是最外層使用的是'CheckboxGroup' 組件,那將使用的就是我們的數組
形式的input,這里在'mounted'聲明周期使用'findComponentUpward'在組件通訊章節講的寫法,去找當前組件的
父級是否是使用'CheckboxGroup' 組件包裹來決定使用哪種模式的'checkbox'
~~~
~~~
<template>
<label>
<span>
<input
v-if="group"
type="checkbox"
:disabled="disabled"
:value="label"
v-model="model"
@change="change"
/>
<input v-else type="checkbox" :disabled="disabled" :checked="currentValue" @change="change" />
</span>
<slot></slot>
</label>
</template>
<script>
import { findComponentUpward } from "@/lib/util.js";
export default {
name: "iCheckbox",
props: {
label: {
type: [String, Number, Boolean]
},
disabled: {
type: Boolean,
default: false
},
value: {
type: [String, Number, Boolean],
default: false
},
trueValue: {
type: [String, Number, Boolean],
default: true
},
falseValue: {
type: [String, Number, Boolean],
default: false
}
},
data() {
return {
model: [],
group: false,
parent: null,
currentValue: this.value
};
},
methods: {
change(event) {
if (this.disabled) {
return false;
}
const checked = event.target.checked;
this.currentValue = checked;
const value = checked ? this.trueValue : this.falseValue;
this.$emit("input", value);
console.log(this.model);
if (this.group) {
this.parent.change(this.model);
} else {
this.$emit("on-change", value);
}
},
updateModel() {
this.currentValue = this.value === this.trueValue;
}
},
mounted() {
this.parent = findComponentUpward(this, "iCheckboxGroup");
if (this.parent) {
this.group = true;
}
if (this.group) {
// 關于updateModel 寫法往下看,這里不用加因為下面父組件的生命周期
// 也做了同樣的事感覺不用加
this.parent.updateModel(true);
} else {
this.updateModel();
}
console.log(this.model);
}
};
</script>
~~~
>[danger] ##### 現在來分析我們的 CheckboxGroup 組件寫法
~~~
1.上面有個'updateModel'方法具體思路,我們先思考一下首先,'CheckboxGroup' 組件插槽中的每一個
'checkedbox' 組件的'v-model'綁定的數組一定要是一個數組,這個數組就是'CheckboxGroup' 傳入進來的數組
2.因此現在的思路就是使用我們組件通信章節說的'findComponentsDownward'向下找到所有在當前組件
'CheckboxGroup' 里面的每一個'checkedbox'組件,并且給他們的'v-model'綁定的數組值都賦值成'CheckboxGroup'
的數組。
3.在'updateModel'方法中有個地方需要說明一下:
if (this.childrens) {
// 這里的this 指代的是當前'CheckboxGroup' 組件,首先因為是一個實例所以肯定是一個對象
// 這里又使用了es6 解構獲取 value 值,這個value值是誰呢?
// 首先我們看使用 <checkbox-group v-model="multiple">,因此其實當前這個組件有個隱藏的props
// 這個props 就是value 這個value 綁定的又是獲取每一項的數組
// 因此將每一項'checkedbox'要管理的數組我們找到了,現在又有每一個子項的對象
// 將每一個子項對象中的'model ' 都綁定上這個統一的數組
const { value } = this;
console.log(this);
this.childrens.forEach(child => {
child.model = value;
if (update) {
child.currentValue = value.indexOf(child.label) >= 0;
child.group = true;
}
});
}
~~~
~~~
<template>
<div>
<slot></slot>
</div>
</template>
<script>
import { findComponentsDownward } from "@/lib/util.js";
export default {
name: "iCheckboxGroup",
props: {
value: {
type: Array,
default() {
return [];
}
}
},
data() {
return {
currentValue: this.value,
childrens: []
};
},
methods: {
updateModel(update) {
this.childrens = findComponentsDownward(this, "iCheckbox");
if (this.childrens) {
const { value } = this;
console.log(this);
this.childrens.forEach(child => {
child.model = value;
if (update) {
child.currentValue = value.indexOf(child.label) >= 0;
child.group = true;
}
});
}
},
change(data) {
this.currentValue = data;
this.$emit("input", data);
this.$emit("on-change", data);
}
},
mounted() {
this.updateModel(true);
},
watch: {
value() {
this.updateModel(true);
}
}
};
</script>
~~~
>[danger] ##### 使用的效果
~~~
<template>
<div>
{{multiple}}
<checkbox-group v-model="multiple">
<checkbox label="option1">選項 1</checkbox>
<checkbox label="option2">選項 2</checkbox>
</checkbox-group>
</div>
</template>
<script>
import Checkbox from "@/components/checkbox/Checkbox.vue";
import CheckboxGroup from "@/components/checkbox/CheckboxGroup.vue";
export default {
data() {
return {
multiple: ["option1"],
};
},
components: {
Checkbox,
CheckboxGroup
}
};
</script>
<style>
</style>
~~~
- Vue--基礎篇章
- Vue -- 介紹
- Vue -- MVVM
- Vue -- 創建Vue實例
- Vue -- 模板語法
- Vue -- 指令用法
- v-cloak -- 遮蓋
- v-bind -- 標簽屬性動態綁定
- v-on -- 綁定事件
- v-model -- 雙向數據綁定
- v-for -- 只是循環沒那么簡單
- 小知識點 -- 計劃內屬性
- key -- 屬性為什么要加
- 案例說明
- v-if/v-show -- 顯示隱藏
- v-for 和 v-if 同時使用
- v-pre -- 不渲染大大胡語法
- v-once -- 只渲染一次
- Vue -- class和style綁定
- Vue -- filter 過濾器
- Vue--watch/computed/fun
- watch -- 巧妙利用watch思想
- Vue -- 自定義指令
- Vue -- $方法
- Vue--生命周期
- Vue -- 專屬ajax
- Vue -- transition過渡動畫
- 前面章節的案例
- 案例 -- 跑馬燈效果
- 案例 -- 選項卡內容切換
- 案例-- 篩選商品
- 案例 -- 搜索/刪除/更改
- 案例 -- 用computed做多選
- 案例 -- checked 多選
- Vue--組件篇章
- component -- 介紹
- component -- 使用全局組件
- component -- 使用局部組件
- component -- 組件深入
- component -- 組件傳值父傳子
- component -- 組件傳值子傳父
- component -- 子傳父語法糖拆解
- component -- 父組件操作子組件
- component -- is 動態切換組件
- component -- 用v-if/v-show控制子組件
- component -- 組件切換的動畫效果
- component -- slot 插槽
- component -- 插槽2.6
- component -- 組件的生命周期
- component -- 基礎組件全局注冊
- VueRouter--獲取路由參數
- VueRouter -- 介紹路由
- VueRouter -- 安裝
- VueRouter -- 使用
- VueRouter--router-link簡單參數
- VueRouter--router-link樣式問題
- VueRouter--router-view動畫效果
- VueRouter -- 匹配優先級
- vueRouter -- 動態路由
- VueRouter -- 命名路由
- VueRouter -- 命名視圖
- VueRouter--$router 獲取函數
- VueRouter--$route獲取參數
- VueRouter--路由嵌套
- VueRouter -- 導航守衛
- VueRouter -- 寫在最后
- Vue--模塊化方式結構
- webpack--自定義配置
- webpack -- 自定義Vue操作
- VueCli -- 3.0可視化配置
- VueCli -- 3.0 項目目錄
- Vue -- 組件升級篇
- Vue -- 組件種類與組件組成
- Vue -- 組件prop、event、slot 技巧
- Vue -- 組件通信(一)
- Vue -- 組件通信(二)
- Vue -- 組件通信(三)
- Vue -- 組件通信(四)
- Vue -- 組件通信(五)
- Vue -- 組件通信(六)
- Vue -- bus非父子組件通信
- Vue -- 封裝js插件成vue組件
- vue組件分裝 -- 進階篇
- Vue -- 組件封裝splitpane(分割面板)
- UI -- 正式封裝
- Vue -- iview 可編輯表格案例
- Ui -- iview 可以同時編輯多行
- Vue -- 了解遞歸組件
- UI -- 正式使用遞歸菜單
- Vue -- iview Tree組件
- Vue -- 利用通信仿寫一個form驗證
- Vue -- 使用自己的Form
- Vue -- Checkbox 組件
- Vue -- CheckboxGroup.vue
- Vue -- Alert 組件
- Vue -- 手動掛載組件
- Vue -- Alert開始封裝
- Vue -- 動態表單組件
- Vue -- Vuex組件的狀態管理
- Vuex -- 參數使用理解
- Vuex -- state擴展
- Vuex -- getters擴展
- Vuex--mutations擴展
- Vuex -- Action 異步
- Vuex -- plugins插件
- Vuex -- v-model寫法
- Vuex -- 更多
- VueCli -- 技巧總結篇
- CLI -- 路由基礎
- CLI -- 路由升級篇
- CLI --異步axios
- axios -- 封裝axios
- CLI -- 登錄寫法
- CLI -- 權限
- CLI -- 簡單權限
- CLI -- 動態路由加載
- CLI -- 數據性能優化
- ES6 -- 類的概念
- ES6類 -- 基礎
- ES6 -- 繼承
- ES6 -- 工作實戰用類數據管理
- JS -- 適配器模式
- ES7 -- 裝飾器(Decorator)
- 裝飾器 -- 裝飾器修飾類
- 裝飾器--修飾類方法(知識擴展)
- 裝飾器 -- 裝飾器修飾類中的方法
- 裝飾器 -- 執行順序
- Reflect -- es6 自帶版本
- Reflect -- reflect-metadata 版本
- 實戰 -- 驗證篇章(基礎)
- 驗證篇章 -- 搭建和目錄
- 驗證篇章 -- 創建基本模板
- 驗證篇章 -- 使用
- 實戰 -- 更新模型(為了迎合ui升級)
- 實戰 -- 模型與接口對接
- TypeSprict -- 基礎篇章
- TS-- 搭建(一)webpack版本
- TS -- 搭建(二)直接使用
- TS -- 基礎類型
- TS -- 枚舉類型
- TS -- Symbol
- TS -- interface 接口
- TS -- 函數
- TS -- 泛型
- TS -- 類
- TS -- 類型推論和兼容
- TS -- 高級類型(一)
- TS -- 高級類型(二)
- TS -- 關于模塊解析
- TS -- 聲明合并
- TS -- 混入
- Vue -- TS項目模擬
- TS -- vue和以前代碼對比
- TS -- vue簡單案例上手
- Vue -- 簡單弄懂VueRouter過程
- VueRouter -- 實現簡單Router
- Vue-- 原理2.x源碼簡單理解
- 了解 -- 簡單的響應式工作原理
- 準備工作 -- 了解發布訂閱和觀察者模式
- 了解 -- 響應式工作原理(一)
- 了解 -- 響應式工作原理(二)
- 手寫 -- 簡單的vue數據響應(一)
- 手寫 -- 簡單的vue數據響應(二)
- 模板引擎可以做的
- 了解 -- 虛擬DOM
- 虛擬dom -- 使用Snabbdom
- 閱讀 -- Snabbdom
- 分析snabbdom源碼 -- h函數
- 分析snabbdom -- init 方法
- init 方法 -- patch方法分析(一)
- init 方法 -- patch方法分析(二)
- init方法 -- patch方法分析(三)
- 手寫 -- 簡單的虛擬dom渲染
- 函數表達解析 - h 和 create-element
- dom操作 -- patch.js
- Vue -- 完成一個minVue
- minVue -- 打包入口
- Vue -- new實例做了什么
- Vue -- $mount 模板編譯階段
- 模板編譯 -- 分析入口
- 模板編譯 -- 分析模板轉譯
- Vue -- mountComponent 掛載階段
- 掛載階段 -- vm._render()
- 掛載階段 -- vnode
- 備份章節
- Vue -- Nuxt.js
- Vue3 -- 學習
- Vue3.x --基本功能快速預覽
- Vue3.x -- createApp
- Vue3.x -- 生命周期
- Vue3.x -- 組件
- vue3.x -- 異步組件???
- vue3.x -- Teleport???
- vue3.x -- 動畫章節 ??
- vue3.x -- 自定義指令 ???
- 深入響應性原理 ???
- vue3.x -- Option API VS Composition API
- Vue3.x -- 使用set up
- Vue3.x -- 響應性API
- 其他 Api 使用
- 計算屬性和監聽屬性
- 生命周期
- 小的案例(一)
- 小的案例(二)-- 泛型
- Vue2.x => Vue3.x 導讀
- v-for 中的 Ref 數組 -- 非兼容
- 異步組件
- attribute 強制行為 -- 非兼容
- $attrs 包括 class & style -- 非兼容
- $children -- 移除
- 自定義指令 -- 非兼容
- 自定義元素交互 -- 非兼容
- Data選項 -- 非兼容
- emits Option -- 新增
- 事件 API -- 非兼容
- 過濾器 -- 移除
- 片段 -- 新增
- 函數式組件 -- 非兼容
- 全局 API -- 非兼容
- 全局 API Treeshaking -- 非兼容
- 內聯模板 Attribute -- 非兼容
- key attribute -- 非兼容
- 按鍵修飾符 -- 非兼容
- 移除 $listeners 和 v-on.native -- 非兼容
- 在 prop 的默認函數中訪問 this -- ??
- 組件使用 v-model -- 非兼容
- 渲染函數 API -- ??
- Slot 統一 ??
- 過渡的 class 名更改 ???
- Transition Group 根元素 -- ??
- v-if 與 v-for 的優先級對比 -- 非兼容
- v-bind 合并行為 非兼容
- 監聽數組 -- 非兼容