In fact, the built-in checkbox and checkbox group in the uniapp are good, but there are two problems:
- Cannot rely on its events to select all
- The style is fixed and difficult to modify
The reasons why they could not achieve full election were:
When I dynamically modify the checked field of the checkbox, the status on the interface can change in real time, but the change event of the checkbox group cannot be triggered. This means that you cannot rely on the checkbox group to manage the selected items.
That is to say: I click Select all, and it looks like select all on the interface. Then I cancel one of the options, and the change event is triggered, but the selected list it feeds back to me is wrong. It won't work.
So I came up with a scheme to realize select all and select multiple boxes.
Realization idea
In view of the above problems, I can give up the checkbox group. Then, I give up the checkbox by the way, because I prefer the circle style of radio.
First, simulate and generate some data to facilitate display. The key point of data is to have a field selected, and others do whatever they want:
<script setup lang="ts"> import { reactive } from "vue"; // The simulated data object should be responsive let data = reactive([] as { id: number; text: string; selected: boolean }[]); // Generate data for (let i = 0; i < 20; i++) { data.push({ id: i + 5, text: "title" + i, selected: false, }); } </script>
Then we need to have an object to store the selected data information, using map:
// Store the selected content. Because the list is frequently added and deleted, map is selected instead of array, and key corresponds to the subscript of data. As for what to store, it's entirely up to you let selected = reactive(new Map<number, number>());
Then we have to have a click time to select data or deselect:
// Click the event in the option box, and the parameter is the subscript of the data function checkbox(index: number) { // Click again in the selected state to cancel the selection if (data[index].selected) { data[index].selected = false; selected.delete(index); // Then delete the corresponding key } // Click when not selected else { data[index].selected = true; selected.set(index, data[index].id); } }
Then, we have to have a click event of select all:
// Select all and deselect events function allSelect() { // If you have selected all, it is the reverse selection. If you select all, it means that the length is the same if (selected.size === data.length) { selected.clear(); // Clear all data.forEach((element) => { element.selected = false; // Just don't choose all of them }); } // In the state of not selecting all else { data.forEach((element, index) => { // Because the possible parts have been selected, you must first judge whether they exist or not before adding them if (!selected.has(index)) { selected.set(index, element.id); // key is the corresponding subscript index, while value can be customized element.selected = true; // Set as selected } }); } }
In fact, the above two click events are very basic judgment, addition and deletion data. So far, all functions are available. Let's see how to write on the page:
<template> <!-- It's a multiple choice list --> <view v-for="(item, index) in data"> <label style="margin-left: 50px"> <radio :value="String(index)" :checked="item.selected" @click="checkbox(index)" />{{ item.text }} </label> </view> <!-- Select all button --> <label> <radio value="1" :checked="selected.size === data.length" @click="allSelect" />Select all</label> </template>
In fact, there are two groups of radio s, one is to display data circularly, and the other is to select all button.
Connected complete code:
<template> <!-- It's a multiple choice list --> <view v-for="(item, index) in data"> <label style="margin-left: 50px"> <radio :value="String(index)" :checked="item.selected" @click="checkbox(index)" />{{ item.text }} </label> </view> <!-- Select all button --> <label> <radio value="1" :checked="selected.size === data.length" @click="allSelect" />Select all</label> </template> <script setup lang="ts"> import { reactive } from "vue"; // The simulated data object should be responsive let data = reactive([] as { id: number; text: string; selected: boolean }[]); // Generate data for (let i = 0; i < 20; i++) { data.push({ id: i + 5, text: "title" + i, selected: false, }); } // Store the selected content. Because the list is frequently added and deleted, map is selected instead of array, and key corresponds to the subscript of data. As for what to store, it's entirely up to you let selected = reactive(new Map<number, number>()); // Select all and deselect events function allSelect() { // If you have selected all, it is the reverse selection. If you select all, it means that the length is the same if (selected.size === data.length) { selected.clear(); // Clear all data.forEach((element) => { element.selected = false; // Just don't choose all of them }); } // In the state of not selecting all else { data.forEach((element, index) => { // Because the possible parts have been selected, you must first judge whether they exist or not before adding them if (!selected.has(index)) { selected.set(index, element.id); // key is the corresponding subscript index, while value can be customized element.selected = true; // Set as selected } }); } } // Click the event in the option box, and the parameter is the subscript of the data function checkbox(index: number) { // Click again in the selected state to cancel the selection if (data[index].selected) { data[index].selected = false; selected.delete(index); // Then delete the corresponding key } // Click when not selected else { data[index].selected = true; selected.set(index, data[index].id); } } </script> <style></style>
It seems that there are many codes, but they are actually very basic logical judgments.
The final effect is as follows:
Select all:
Multiple choices:
Invert all: