feat: tree-style Dropdown.
This commit is contained in:
+41
-40
@@ -104,6 +104,7 @@ function getValue(it, valuekey, textkey) {
|
|||||||
* @property {string} [textKey=text] - 文本关键字
|
* @property {string} [textKey=text] - 文本关键字
|
||||||
* @property {string} [valueKey=value] - 值关键字
|
* @property {string} [valueKey=value] - 值关键字
|
||||||
* @property {string} [htmlKey=html] - 源码显示的关键字
|
* @property {string} [htmlKey=html] - 源码显示的关键字
|
||||||
|
* @property {string} [childKey=children] - 子集合的关键字
|
||||||
* @property {Function} [htmlTemplate] - 模板创建函数
|
* @property {Function} [htmlTemplate] - 模板创建函数
|
||||||
* @property {number} [maxLength=500] - 最大输入长度
|
* @property {number} [maxLength=500] - 最大输入长度
|
||||||
* @property {boolean} [multiSelect] - 是否允许多选
|
* @property {boolean} [multiSelect] - 是否允许多选
|
||||||
@@ -144,6 +145,7 @@ export class Dropdown {
|
|||||||
options.textKey ??= 'text';
|
options.textKey ??= 'text';
|
||||||
options.valueKey ??= 'value';
|
options.valueKey ??= 'value';
|
||||||
options.htmlKey ??= 'html';
|
options.htmlKey ??= 'html';
|
||||||
|
options.childKey ??= 'children';
|
||||||
options.maxLength ??= 500;
|
options.maxLength ??= 500;
|
||||||
this._var.options = options;
|
this._var.options = options;
|
||||||
const getText = options.getText;
|
const getText = options.getText;
|
||||||
@@ -303,11 +305,16 @@ export class Dropdown {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const valuekey = this._var.options.valueKey;
|
const valuekey = this._var.options.valueKey;
|
||||||
|
const childkey = this._var.options.childKey;
|
||||||
function reduceItems(list, id, level = 0) {
|
function reduceItems(list, id, level = 0) {
|
||||||
if (!Array.isArray(list)) {
|
if (!Array.isArray(list)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return list.reduce((array, item) => [...array, { __p: id, __level: level, ...item }, ...reduceItems(item.children, item[valuekey], level + 1)], []);
|
return list.reduce((array, item) => [
|
||||||
|
...array,
|
||||||
|
(id == null ? item : { __p: String(id), __level: level, ...item }),
|
||||||
|
...reduceItems(item[childkey], item[valuekey], level + 1)
|
||||||
|
], []);
|
||||||
}
|
}
|
||||||
this._var.source = reduceItems(list);
|
this._var.source = reduceItems(list);
|
||||||
if (this._expanded) {
|
if (this._expanded) {
|
||||||
@@ -580,19 +587,18 @@ export class Dropdown {
|
|||||||
const multiselect = this.multiSelect;
|
const multiselect = this.multiSelect;
|
||||||
const valuekey = this._var.options.valueKey;
|
const valuekey = this._var.options.valueKey;
|
||||||
const textkey = this._var.options.textKey;
|
const textkey = this._var.options.textKey;
|
||||||
|
const childkey = this._var.options.childKey;
|
||||||
const allchecked = this._var.allChecked;
|
const allchecked = this._var.allChecked;
|
||||||
const selectedlist = this.selectedList;
|
const selectedlist = this.selectedList;
|
||||||
source.forEach((item, i) => {
|
source.forEach((item, i) => {
|
||||||
let val = getValue(item, valuekey, textkey);
|
const val = String(getValue(item, valuekey, textkey));
|
||||||
if (typeof val !== 'string') {
|
|
||||||
val = String(val);
|
|
||||||
}
|
|
||||||
if (multiselect) {
|
if (multiselect) {
|
||||||
const selected = selectedlist.some(s => String(getValue(s, valuekey, textkey)) === val);
|
const selected = selectedlist.some(s => String(getValue(s, valuekey, textkey)) === val);
|
||||||
if (allchecked || selected) {
|
if (allchecked || selected) {
|
||||||
item.__checked = 1;
|
item.__checked = 1;
|
||||||
|
source.filter(it => it.__p === val).forEach(it => it.__checked = 1);
|
||||||
} else {
|
} else {
|
||||||
const indeterminate = selectedlist.some(s => this._contains(String(getValue(s, valuekey, textkey)), item, valuekey, textkey));
|
const indeterminate = selectedlist.some(s => this._contains(String(getValue(s, valuekey, textkey)), item, valuekey, textkey, childkey));
|
||||||
if (indeterminate) {
|
if (indeterminate) {
|
||||||
item.__checked = 2;
|
item.__checked = 2;
|
||||||
}
|
}
|
||||||
@@ -609,10 +615,10 @@ export class Dropdown {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_contains(it, item, valuekey, textkey) {
|
_contains(it, item, valuekey, textkey, childkey) {
|
||||||
if (Array.isArray(item.children)) {
|
if (Array.isArray(item[childkey])) {
|
||||||
for (let t of item.children) {
|
for (let t of item[childkey]) {
|
||||||
if (it === getValue(t, valuekey, textkey)) {
|
if (it === String(getValue(t, valuekey, textkey))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this._contains(it, t, valuekey, textkey)) {
|
if (this._contains(it, t, valuekey, textkey)) {
|
||||||
@@ -629,34 +635,32 @@ export class Dropdown {
|
|||||||
const textkey = this._var.options.textKey;
|
const textkey = this._var.options.textKey;
|
||||||
const template = this._var.options.htmlTemplate;
|
const template = this._var.options.htmlTemplate;
|
||||||
const htmlkey = this._var.options.htmlKey;
|
const htmlkey = this._var.options.htmlKey;
|
||||||
|
const childkey = this._var.options.childKey;
|
||||||
const selected = this.selected;
|
const selected = this.selected;
|
||||||
let scrolled;
|
let scrolled;
|
||||||
array.forEach((item, i) => {
|
array.forEach((item, i) => {
|
||||||
let val = getValue(item, valuekey, textkey);
|
const val = String(getValue(item, valuekey, textkey));
|
||||||
if (typeof val !== 'string') {
|
|
||||||
val = String(val);
|
|
||||||
}
|
|
||||||
const li = createElement('li');
|
const li = createElement('li');
|
||||||
li.dataset.value = val;
|
li.dataset.value = val;
|
||||||
li.title = item[textkey];
|
li.title = item[textkey];
|
||||||
if (item.__level > 0) {
|
if (!isNaN(item.__level) && item.__level > 0) {
|
||||||
li.style.marginLeft = `${item.__level * 24}px`;
|
li.style.marginLeft = `${item.__level * 24}px`;
|
||||||
}
|
}
|
||||||
const wrapper = createElement('span', 'li-wrapper',
|
const wrapper = createElement('span', 'li-wrapper',
|
||||||
createElement('span', span => {
|
createElement('span', span => {
|
||||||
// events
|
// events
|
||||||
span.className = 'ui-expandor';
|
span.className = 'ui-expandor';
|
||||||
if (Array.isArray(item.children) && item.children.length > 0) {
|
// if (Array.isArray(item[childkey]) && item[childkey].length > 0) {
|
||||||
span.classList.add('active');
|
// span.classList.add('active');
|
||||||
function hideChildren(children) {
|
// function hideChildren(children) {
|
||||||
for (let c of children) {
|
// for (let c of children) {
|
||||||
c.__visible = false;
|
// c.__visible = false;
|
||||||
if (Array.isArray(c.children)) {
|
// if (Array.isArray(c[childkey])) {
|
||||||
hideChildren(c.children);
|
// hideChildren(c[childkey]);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
},
|
},
|
||||||
createIcon('fa-solid', 'caret-down')
|
createIcon('fa-solid', 'caret-down')
|
||||||
)
|
)
|
||||||
@@ -713,6 +717,7 @@ export class Dropdown {
|
|||||||
const textkey = this._var.options.textKey;
|
const textkey = this._var.options.textKey;
|
||||||
const template = this._var.options.htmlTemplate;
|
const template = this._var.options.htmlTemplate;
|
||||||
const htmlkey = this._var.options.htmlKey;
|
const htmlkey = this._var.options.htmlKey;
|
||||||
|
const childkey = this._var.options.childKey;
|
||||||
const source = this.source;
|
const source = this.source;
|
||||||
if (checkbox.getAttribute('isall') === '1') {
|
if (checkbox.getAttribute('isall') === '1') {
|
||||||
const allchecked = this._var.allChecked = checkbox.checked;
|
const allchecked = this._var.allChecked = checkbox.checked;
|
||||||
@@ -725,19 +730,15 @@ export class Dropdown {
|
|||||||
const val = checkbox.dataset.value;
|
const val = checkbox.dataset.value;
|
||||||
const getSelectedList = () => {
|
const getSelectedList = () => {
|
||||||
const list = [];
|
const list = [];
|
||||||
const cache = {};
|
|
||||||
source.filter(it => it.__p == null).forEach(it => {
|
source.filter(it => it.__p == null).forEach(it => {
|
||||||
|
const key = String(getValue(it, valuekey, textkey));
|
||||||
if (it.__checked === 1) {
|
if (it.__checked === 1) {
|
||||||
list.push(it);
|
list.push(it);
|
||||||
cache[getValue(it, valuekey, textkey)] = true;
|
} else if (it.__checked === 2) {
|
||||||
|
const children = source.filter(c => c.__checked === 1 && c.__p === key);
|
||||||
|
if (children.length > 0) {
|
||||||
|
Array.prototype.push.apply(list, children);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
source.filter(it => it.__p != null).forEach(it => {
|
|
||||||
if (cache[it.__p]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (it.__checked === 1) {
|
|
||||||
list.push(it);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return list;
|
return list;
|
||||||
@@ -746,15 +747,16 @@ export class Dropdown {
|
|||||||
item.__checked = 1;
|
item.__checked = 1;
|
||||||
if (item.__p != null) {
|
if (item.__p != null) {
|
||||||
// parent
|
// parent
|
||||||
if (!source.filter(it => it.__p === item.__p).some(it => it.__checked !== 1)) {
|
|
||||||
const parent = source.filter(it => String(getValue(it, valuekey, textkey)) === item.__p)[0];
|
const parent = source.filter(it => String(getValue(it, valuekey, textkey)) === item.__p)[0];
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
|
if (!source.filter(it => it.__p === item.__p).some(it => it.__checked !== 1)) {
|
||||||
parent.__checked = 1;
|
parent.__checked = 1;
|
||||||
|
} else if (parent.__checked !== 2) {
|
||||||
|
parent.__checked = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item.children?.length > 0) {
|
if (item[childkey]?.length > 0) {
|
||||||
// children
|
|
||||||
source.filter(it => it.__p === val).forEach(it => it.__checked = 1);
|
source.filter(it => it.__p === val).forEach(it => it.__checked = 1);
|
||||||
}
|
}
|
||||||
if (!source.some(it => it.__checked !== 1)) {
|
if (!source.some(it => it.__checked !== 1)) {
|
||||||
@@ -767,10 +769,9 @@ export class Dropdown {
|
|||||||
list = getSelectedList();
|
list = getSelectedList();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (item.children?.length > 0) {
|
if (item[childkey]?.length > 0) {
|
||||||
if (item.__checked === 2) {
|
if (item.__checked === 2) {
|
||||||
item.__checked = 0;
|
item.__checked = 0;
|
||||||
// children
|
|
||||||
source.filter(it => it.__p === val).forEach(it => it.__checked = 0);
|
source.filter(it => it.__p === val).forEach(it => it.__checked = 0);
|
||||||
} else {
|
} else {
|
||||||
item.__checked = 2;
|
item.__checked = 2;
|
||||||
|
|||||||
Reference in New Issue
Block a user