Because I just started to get involved in vue, the implementation of all selected references to the implementation method on Zhihu:
1. Get data from the server and set the checked attribute for each item
2. Calculate the selected quantity selectCount. If the selected quantity is equal to the number of selectItems, select all selectAll
3. When selecting all, set the checked attribute of each item to true, and when selecting inversely, set it to false.
4. Every time the property of selectItems changes, the checked item is placed in the array checkedGroups.
The following is the implementation code:
//Select all data: function() { return { selectItems: [], // Data obtained from the server} }, computed: { // Select all model bound to checkbox selectAll: { get: function() { return this.selectCount == this.selectItems.length; }, set: function(value) { this.selectItems.forEach(function(item) { item.checked = value; }); return value; } }, //The selected quantity selectCount: { get: function() { var i = 0; this.selectItems.forEach(function(item) { if (item.checked) { i++; } }); return i; } }, //The selected array checkedGroups: { get: function() { var checkedGroups = []; this.selectItems.forEach(function(item) { if (item.checked) { checkedGroups.push(item); } }); return checkedGroups; } } }This method is not very convenient to use. First of all, it is difficult to reuse. Every time you want to use it, you need to write computed. Secondly, selectAll, checkedGroups, and selectItems are all fixed and not very flexible.
So in this project, I used the vue instruction to re-implement the function of selecting all. The idea of directive is actually similar to that of computed. Let's start with the code:
export default { 'check-all': { twoWay: true, params: ['checkData'], bind() { /** - If the checked attribute of all lists is true, select the check all box, otherwise the checkbox is not selected */ this.vm.$watch(this.params.checkData, (checkData) => { if (checkData.every((item) => item.checked)) { this.set(true); } else { this.set(false); } }, { deep: true }); }, // update(checkAll) when checkAll changes { /** - If the check all box is selected, all checked properties of the list are converted to true, otherwise they are converted to false */ if (checkAll) { this.vm[this.params.checkData].forEach((item) => { item.checked = true; }); } else { this.vm[this.params.checkData].forEach((item) => { item.checked = false; }); } }, },};Called:
<input type="checkbox" v-model="checkAll" v-check-all="checkAll" check-data="checkData"> <ul> <li v-for="item in checkData"> <input type="checkbox" v-model="item.checked"> {{item.text}} </li> </ul>Let’s talk about the advantages of using this:
1. Easy to use. Just write v-check-all command and check-data where needed.
2. The selected model and array names can be customized, and any name can be used. If you don’t want to call checkAll and checkAllData, you can also call arrays and checkData dataFromServer.
In the instruction, specify twoWay to true, you can use this.set(value) to set the value of checkAll, and use params to receive the property value checkData on the binding instruction element, which is the array to operate.
Use this.vm to get the context of the usage directive, call $watch of the context to listen for the changes in checkData. If all checkData is selected, set checkAll to true, otherwise set checkAll to false.
When the instruction value (checkAll) changes, if true, set the checked attribute of checkData to true, otherwise it is false. At this point, a selected command is completed.
When doing this selection all instruction, I originally wanted to use paramWatchers to listen for checkData changes, but I found that when checkData changes, the callback of paramWatchers will not be triggered. Later, I looked at the source code and found that paramWatchers actually called $watch , but it does not support deep detection:
Directive.prototype._setupParamWatcher = function (key, expression) { var self = this; var called = false; var unwatch = (this._scope || this.vm).$watch(expression, function (val, oldVal) { self.params[key] = val; // since we are in immediate mode, // only call the param change callbacks if this is not the first update. if (called) { var cb = self.paramWatchers && self.paramWatchers[key]; if (cb) { cb.call(self, val, oldVal); } } else { called = true; } }, { immediate: true, user: false });(this._paramUnwatchFns || (this._paramUnwatchFns = [])).push(unwatch);};Summarize
The above is the entire content of this article. If there is something wrong, please give me some advice. I hope the content of this article will be helpful to everyone.