Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default class Cascader {
private query;
private queryAll;
private getSiblings;
private isPrefixPath;
private menusShow;
private menusHide;
private calculateElementWidth;
Expand All @@ -37,8 +38,8 @@ export default class Cascader {
constructor(container: string, options: CascaderOptions);
init(): void;
setValue(value?: any[]): void;
get value(): any[];
get value(): any;
get labelValue(): any;
get indexValue(): any;
get indexValue(): any[];
}
export type CascaderInstance = InstanceType<typeof Cascader>;
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default class Cascader {
private query;
private queryAll;
private getSiblings;
private isPrefixPath;
private menusShow;
private menusHide;
private calculateElementWidth;
Expand All @@ -37,8 +38,8 @@ export default class Cascader {
constructor(container: string, options: CascaderOptions);
init(): void;
setValue(value?: any[]): void;
get value(): any[];
get value(): any;
get labelValue(): any;
get indexValue(): any;
get indexValue(): any[];
}
export type CascaderInstance = InstanceType<typeof Cascader>;
2 changes: 1 addition & 1 deletion index.js

Large diffs are not rendered by default.

182 changes: 96 additions & 86 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,15 @@ export default class Cascader {

return siblings;
}
private isPrefixPath(prefix: number[], path: number[]): boolean {
if (prefix.length > path.length) return false;
return prefix.every((v, i) => v === path[i]);
}
private menusShow() {
const { mode = "single" } = this.options;

if (mode !== "multiple") {
this.setValue(this.valValue);
this.setValue(this.value);
}

this.query(`.cascader-container_${this.uuid}`, true)?.classList.add("cascader-container_active");
Expand Down Expand Up @@ -179,8 +183,8 @@ export default class Cascader {
private renderValue(value: any[] = []) {
const { displayRender, mode = "single", placeholder = "" } = this.options;

const fullItemTagValue = [];
const checkedItemTagValue = [];
const fullItemTagValue: number[][] = [];
const checkedItemTagValue: number[][] = [];

if (mode === "multiple") {
const allItem = this.queryAll(".cascader-container_menus_menu_item") ?? [];
Expand All @@ -191,55 +195,52 @@ export default class Cascader {
}

for (let index = 0; index < this.valValue.length; index++) {
const element = this.valValue[index];
const element = this.valValue[index] as number[];
const item = this.query(`.cascader-container_menus_menu_item[data-tag="${element.join(this.splitStr)}"]`);
item?.classList.add("cascader-container_menus_menu_item_full");

for (let index = 0; index < element.length - 1; index++) {
const parentValue = element.slice(0, element.length - 1 - index);
const parentPath = element.slice(0, element.length - 1 - index) as number[];

if (checkedItemTagValue.map((ele) => ele.join(this.splitStr)).indexOf(parentValue.join(this.splitStr)) !== -1) {
if (checkedItemTagValue.map((ele) => ele.join(this.splitStr)).indexOf(parentPath.join(this.splitStr)) !== -1) {
continue;
}

const parentChild = this.getNextLevelData(parentValue);
const parentChild = this.getNextLevelData(parentPath);

const recursion = (data: CascaderOptionsData, tag: string[]) => {
const { value, children } = data ?? {};
const recursion = (data: CascaderOptionsData, tag: number[]): boolean => {
const { children } = data ?? {};

if (children) {
if (children && children.length > 0) {
let fullCount = 0;

for (let index = 0; index < children.length; index++) {
if (recursion(children[index], [...tag, value])) {
for (let i = 0; i < children.length; i++) {
if (recursion(children[i], [...tag, i])) {
fullCount++;
}
}

return fullCount === children.length;
}

return this.valValue.findIndex((ele) => ele.join(this.splitStr) === `${tag.join(this.splitStr)}${this.splitStr}${value}`) !== -1;
return this.valValue.findIndex((ele: number[]) => ele.join(this.splitStr) === tag.join(this.splitStr)) !== -1;
};

const fullCount = parentChild.reduce((acc, cur) => {
if (recursion(cur, parentValue)) {
return acc + 1;
let fullCount = 0;
for (let i = 0; i < parentChild.length; i++) {
if (recursion(parentChild[i], [...parentPath, i])) {
fullCount++;
}
}

return acc;
}, 0);

const parentItem = this.query(`.cascader-container_menus_menu_item[data-tag="${parentValue.join(this.splitStr)}"]`);
const parentItem = this.query(`.cascader-container_menus_menu_item[data-tag="${parentPath.join(this.splitStr)}"]`);

if (fullCount === parentChild.length) {
parentItem?.classList.add("cascader-container_menus_menu_item_full");
fullItemTagValue.push(parentValue);
fullItemTagValue.push(parentPath);
} else {
parentItem?.classList.add("cascader-container_menus_menu_item_half");
}

checkedItemTagValue.push(parentValue);
checkedItemTagValue.push(parentPath);
}
}
}
Expand Down Expand Up @@ -270,10 +271,10 @@ export default class Cascader {
const labelArr: any[] = [];

for (let index = 0; index < value.length; index++) {
const element = value[index];
const element = value[index] as number[];
let label = labelValue[index];

if (fullItemTagValue.filter((ele) => ele.length === 1).find((ele) => element.join(this.splitStr).indexOf(ele.join("")) !== -1)) {
if (fullItemTagValue.filter((ele: number[]) => ele.length === 1).find((ele: number[]) => this.isPrefixPath(ele, element))) {
label = label.slice(0, 1);
}

Expand Down Expand Up @@ -309,33 +310,32 @@ export default class Cascader {
}
}
}
private getNextLevelData(value: string[] = []) {
private getNextLevelData(indexPath: number[] = []) {
const { data = [] } = this.options;

return value.reduce((acc, cur) => {
return acc.find((ele) => ele.value === cur)?.children ?? [];
}, data);
return indexPath.reduce((acc: CascaderOptionsData[], cur) => {
return acc[cur]?.children ?? [];
}, data as CascaderOptionsData[]);
}
private transformValue(type: "getValue" | "getLabelValue" | "getIndexValue", value: any[] = []) {
const { data = [], mode = "single" } = this.options;

const getValue = (values: any[]) => {
const getValue = (values: number[]) => {
const result: any = [];

let treeData: CascaderOptionsData[] = [...data];
for (let index = 0; index < values.length; index++) {
const element = values[index];
for (let i = 0; i < values.length; i++) {
const idx = values[i];

if (type === "getValue") {
result.push(treeData[element]?.value);
treeData = treeData[element]?.children ?? [];
result.push(treeData[idx]?.value);
treeData = treeData[idx]?.children ?? [];
} else if (type === "getLabelValue") {
const target = treeData.find((ele) => ele.value === element);
result.push(target?.label);
treeData = target?.children ?? [];
result.push(treeData[idx]?.label);
treeData = treeData[idx]?.children ?? [];
} else if (type === "getIndexValue") {
result.push(treeData.findIndex((ele) => ele.value === element));
treeData = treeData.find((ele) => ele.value === element)?.children ?? [];
result.push(idx);
treeData = treeData[idx]?.children ?? [];
}
}

Expand Down Expand Up @@ -365,7 +365,7 @@ export default class Cascader {

const otherClass = `${className ? ` ${className}` : ""}${disabled ? " cascader-container_menus_menu_item_disabled" : ""}`;

const tagStr = tag ? `${tag}${this.splitStr}${value}` : value;
const tagStr = tag ? `${tag}${this.splitStr}${index}` : String(index);

const multipleisDisabled = disabled ? "cascader-container_menus_menu_item_multiple_disabled" : "";

Expand Down Expand Up @@ -433,38 +433,38 @@ export default class Cascader {

if (currentItem) {
const currentItemTag = currentItem.dataset.tag ?? "";
const currentValue = currentItemTag.split(this.splitStr);
const nextLevelData = this.getNextLevelData(currentValue);
const currentIndexPath = currentItemTag.split(this.splitStr).map(Number);
const nextLevelData = this.getNextLevelData(currentIndexPath);

const currentMultipleItem = target.closest(
".cascader-container_menus_menu_item_multiple:not(.cascader-container_menus_menu_item_multiple_disabled)",
) as HTMLElement;

if (currentMultipleItem && nextLevelData.length !== 0) {
this.valValue = [...this.valValue.filter((ele) => ele.join(this.splitStr).indexOf(currentItemTag) === -1)];
this.valValue = [...this.valValue.filter((ele: number[]) => !this.isPrefixPath(currentIndexPath, ele))];

if (!currentItem.classList.contains("cascader-container_menus_menu_item_full")) {
const recursion = (data: CascaderOptionsData, values: string[]) => {
const { value, children } = data ?? {};
const recursion = (data: CascaderOptionsData, values: number[]): number[][] => {
const { children } = data ?? {};

if (children) {
const arr: string[][] = [];
if (children && children.length > 0) {
const arr: number[][] = [];

for (let index = 0; index < children.length; index++) {
arr.push(...recursion(children[index], [...values, value]));
for (let i = 0; i < children.length; i++) {
arr.push(...recursion(children[i], [...values, i]));
}

return arr;
}

return [[...values, value]];
return [values];
};

const valueArr: any[] = [];
const valueArr: number[][] = [];

for (let index = 0; index < nextLevelData.length; index++) {
const element = nextLevelData[index];
valueArr.push(...recursion(element, currentValue));
valueArr.push(...recursion(element, [...currentIndexPath, index]));
}

this.valValue = [...this.valValue, ...valueArr];
Expand All @@ -474,14 +474,14 @@ export default class Cascader {

if (nextLevelData.length === 0) {
if (mode === "multiple") {
if (this.valValue.map((ele) => ele.join(this.splitStr)).indexOf(currentValue.join(this.splitStr)) !== -1) {
const index = this.valValue.map((ele) => ele.join(this.splitStr)).findIndex((ele) => ele === currentValue.join(this.splitStr));
this.valValue.splice(index, 1);
const existingIdx = this.valValue.findIndex((ele: number[]) => ele.join(this.splitStr) === currentIndexPath.join(this.splitStr));
if (existingIdx !== -1) {
this.valValue.splice(existingIdx, 1);
} else {
this.valValue.push(currentValue);
this.valValue.push(currentIndexPath);
}
} else {
this.valValue = [...currentValue];
this.valValue = [...currentIndexPath];
this.menusHide();
}
} else {
Expand All @@ -491,7 +491,7 @@ export default class Cascader {
}

this.renderValue(this.valValue);
this.options.onChange?.(this.valValue, this.transformValue("getLabelValue", this.valValue), this.transformValue("getIndexValue", this.valValue));
this.options.onChange?.(this.transformValue("getValue", this.valValue), this.transformValue("getLabelValue", this.valValue), this.valValue);
}
}
};
Expand Down Expand Up @@ -577,67 +577,77 @@ export default class Cascader {
}
this.createMenu(data);

const getValue = (value: any[]) => {
let valueArr: any[] = [];
const toIndexPath = (val: any[]): number[] => {
if (val.every((item) => typeof item === "number")) {
return [...val];
}

if (value.every((item) => typeof item === "string") || value.every((item) => typeof item === "number")) {
if (value.every((item) => typeof item === "number")) {
valueArr = [...this.transformValue("getValue", value)];
} else {
valueArr = [...value];
if (val.every((item) => typeof item === "string")) {
const result: number[] = [];
let treeData: CascaderOptionsData[] = data;
for (const v of val) {
const idx = treeData.findIndex((ele) => ele.value === v);
if (idx === -1) break;
result.push(idx);
treeData = treeData[idx]?.children ?? [];
}
return result;
}

for (let index = 0; index < valueArr.length; index++) {
const levelValue = valueArr.slice(0, index + 1);
const tagStr = levelValue.join(this.splitStr);
const currentItem = this.query(`.cascader-container_menus_menu_item[data-tag="${tagStr}"]`);
const nextLevelData = this.getNextLevelData(levelValue);
return [];
};

if (nextLevelData.length !== 0) {
const menu = this.query(`.cascader-container_menus_menu[data-level="${index + 1}"]`);
const applyIndexPath = (indexPath: number[]) => {
for (let index = 0; index < indexPath.length; index++) {
const levelIndices = indexPath.slice(0, index + 1);
const tagStr = levelIndices.join(this.splitStr);
const currentItem = this.query(`.cascader-container_menus_menu_item[data-tag="${tagStr}"]`);
const nextLevelData = this.getNextLevelData(levelIndices);

if (menu) {
this.query(`.cascader-container_menus`)?.removeChild(menu);
}
if (nextLevelData.length !== 0) {
const menu = this.query(`.cascader-container_menus_menu[data-level="${index + 1}"]`);

this.createMenu(nextLevelData, index + 1, tagStr);
if (menu) {
this.query(`.cascader-container_menus`)?.removeChild(menu);
}

if (mode !== "multiple") {
currentItem?.classList.add("cascader-container_menus_menu_item_active");
}
this.createMenu(nextLevelData, index + 1, tagStr);
}

if (mode !== "multiple") {
currentItem?.classList.add("cascader-container_menus_menu_item_active");
}
}

return valueArr;
return indexPath;
};

if (mode === "multiple") {
const valueArr = [];
const valueArr: number[][] = [];

for (let index = 0; index < value.length; index++) {
const element = value[index];
valueArr.push(getValue(element));
valueArr.push(applyIndexPath(toIndexPath(element)));
}

this.valValue = [...valueArr];
} else {
this.valValue = [...getValue(value)];
this.valValue = [...applyIndexPath(toIndexPath(value))];
}

this.renderValue(this.valValue);
}

get value() {
return this.valValue;
return this.transformValue("getValue", this.valValue);
}

get labelValue() {
return this.transformValue("getLabelValue", this.valValue);
}

get indexValue() {
return this.transformValue("getIndexValue", this.valValue);
return this.valValue;
}
}

Expand Down