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