最近vue项目需要用到三级CheckBox复选框,需要实现全选反选不确定三种状态。但是element-ui table只支持多选行,并不能支持三级及以上的多选,所以写了这篇博客以后学习使用。
效果图预览:

首先是页面布局,当然也可已使用table,但是自己用flex布局后面更容易增删改查其他功能
1 <div class="deliverySetting-table">
2 <div class="table-head">
3 <div class="selection">
4 <el-checkbox :indeterminate="indeterminate" v-model="ischeckAll" @change="handleCheckAllChange"></el-checkbox>
5 </div>
6 <div class="width185">分区名称</div>
7 <div class="width265">国家</div>
8 <div>派送商</div>
9 </div>
10 <div class="table-body" v-for="(partition,partitionIndex) in distributorsInfo" :key="partitionIndex">
11 <div class="selection">
12 <p><el-checkbox :indeterminate="partition.indeterminate" v-model="partition.selected" @change="handleCheckedCountryAllChange(partitionIndex,partition.partitionId,$event)" :key="partitionIndex"></el-checkbox></p>
13 </div>
14 <div class="width185"><p>{{ partition.partitionName }}</p></div>
15 <div class="width265">
16 <el-checkbox v-for="country in partition.country" v-model="country.selected" @change="handleCheckedCountryChange(partitionIndex,country.id,partition.partitionId,$event)" :label="country" :key="country.id">{{country.fieldName}}</el-checkbox>
17 </div>
18 <div>
19 <p v-for="(item,index) in partition.country" :key="index">
20 {{ item.distributors }}
21 </p>
22 </div>
23 </div>
24 </div>
接下来是数据结构,自定义的,可以更后台商议,但是字段indeterminate(显示不确定状态~符号),selected(CheckBox选中状态)一定要让后台加入到data中,其他可以按照后台数据来。
2 distributorsInfo:[
3 { partitionName:'1区',selected:false,partitionId:1,isIndeterminate:false,
4 country:[
5 { id: "1",fieldName: "奥地利",fieldTableName: "奥地利",distributors:'UPS',selected: false},
6 { id: "2",fieldName: "芬兰",fieldTableName: "芬兰",distributors:'UPS',selected: false},
7 { id: "3",fieldName: "意大利",fieldTableName: "意大利",distributors:'UPS',selected: false},
8 { id: "4",fieldName: "葡萄牙",fieldTableName: "葡萄牙",distributors:'UPS',selected: false},
9 { id: "9",fieldName: "西班牙",fieldTableName: "西班牙",distributors:'UPS',selected: false},
10 { id: "10",fieldName: "瑞典",fieldTableName: "瑞典",distributors:'UPS',selected: false},]
11 },
12 { partitionName:'2区',selected:false,partitionId:2,isIndeterminate:false,
13 country:[
14 { id: "5",fieldName: "丹麦",fieldTableName: "单买",distributors:'',selected: false},
15 { id: "6",fieldName: "法国",fieldTableName: "法国",distributors:'',selected: false},]
16 },
17 { partitionName:'3区',selected:false,partitionId:3,isIndeterminate:false,
18 country:[
19 { id: "7",fieldName: "德国",fieldTableName: "德国",distributors:'YODEL',selected: false},
20 { id: "8",fieldName: "瑞士",fieldTableName: "瑞士",distributors:'DPD',selected: false}]
21 }
22 ],
23 ischeckAll:false,//一级全选状态
因为此处是三级复选,所以函数为三个change,具体有详细注释可以查看
1 handleCheckAllChange(e){//一级change事件
2 this.ischeckAll = e
3 if(e == true){
4 this.indeterminate = false
5 for(var i=0,len=this.distributorsInfo.length; i<len; i++){ //二级全选反选不确定
6 this.distributorsInfo[i].selected = e
7 for(var j=0,len1=this.distributorsInfo[i].country.length; j<len1; j++){
8 this.distributorsInfo[i].country[j].selected = e
9 }
10 }
11 }else{
12 this.indeterminate = false
13 for(var i=0,len=this.distributorsInfo.length; i<len; i++){ //三级全选反选不确定
14 this.distributorsInfo[i].selected = e
15 for(var j=0,len1=this.distributorsInfo[i].country.length; j<len1; j++){
16 this.distributorsInfo[i].country[j].selected = e
17 }
18 }
19 }
20 },
21 handleCheckedCountryAllChange(index, topId, e){//二级change事件
22 this.distributorsInfo[index].selected = e//二级勾选后,子级全部勾选或者取消
23 if(e == false) this.distributorsInfo[index].indeterminate = false //去掉二级不确定状态
24 var childrenArray = this.distributorsInfo[index].country
25 if(childrenArray)
26 for(var i=0,len=childrenArray.length; i<len; i++)
27 childrenArray[i].selected = e
28
29 this.getIsCheckAll()
30 },
31 handleCheckedCountryChange(topIndex, sonId, topId, e){//三级change事件
32 var childrenArray = this.distributorsInfo[topIndex].country
33 var tickCount = 0, unTickCount = 0, len = childrenArray.length
34 for(var i = 0; i < len; i++){
35 if(sonId == childrenArray[i].id) childrenArray[i].selected = e
36 if(childrenArray[i].selected == true) tickCount++
37 if(childrenArray[i].selected == false) unTickCount++
38 }
39 if(tickCount == len) {//三级级全勾选
40 this.distributorsInfo[topIndex].selected = true
41 this.distributorsInfo[topIndex].indeterminate = false
42 } else if(unTickCount == len) {//三级级全不勾选
43 this.distributorsInfo[topIndex].selected = false
44 this.distributorsInfo[topIndex].indeterminate = false
45 } else {
46 this.distributorsInfo[topIndex].selected = false
47 this.distributorsInfo[topIndex].indeterminate = true //添加二级不确定状态
48 }
49
50 this.getIsCheckAll()
51 },
52 getIsCheckAll(){
53 var tickCount = 0, unTickCount = 0, ArrLength = this.distributorsInfo.length
54 for(var j=0; j<ArrLength; j++){//全选checkbox状态
55 if(this.distributorsInfo[j].selected == true) tickCount++
56 if(this.distributorsInfo[j].selected == false) unTickCount++
57 }
58 if(tickCount == ArrLength) {//二级全勾选
59 this.ischeckAll = true
60 this.indeterminate = false
61 } else if(unTickCount == ArrLength) {//二级全不勾选
62 this.ischeckAll = false
63 this.indeterminate = false
64 } else {
65 this.ischeckAll = false
66 this.indeterminate = true //添加一级不确定状态
67 }
68 },
以下是页面完整组件代码可以使用预览


1 <template>
2 <div class="deliverySetting">
3 <div class="deliverySetting-btn">
4 <div class="tabs-btn ac">
5 <input type="button" value="分配派送商" @click="showSetDistributorDailog">
6 </div>
7 <div class="tabs-btn ac">
8 <input type="button" value="取消分配" @click="showCancelDistributorDailog">
9 </div>
10 </div>
11
12 <div class="deliverySetting-table">
13 <div class="table-head">
14 <div class="selection">
15 <el-checkbox :indeterminate="indeterminate" v-model="ischeckAll" @change="handleCheckAllChange"></el-checkbox>
16 </div>
17 <div class="width185">分区名称</div>
18 <div class="width265">国家</div>
19 <div>派送商</div>
20 </div>
21 <div class="table-body" v-for="(partition,partitionIndex) in distributorsInfo" :key="partitionIndex">
22 <div class="selection">
23 <p><el-checkbox :indeterminate="partition.indeterminate" v-model="partition.selected" @change="handleCheckedCountryAllChange(partitionIndex,partition.partitionId,$event)" :key="partitionIndex"></el-checkbox></p>
24 </div>
25 <div class="width185"><p>{{ partition.partitionName }}</p></div>
26 <div class="width265">
27 <el-checkbox v-for="country in partition.country" v-model="country.selected" @change="handleCheckedCountryChange(partitionIndex,country.id,partition.partitionId,$event)" :label="country" :key="country.id">{{country.fieldName}}</el-checkbox>
28 </div>
29 <div>
30 <p v-for="(item,index) in partition.country" :key="index">
31 {{ item.distributors }}
32 </p>
33 </div>
34 </div>
35 </div>
36
37 <!-- 分配派送商dailog -->
38 <el-dialog title="分配派送商" :visible.sync="setDistributorDailog" width="480px">
39 <el-form :model="distributorForm" :rules="rules" class="setDistributorDailog">
40 <el-form-item label="派送代理商" label-width="120px">
41 <el-input v-model="distributorForm.vendorName" auto-complete="off" placeholder="请输入供应商名称"></el-input>
42 </el-form-item>
43 <el-form-item label="末端派送商" prop="senderName" label-width="120px">
44 <el-select v-model="distributorForm.senderName"
45 filterable
46 allow-create
47 default-first-option
48 placeholder="请选派送商名称">
49 <el-option label="派送商1" value="shanghai"></el-option>
50 <el-option label="派送商2" value="beijing"></el-option>
51 </el-select>
52 </el-form-item>
53 <el-form-item label="派送商官网" prop="website" label-width="120px">
54 <el-input v-model="distributorForm.website" auto-complete="off" placeholder="请输入派送商官网"></el-input>
55 </el-form-item>
56 </el-form>
57 <div slot="footer" class="dialog-footer">
58 <el-button @click="setDistributorDailog = false">取 消</el-button>
59 <el-button type="primary" @click="setDistributorDailog = false">确 定</el-button>
60 </div>
61 </el-dialog>
62
63 <!-- 取消分配派送商 -->
64 <el-dialog title="停止提示" :visible.sync="cancelDistributorDailog" :modal="false" width="480px" custom-class="stop-coupon-dialog">
65 <p><br></p>
66 <p class="ac f16">您确定要取消对的派送分配吗?</p>
67 <p><br></p>
68 <span slot="footer" class="dialog-footer">
69 <el-button @click="cancelDistributorDailog = false">取 消</el-button>
70 <el-button type="primary" @click="cancelDistributorDailog=false">确 定</el-button>
71 </span>
72 </el-dialog>
73 </div>
74 </template>
75 <script>
76 export default {
77 name:'deliverySetting',
78 components: {
79 },
80 props:{
81 },
82 data() {
83 return {
84 distributorsInfo:[
85 { partitionName:'1区',selected:false,partitionId:1,isIndeterminate:false,
86 country:[
87 { id: "1",fieldName: "奥地利",fieldTableName: "奥地利",distributors:'UPS',selected: false},
88 { id: "2",fieldName: "芬兰",fieldTableName: "芬兰",distributors:'UPS',selected: false},
89 { id: "3",fieldName: "意大利",fieldTableName: "意大利",distributors:'UPS',selected: false},
90 { id: "4",fieldName: "葡萄牙",fieldTableName: "葡萄牙",distributors:'UPS',selected: false},
91 { id: "9",fieldName: "西班牙",fieldTableName: "西班牙",distributors:'UPS',selected: false},
92 { id: "10",fieldName: "瑞典",fieldTableName: "瑞典",distributors:'UPS',selected: false},]
93 },
94 { partitionName:'2区',selected:false,partitionId:2,isIndeterminate:false,
95 country:[
96 { id: "5",fieldName: "丹麦",fieldTableName: "单买",distributors:'',selected: false},
97 { id: "6",fieldName: "法国",fieldTableName: "法国",distributors:'',selected: false},]
98 },
99 { partitionName:'3区',selected:false,partitionId:3,isIndeterminate:false,
100 country:[
101 { id: "7",fieldName: "德国",fieldTableName: "德国",distributors:'YODEL',selected: false},
102 { id: "8",fieldName: "瑞士",fieldTableName: "瑞士",distributors:'DPD',selected: false}]
103 }
104 ],
105 ischeckAll:false,//一级全选状态
106 setDistributorDailog:false,
107 cancelDistributorDailog:false,
108 distributorForm:{
109 vendorName:'',
110 senderName:''
111 },
112 indeterminate:false,
113 rules: {
114 senderName: [{ required: true, message: '字段不能为空',trigger: 'blur'}],
115 website: [{ required: true, message: '字段不能为空',trigger: 'blur'}],
116 },
117 }
118 },
119 computed: {
120 },
121 methods: {
122 handleCheckAllChange(e){//一级change事件
123 this.ischeckAll = e
124 if(e == true){
125 this.indeterminate = false
126 for(var i=0,len=this.distributorsInfo.length; i<len; i++){ //二级全选反选不确定
127 this.distributorsInfo[i].selected = e
128 for(var j=0,len1=this.distributorsInfo[i].country.length; j<len1; j++){
129 this.distributorsInfo[i].country[j].selected = e
130 }
131 }
132 }else{
133 this.indeterminate = false
134 for(var i=0,len=this.distributorsInfo.length; i<len; i++){ //三级全选反选不确定
135 this.distributorsInfo[i].selected = e
136 for(var j=0,len1=this.distributorsInfo[i].country.length; j<len1; j++){
137 this.distributorsInfo[i].country[j].selected = e
138 }
139 }
140 }
141 },
142 handleCheckedCountryAllChange(index, topId, e){//二级change事件
143 this.distributorsInfo[index].selected = e//二级勾选后,子级全部勾选或者取消
144 if(e == false) this.distributorsInfo[index].indeterminate = false //去掉二级不确定状态
145 var childrenArray = this.distributorsInfo[index].country
146 if(childrenArray)
147 for(var i=0,len=childrenArray.length; i<len; i++)
148 childrenArray[i].selected = e
149
150 this.getIsCheckAll()
151 },
152 handleCheckedCountryChange(topIndex, sonId, topId, e){//三级change事件
153 var childrenArray = this.distributorsInfo[topIndex].country
154 var tickCount = 0, unTickCount = 0, len = childrenArray.length
155 for(var i = 0; i < len; i++){
156 if(sonId == childrenArray[i].id) childrenArray[i].selected = e
157 if(childrenArray[i].selected == true) tickCount++
158 if(childrenArray[i].selected == false) unTickCount++
159 }
160 if(tickCount == len) {//三级级全勾选
161 this.distributorsInfo[topIndex].selected = true
162 this.distributorsInfo[topIndex].indeterminate = false
163 } else if(unTickCount == len) {//三级级全不勾选
164 this.distributorsInfo[topIndex].selected = false
165 this.distributorsInfo[topIndex].indeterminate = false
166 } else {
167 this.distributorsInfo[topIndex].selected = false
168 this.distributorsInfo[topIndex].indeterminate = true //添加二级不确定状态
169 }
170
171 this.getIsCheckAll()
172 },
173 getIsCheckAll(){
174 var tickCount = 0, unTickCount = 0, ArrLength = this.distributorsInfo.length
175 for(var j=0; j<ArrLength; j++){//全选checkbox状态
176 if(this.distributorsInfo[j].selected == true) tickCount++
177 if(this.distributorsInfo[j].selected == false) unTickCount++
178 }
179 if(tickCount == ArrLength) {//二级全勾选
180 this.ischeckAll = true
181 this.indeterminate = false
182 } else if(unTickCount == ArrLength) {//二级全不勾选
183 this.ischeckAll = false
184 this.indeterminate = false
185 } else {
186 this.ischeckAll = false
187 this.indeterminate = true //添加一级不确定状态
188 }
189 },
190
191 showSetDistributorDailog(){
192 this.setDistributorDailog=true
193 },
194 showCancelDistributorDailog(){
195 this.cancelDistributorDailog=true
196 }
197 },
198 created: function() {
199 },
200 mounted: function() {
201 // (async() => {
202 },
203 watch: {
204 }
205 }
206 </script>
207 <style lang="scss">
208 .deliverySetting{
209 padding: 20px 0;
210 position: relative;
211 .el-table{
212 thead{
213 tr{
214 th{
215 font-size: 14px;
216 }
217 }
218 }
219 tbody{
220 tr{
221 td{
222 vertical-align: baseline;
223 p{
224 line-height: 30px;
225 }
226 .el-checkbox-group{
227 display: flex;
228 flex-direction: column;
229 label{
230 line-height: 30px;
231 margin-left: 0;
232 }
233 }
234 }
235 }
236 }
237 }
238 .deliverySetting-table{
239 font-size: 14px;
240 color: #333;
241 .table-head,
242 .table-body{
243 display: flex;
244 padding: 10px 0;
245 .selection{
246 width: 45px;
247 text-align: center;
248 line-height: 36px;
249 }
250 .width185{
251 width: 185px;
252 }
253 .width265{
254 width: 265px;
255 }
256 }
257 .table-head{
258 height: 36px;
259 align-items: center;
260 background-color: #E7F2FF;
261 }
262 .table-body{
263 border-bottom: 1px solid #e4e4e4;
264 color: #666;
265 &:hover{
266 background-color: #f5f7fa;
267 }
268 .width265{
269 display: flex;
270 flex-direction: column;
271 label{
272 line-height: 30px;
273 margin-left: 0;
274 color: #666;
275 }
276 }
277 p{
278 line-height: 30px;
279 }
280 }
281 }
282 .deliverySetting-btn{
283 /*width: 100%;*/
284 height: 59px;
285 display: flex;
286 justify-content: flex-end;
287 align-items: center;
288 position: absolute;
289 top: -55px;
290 right: -16px;
291 z-index: 100;
292 .tabs-btn {
293 min-width: 90px;
294 height: 34px;
295 line-height: 32px;
296 padding: 0 10px;
297 color: #2387f7;
298 border: solid 1px #4fa2ff;
299 background-color: #e7f2ff;
300 cursor: pointer;
301 &:nth-of-type(2) {
302 margin: 0 15px;
303 }
304 input {
305 border: none;
306 background: transparent;
307 color: inherit;
308 cursor: inherit;
309 outline: none;
310 margin: 0;
311 padding: 0;
312 }
313 &:hover {
314 color: #fff;
315 background-color: #2387f7;
316 }
317 }
318 }
319 .setDistributorDailog{
320 .el-input{
321 width: 270px;
322 }
323 }
324 }
325 </style>
好了,以后使用三级甚至多级复选都可以使用此方法添加change代码即可。
来源:oschina
链接:https://my.oschina.net/u/4334770/blog/3298852