vue基于element-ui的三级CheckBox复选框

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

效果图预览:

首先是页面布局,当然也可以使用框架自带的table布局,这里博主自己用的flex布局,这样后面更利于增删改查其他功能


 

接下来是数据结构,可以跟后端商议,但是字段indeterminate(显示不确定状态~符号),selected(CheckBox选中状态)一定要让后端加入到data中。

<template>
    <div class="deliverySetting">
        <div class="deliverySetting-btn">
            <div class="tabs-btn ac">
                <input type="button" value="分配派送商" @click="showSetDistributorDailog">
            </div>
            <div class="tabs-btn ac">
                <input type="button" value="取消分配" @click="showCancelDistributorDailog">
            </div>
        </div>
 
        <div class="deliverySetting-table">
            <div class="table-head">
                <div class="selection">
                    <el-checkbox :indeterminate="indeterminate" v-model="ischeckAll" @change="handleCheckAllChange"></el-checkbox>
                </div>
                <div class="width185">分区名称</div>
                <div class="width265">国家</div>
                <div>派送商</div>
            </div>
            <div class="table-body" v-for="(partition,partitionIndex) in distributorsInfo" :key="partitionIndex">
                <div class="selection">
                    <p><el-checkbox :indeterminate="partition.indeterminate" v-model="partition.selected" @change="handleCheckedCountryAllChange(partitionIndex,partition.partitionId,$event)" :key="partitionIndex"></el-checkbox></p>
                </div>
                <div class="width185"><p>{{ partition.partitionName }}</p></div>
                <div class="width265">
                    <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>
                </div>
                <div>
                    <p v-for="(item,index) in partition.country" :key="index">
                        {{ item.distributors }}
                    </p>
                </div>
            </div>
        </div>
 
        <!-- 分配派送商dailog -->
        <el-dialog title="分配派送商" :visible.sync="setDistributorDailog" width="480px">
            <el-form :model="distributorForm" :rules="rules" class="setDistributorDailog">
                <el-form-item label="派送代理商" label-width="120px">
                    <el-input v-model="distributorForm.vendorName" auto-complete="off" placeholder="请输入供应商名称"></el-input>
                </el-form-item>
                <el-form-item label="末端派送商" prop="senderName" label-width="120px">
                    <el-select v-model="distributorForm.senderName"
                    filterable
                    allow-create
                    default-first-option
                    placeholder="请选派送商名称">
                        <el-option label="派送商1" value="shanghai"></el-option>
                        <el-option label="派送商2" value="beijing"></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="派送商官网" prop="website" label-width="120px">
                    <el-input v-model="distributorForm.website" auto-complete="off" placeholder="请输入派送商官网"></el-input>
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click="setDistributorDailog = false">取 消</el-button>
                <el-button type="primary" @click="setDistributorDailog = false">确 定</el-button>
            </div>
        </el-dialog>
 
        <!-- 取消分配派送商 -->
        <el-dialog title="停止提示" :visible.sync="cancelDistributorDailog" :modal="false" width="480px" custom-class="stop-coupon-dialog">
            <p><br></p>
            <p class="ac f16">您确定要取消对的派送分配吗?</p>
            <p><br></p>
            <span slot="footer" class="dialog-footer">
                <el-button @click="cancelDistributorDailog = false">取 消</el-button>
                <el-button type="primary" @click="cancelDistributorDailog=false">确 定</el-button>
            </span>
        </el-dialog>
    </div>
</template>
<script>
    export default {
        name:'deliverySetting',
        components: {
        },
        props:{
        },
        data() {
            return {
                distributorsInfo:[
                    { partitionName:'1区',selected:false,partitionId:1,isIndeterminate:false,
                        country:[
                        {   id: "1",fieldName: "奥地利",fieldTableName: "奥地利",distributors:'UPS',selected: false},
                        {   id: "2",fieldName: "芬兰",fieldTableName: "芬兰",distributors:'UPS',selected: false},
                        {   id: "3",fieldName: "意大利",fieldTableName: "意大利",distributors:'UPS',selected: false},
                        {   id: "4",fieldName: "葡萄牙",fieldTableName: "葡萄牙",distributors:'UPS',selected: false},
                        {   id: "9",fieldName: "西班牙",fieldTableName: "西班牙",distributors:'UPS',selected: false},
                        {   id: "10",fieldName: "瑞典",fieldTableName: "瑞典",distributors:'UPS',selected: false},]
                    },
                    { partitionName:'2区',selected:false,partitionId:2,isIndeterminate:false,
                        country:[
                        {   id: "5",fieldName: "丹麦",fieldTableName: "单买",distributors:'',selected: false},
                        {   id: "6",fieldName: "法国",fieldTableName: "法国",distributors:'',selected: false},]
                    },
                    { partitionName:'3区',selected:false,partitionId:3,isIndeterminate:false,
                        country:[
                        {   id: "7",fieldName: "德国",fieldTableName: "德国",distributors:'YODEL',selected: false},
                        {   id: "8",fieldName: "瑞士",fieldTableName: "瑞士",distributors:'DPD',selected: false}]
                    }
                ],
                ischeckAll:false,//
                setDistributorDailog:false,
                cancelDistributorDailog:false,
                distributorForm:{
                    vendorName:'',
                    senderName:''
                },
                indeterminate:false,
                rules: {
                    senderName: [{ required: true, message: '字段不能为空',trigger: 'blur'}],
                    website: [{ required: true, message: '字段不能为空',trigger: 'blur'}],
                },
            }
        },
        computed: {
        },
        methods: {
            handleCheckAllChange(e){//一级change事件
                this.ischeckAll = e
                this.indeterminate = false
                for(var i=0,len=this.distributorsInfo.length; i<len; i++){ //二级全选反选
                    this.distributorsInfo[i].selected = e
                    this.distributorsInfo[i].indeterminate = false //去掉二级不确定状态
                    for(var j=0,len1=this.distributorsInfo[i].country.length; j<len1; j++){//三级全选反选
                        this.distributorsInfo[i].country[j].selected = e
                    }
                }
            },
            handleCheckedCountryAllChange(index, topId, e){//二级change事件
                this.distributorsInfo[index].selected = e//二级勾选后,子级全部勾选或者取消
                this.distributorsInfo[index].indeterminate = false //去掉二级不确定状态
                var childrenArray = this.distributorsInfo[index].country
                if(childrenArray)
                    for(var i=0,len=childrenArray.length; i<len; i++)
                        childrenArray[i].selected = e
 
                this.getIsCheckAll()
            },
            handleCheckedCountryChange(topIndex, sonId, topId, e){//三级change事件
                var childrenArray = this.distributorsInfo[topIndex].country
                var tickCount = 0, unTickCount = 0, len = childrenArray.length
                for(var i = 0; i < len; i++){
                    if(sonId == childrenArray[i].id) childrenArray[i].selected = e
                    if(childrenArray[i].selected == true) tickCount++
                    if(childrenArray[i].selected == false) unTickCount++
                }
                if(tickCount == len) {//三级级全勾选
                    this.distributorsInfo[topIndex].selected = true 
                    this.distributorsInfo[topIndex].indeterminate = false
                } else if(unTickCount == len) {//三级级全不勾选
                    this.distributorsInfo[topIndex].selected = false 
                    this.distributorsInfo[topIndex].indeterminate = false
                } else {
                    this.distributorsInfo[topIndex].selected = false
                    this.distributorsInfo[topIndex].indeterminate = true //添加二级不确定状态
                }
 
                this.getIsCheckAll()
            },
            getIsCheckAll(){
                var tickCount = 0, unTickCount = 0, indeterminateCount = 0,ArrLength = this.distributorsInfo.length
                for(var j=0; j<ArrLength; j++){//全选checkbox状态
                    if(this.distributorsInfo[j].selected == true) tickCount++
                    if(this.distributorsInfo[j].selected == false) unTickCount++
                    if(this.distributorsInfo[j].indeterminate == true) indeterminateCount++
                }
                if(tickCount == ArrLength) {//二级全勾选
                    this.ischeckAll = true
                    this.indeterminate = false
                } else if(unTickCount == ArrLength) {//二级全不勾选
                    this.ischeckAll = false
                    if(indeterminateCount>0){
                        this.indeterminate = true
                    }else{
                        this.indeterminate = false
                    }
                } else {
                    this.ischeckAll = false
                    this.indeterminate = true //添加一级不确定状态
                }
            },
 
            showSetDistributorDailog(){
                this.setDistributorDailog=true
            },
            showCancelDistributorDailog(){
                this.cancelDistributorDailog=true
            }
        },
        created: function() {
        },
        mounted: function() {
            // (async() => {
        },
        watch: {
        }
    }
</script>
<style lang="scss">
.deliverySetting{
    padding: 20px 0;
    position: relative;
    .el-table{
        thead{
            tr{
                th{
                    font-size: 14px;
                }
            }
        }
        tbody{
            tr{
                td{
                    vertical-align: baseline;
                    p{
                        line-height: 30px;
                    }
                    .el-checkbox-group{
                        display: flex;
                        flex-direction: column;
                        label{
                            line-height: 30px;
                            margin-left: 0;
                        }
                    }
                }
            }
        }
    }
    .deliverySetting-table{
        font-size: 14px;
        color: #333;
        .table-head,
        .table-body{
            display: flex;
            padding: 10px 0;
            .selection{
                width: 45px;
                text-align: center;
                line-height: 36px;
            }
            .width185{
                width: 185px;
            }
            .width265{
                width: 265px;
            }
        }
        .table-head{
            height: 36px;
            align-items: center;
            background-color: #E7F2FF;
        }
        .table-body{
            border-bottom: 1px solid #e4e4e4;
            color: #666;
            &:hover{
                background-color: #f5f7fa;
            }
            .width265{
                display: flex;
                flex-direction: column;
                label{
                    line-height: 30px;
                    margin-left: 0;
                    color: #666;
                }
            }
            p{
                line-height: 30px;
            }
        }
    }
    .deliverySetting-btn{
        /* 100%;*/
        height: 59px;
        display: flex;
        justify-content: flex-end;
        align-items: center;
        position: absolute;
        top: -55px;
        right: -16px;
        z-index: 100;
        .tabs-btn {
            min-width: 90px;
            height: 34px;
            line-height: 32px;
            padding: 0 10px;
            color: #2387f7;
            border: solid 1px #4fa2ff;
            background-color: #e7f2ff;
            cursor: pointer;
            &:nth-of-type(2) {
                margin: 0 15px;
            }
            input {
                border: none;
                background: transparent;
                color: inherit;
                cursor: inherit;
                outline: none;
                margin: 0;
                padding: 0;
            }
            &:hover {
                color: #fff;
                background-color: #2387f7;
            }
        }
    }
    .setDistributorDailog{
        .el-input{
            width: 270px;
        }
    }
}
</style>
原文地址:https://www.cnblogs.com/lst619247/p/10879459.html