ie-dropdown-hooks.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import type { Dropdown } from "@/types";
  2. import type { InjectionKey } from "vue";
  3. export const DROPDOWN_SYMBOL = Symbol('DROPDOWN_SYMBOL') as InjectionKey<ReturnType<typeof useDropdown>>;
  4. /**
  5. * 深拷贝一个值
  6. * @param value 要拷贝的值
  7. * @returns 深拷贝后的值
  8. */
  9. const deepClone = (value: any): any => {
  10. // 如果是基本类型或 null/undefined,直接返回
  11. if (value == null || typeof value !== 'object') {
  12. return value;
  13. }
  14. // 如果是数组,递归拷贝每个元素
  15. if (Array.isArray(value)) {
  16. return value.map(item => deepClone(item));
  17. }
  18. // 如果是对象,递归拷贝所有属性
  19. const cloned: Record<string, any> = {};
  20. for (const key in value) {
  21. if (Object.prototype.hasOwnProperty.call(value, key)) {
  22. cloned[key] = deepClone(value[key]);
  23. }
  24. }
  25. return cloned;
  26. };
  27. /**
  28. * 深度比较两个值是否严格相等
  29. * @param a 第一个值
  30. * @param b 第二个值
  31. * @returns 是否相等
  32. */
  33. const deepEqual = (a: any, b: any): boolean => {
  34. // 如果引用相同,直接返回 true
  35. if (a === b) return true;
  36. // 如果其中一个为 null 或 undefined
  37. if (a == null || b == null) return a === b;
  38. // 如果类型不同,返回 false
  39. if (typeof a !== typeof b) return false;
  40. // 如果是基本类型(非对象),直接比较
  41. if (typeof a !== 'object') return a === b;
  42. // 如果是数组
  43. if (Array.isArray(a) && Array.isArray(b)) {
  44. if (a.length !== b.length) return false;
  45. return a.every((item, index) => deepEqual(item, b[index]));
  46. }
  47. // 如果一个是数组,另一个不是,返回 false
  48. if (Array.isArray(a) || Array.isArray(b)) return false;
  49. // 如果是对象,比较所有键值对
  50. const keysA = Object.keys(a);
  51. const keysB = Object.keys(b);
  52. // 键的数量不同,返回 false
  53. if (keysA.length !== keysB.length) return false;
  54. // 检查所有键是否都存在且值相等
  55. for (const key of keysA) {
  56. if (!keysB.includes(key)) return false;
  57. if (!deepEqual(a[key], b[key])) return false;
  58. }
  59. return true;
  60. };
  61. export const useDropdown = (configs: Dropdown.DropdownItem[]) => {
  62. const list = computed(() => configs);
  63. const form = ref<Record<string, any>>({});
  64. const openIndex = ref<number>(-1);
  65. const open = (index: number) => {
  66. openIndex.value = index;
  67. }
  68. const close = () => {
  69. openIndex.value = -1;
  70. }
  71. const submit = (index: number, value: any) => {
  72. form.value = {
  73. ...form.value,
  74. [list.value[index].prop]: value
  75. };
  76. }
  77. const reset = (index: number) => {
  78. form.value = {
  79. ...form.value,
  80. [list.value[index].prop]: list.value[index].value
  81. };
  82. }
  83. const init = (initValue: Record<string, any>) => {
  84. form.value = { ...initValue };
  85. list.value.forEach(item => {
  86. item.value = initValue[item.prop] || item.value;
  87. });
  88. }
  89. return {
  90. init,
  91. form,
  92. openIndex,
  93. open,
  94. close,
  95. submit,
  96. reset,
  97. deepEqual,
  98. deepClone
  99. }
  100. }