自定义单选、多选组件(vue)

  • Post author:
  • Post category:vue




效果演示:


在这里插入图片描述



一、组件:


组件内部实现支持多选、单选能力;多选情况支持全选、反选、清空。


思路:

1、数据:

selectedArr 存储当前选中的数据。

单选:如果selectedArr[0] 等于当前选择数据,清空selectedArr ,否则赋值给 selectedArr[0] 。数组长度为0或1

多选:当前选择数据不在selectedArr 中,则push,否则splice。

2、样式:动态绑定样式,数组selectedArr中含有当前元素,则添加选中样式。


组件完整代码:

<template>

    <div class="cmp-container">
        <div v-if="data.length>0">
            <!--支持多选-->
            <div class="btn-wrapper" v-if="type ==='multiple'">
                <span class="title-text" @click="selectedAll()">
                    全选
                </span
                >
                <span class="title-text" @click="toggle()">
                    反选
                </span>
                <span class="title-text" @click="cancelSelect()">
                    清空
                </span>
            </div>

            <div class="grid">
            <span v-for="(item,index) in data"
                  :key="index"
                  class="grid-item"
                  @click="select(index)"
                  :class="{'span-active':selectedArr.indexOf(index) !==-1}"
            >
                {{ item.text }}
            </span>
            </div>

        </div>
        <div v-else>
            <span> 暂无数据 </span>
        </div>

    </div>


</template>

<script>
export default {
    components: {},
    props: {
        data: {
            type: Array,
            default: () => {
                return [];
            }
        },
        selected: {
            type: Array,
            default: () => {
                return [];
            }
        },
        type: {
            type: String,
            default: "single"   //single单选   multiple 多选
        }

    },
    data() {
        return {
            selectedArr: []
        };
    },
    watch: {
        selectedArr: {
            handler(val) {
                let arr = [];
                let textArr =[];
                val.forEach((el) => {
                    arr.push(this.data[el].value);
                    textArr.push(this.data[el].text);
                });
                this.$emit("update", arr,textArr);
            },
            deep: true
        }
    },
    computed: {},
    mounted() {
    },
    methods: {
        select(index) {
            if (this.type === "single") {//单选
                if (this.selectedArr[0] !== index) {
                    this.selectedArr = [];
                    this.selectedArr.push(index);
                } else {
                    this.selectedArr = [];
                }
            } else { //可多选
                let searchIndex = this.selectedArr.indexOf(index);
                if (searchIndex === -1) {
                    this.selectedArr.push(index);
                } else {
                    this.selectedArr.splice(searchIndex, 1);
                }
            }
        },
        /**
         * 全选
         */
        selectedAll() {
            this.selectedArr = Array(this.data.length).fill(null).map((_, index) => index);
        },
        /**
         * 反选
         */
        toggle() {
            let arr = Array(this.data.length).fill(null).map((_, index) => index);
            this.selectedArr = arr.filter((_item, _index, _arr) => {
                return this.selectedArr.indexOf(_item) === -1;
            });
        },
        /**
         * 清空选择
         */
        cancelSelect() {
            this.selectedArr = [];
        }
    }

};

</script>
<style lang="less" scoped>
@import url("~@/assets/style/common.less");

.cmp-container {
    background: white;
}

.btn-wrapper {
    padding-top: 10px;
}

.select-btn {
    color: blueviolet;
    font-size: 14px;
    padding: 10px;
}

.grid {
    display: flex;
    flex-wrap: wrap;
    padding: 10px;
}

.grid-item {
    margin: 8px 4px;
    padding: 10px 5px;
    border-radius: 16px;
    display: block;
    text-align: center;
    box-sizing: border-box;
    width: 30%;
    font-size: 10px;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
    background: rgba(0, 0, 0, 0.05);
    cursor: pointer;
}

.span-active {
    color: white;
    background: rgba(138, 43, 226, 0.7);
}

.title-text{
    color: #576b95;
    padding: 5px;
    cursor: pointer;
}

</style>



二、页面中引用:



完整代码:

<template>
    <div class="selected-paged">
        <div style="width: 400px">
            <span class="selected-text">当前选中:</span>
            <span class="selected-content">{{ singleSelected }}</span>
            <label-selector :data="selectList" type="single" @update="updateSingle"></label-selector>
        </div>

        <div style="margin-top: 40px;width: 400px">
            <span class="selected-text">当前选中:</span>
            <span class="selected-content">{{ multipleSelected }}</span>
            <label-selector :data="selectList" type="multiple" @update="updateMultiple"></label-selector>
        </div>

    </div>
</template>

<script>
import LabelSelector from "@/components/LabelSelector";

export default {
    name: "",
    components: {
        LabelSelector
    },
    data() {
        return {
            selectList: [
                { text: "飞机", value: "01" },
                { text: "火车", value: "02" },
                { text: "大巴", value: "03" },
                { text: "高铁", value: "04" },
                { text: "出租车", value: "05" },
                { text: "自行车", value: "05" },
                { text: "火箭", value: "07" },
                { text: "潜艇", value: "08" },
                { text: "航空母舰", value: "08" },
                { text: "游轮", value: "09" }
            ],
            singleSelected: "",
            multipleSelected: ""

        };
    },
    created() {
    },
    mounted() {
    },
    methods: {
        updateSingle(valueArr,textArr) {
            this.singleSelected = textArr.toString();
        },
        updateMultiple(valueArr,textArr) {
            this.multipleSelected = textArr.toString();
        }
    }
};
</script>
<style lang='less' scoped>


.selected-text {
    font-size: 16px;
}
.selected-content{
    display: block;
    height: 30px;
}
</style>



总结:



每天记录一点,从小小菜鸟变小菜鸟!!!



版权声明:本文为King0217原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。