util.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import { reactive, watch } from "vue";
  2. import { Attrib, GetSetPick } from "../type";
  3. import { inRevise, toRawType } from "./public";
  4. import { Shape } from "konva/lib/Shape";
  5. import { Group } from "konva/lib/Group";
  6. export const setShapeConfig = <T extends Group | Shape>(
  7. shape: T,
  8. config: GetSetPick<T>
  9. ) => {
  10. for (const key in config) {
  11. if (typeof shape[key as any] === "function") {
  12. shape[key as any](config[key]);
  13. }
  14. }
  15. };
  16. export const getChangePart = <T>(newIds: T[], oldIds: T[] = []) => {
  17. const addPort = newIds.filter((newId) => !oldIds.includes(newId));
  18. const delPort = oldIds.filter((oldId) => !newIds.includes(oldId));
  19. const holdPort = oldIds.filter((oldId) => newIds.includes(oldId));
  20. return { addPort, delPort, holdPort };
  21. };
  22. export const getChangeAllPoart = <T extends Attrib>(
  23. newAttribs: T[],
  24. oldAttribs: T[]
  25. ) => {
  26. const newIds = newAttribs.map(({ id }) => id);
  27. const oldIds = oldAttribs.map(({ id }) => id);
  28. const ports = getChangePart(newIds, oldIds);
  29. // 数组子项引用变化
  30. const changePort = newAttribs
  31. .filter(
  32. (newAttrib) =>
  33. !oldAttribs.includes(newAttrib) && oldIds.includes(newAttrib.id)
  34. )
  35. .map((attrib) => attrib.id);
  36. oldAttribs = newAttribs;
  37. return { ...ports, changePort };
  38. };
  39. type AttribsChange = ReturnType<typeof getChangePart> & {
  40. changePort: string[];
  41. };
  42. export const watchAttribs = (
  43. attribs: Attrib[],
  44. callback: (data: AttribsChange) => void,
  45. immediate = true
  46. ) => {
  47. return watch(
  48. () => [...attribs],
  49. (newAttribs, oldAttribs = []) => {
  50. callback(getChangeAllPoart(newAttribs, oldAttribs));
  51. },
  52. { immediate, flush: "sync" }
  53. );
  54. };
  55. export const deptComputed = <T extends Record<string, any>>(
  56. getter: () => T
  57. ) => {
  58. const data = reactive(getter());
  59. const stop = watch(getter, (newData) => {
  60. if (inRevise(data, newData)) {
  61. if (Array.isArray(newData)) {
  62. newData.forEach((item, ndx) => {
  63. data[ndx] = item;
  64. });
  65. } else {
  66. Object.keys(data).forEach((key) => delete data[key]);
  67. Object.assign(data, newData);
  68. }
  69. }
  70. });
  71. return {
  72. data: data as T,
  73. stop,
  74. };
  75. };
  76. export const partialComputed = <T extends Attrib>(getter: () => T[]) => {
  77. const data = reactive(getter()) as T[];
  78. const stop = watch(getter, (newData, oldData) => {
  79. const { addPort, delPort, changePort } = getChangeAllPoart(
  80. newData,
  81. oldData
  82. );
  83. for (const delId of delPort) {
  84. const ndx = data.findIndex((i) => i.id === delId);
  85. ~ndx && data.splice(ndx, 1);
  86. }
  87. for (const addId of addPort) {
  88. const addItem = newData.find((i) => i.id === addId);
  89. addItem && data.push(addItem);
  90. }
  91. for (const changeId of changePort) {
  92. const dataNdx = data.findIndex((i) => i.id === changeId);
  93. const newDataNdx = newData.findIndex((i) => i.id === changeId);
  94. if (inRevise(data[dataNdx], newData[newDataNdx])) {
  95. data[dataNdx] = newData[newDataNdx];
  96. }
  97. }
  98. });
  99. return {
  100. data,
  101. stop,
  102. };
  103. };
  104. export const depPartialUpdate = <T>(newData: T, oldData: T): T => {
  105. if (!inRevise(newData, oldData)) {
  106. return oldData;
  107. }
  108. if (!oldData) {
  109. return newData;
  110. }
  111. const nData = newData as any,
  112. oData = oldData as any;
  113. const type = toRawType(nData);
  114. if (toRawType(oldData) !== type) {
  115. return newData;
  116. }
  117. switch (type) {
  118. case "Array":
  119. if (nData[0]?.id || oData[0]?.id) {
  120. var { changePort, addPort, delPort } = getChangeAllPoart(nData, oData);
  121. addPort.forEach((qid) => {
  122. oData.push(nData.find(({ id }) => id === qid));
  123. });
  124. delPort.forEach((dId) => {
  125. const ndx = oData.findIndex(({ id }) => id === dId);
  126. ~ndx && oData.splice(ndx, 1);
  127. });
  128. changePort.forEach((cId) => {
  129. const nItem = nData.find(({ id }) => id === cId);
  130. const ndx = oData.findIndex(({ id }) => id === cId);
  131. oData[ndx] = depPartialUpdate(nItem, oData[ndx]);
  132. });
  133. } else {
  134. for (let i = 0; i < nData.length; i++) {
  135. oData[i] = depPartialUpdate(nData[i], oData[i]);
  136. }
  137. while (oData.length !== nData.length) {
  138. oData.pop();
  139. }
  140. }
  141. break;
  142. case "Object":
  143. const oKeys = Object.keys(oData).sort();
  144. const nKeys = Object.keys(nData).sort();
  145. var { addPort, delPort, holdPort } = getChangePart(nKeys, oKeys);
  146. for (let i = 0; i < holdPort.length; i++) {
  147. oData[oKeys[i]] = depPartialUpdate(
  148. nData[holdPort[i]],
  149. oData[holdPort[i]]
  150. );
  151. }
  152. addPort.forEach((key) => (oData[key] = nData[key]));
  153. delPort.forEach((key) => delete oData[key]);
  154. break;
  155. default:
  156. return newData;
  157. }
  158. return oldData;
  159. };