vben
2021-02-05 91e004e21148c38e572cfbb6b75f0a6f353c15b6
提交 | 用户 | age
74e62c 1 import type { VNodeChild } from 'vue';
b71e4e 2 import type { App } from 'vue';
234c1d 3
74e62c 4 export function withInstall(...components: any[]) {
V 5   components.forEach((comp) => {
6     comp.install = (app: App) => {
7       app.component(comp.displayName || comp.name, comp);
8     };
9   });
234c1d 10 }
2f6253 11
12 export function convertToUnit(
13   str: string | number | null | undefined,
14   unit = 'px'
15 ): string | undefined {
16   if (str == null || str === '') {
17     return undefined;
18   } else if (isNaN(+str!)) {
19     return String(str);
20   } else {
21     return `${Number(str)}${unit}`;
22   }
23 }
24
25 /**
26  * Camelize a hyphen-delimited string.
27  */
28 const camelizeRE = /-(\w)/g;
29 export const camelize = (str: string): string => {
30   return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));
31 };
32
33 export function wrapInArray<T>(v: T | T[] | null | undefined): T[] {
34   return v != null ? (Array.isArray(v) ? v : [v]) : [];
35 }
36
37 const pattern = {
38   styleList: /;(?![^(]*\))/g,
39   styleProp: /:(.*)/,
40 } as const;
41
42 function parseStyle(style: string) {
4ff1c4 43   const styleMap: Recordable = {};
2f6253 44
45   for (const s of style.split(pattern.styleList)) {
46     let [key, val] = s.split(pattern.styleProp);
47     key = key.trim();
48     if (!key) {
49       continue;
50     }
51     // May be undefined if the `key: value` pair is incomplete.
52     if (typeof val === 'string') {
53       val = val.trim();
54     }
55     styleMap[camelize(key)] = val;
56   }
57
58   return styleMap;
59 }
60
61 /**
62  * Intelligently merges data for createElement.
63  * Merges arguments left to right, preferring the right argument.
64  * Returns new VNodeData object.
65  */
66 export function mergeData(...vNodeData: VNodeChild[]): VNodeChild;
67 export function mergeData(...args: any[]): VNodeChild {
68   const mergeTarget: any = {};
69   let i: number = args.length;
70   let prop: string;
71
72   // Allow for variadic argument length.
73   while (i--) {
74     // Iterate through the data properties and execute merge strategies
75     // Object.keys eliminates need for hasOwnProperty call
76     for (prop of Object.keys(args[i])) {
77       switch (prop) {
78         // Array merge strategy (array concatenation)
79         case 'class':
80         case 'directives':
81           if (args[i][prop]) {
82             mergeTarget[prop] = mergeClasses(mergeTarget[prop], args[i][prop]);
83           }
84           break;
85         case 'style':
86           if (args[i][prop]) {
87             mergeTarget[prop] = mergeStyles(mergeTarget[prop], args[i][prop]);
88           }
89           break;
90         // Space delimited string concatenation strategy
91         case 'staticClass':
92           if (!args[i][prop]) {
93             break;
94           }
95           if (mergeTarget[prop] === undefined) {
96             mergeTarget[prop] = '';
97           }
98           if (mergeTarget[prop]) {
99             // Not an empty string, so concatenate
100             mergeTarget[prop] += ' ';
101           }
102           mergeTarget[prop] += args[i][prop].trim();
103           break;
104         // Object, the properties of which to merge via array merge strategy (array concatenation).
105         // Callback merge strategy merges callbacks to the beginning of the array,
106         // so that the last defined callback will be invoked first.
107         // This is done since to mimic how Object.assign merging
108         // uses the last given value to assign.
109         case 'on':
110         case 'nativeOn':
111           if (args[i][prop]) {
112             mergeTarget[prop] = mergeListeners(mergeTarget[prop], args[i][prop]);
113           }
114           break;
115         // Object merge strategy
116         case 'attrs':
117         case 'props':
118         case 'domProps':
119         case 'scopedSlots':
120         case 'staticStyle':
121         case 'hook':
122         case 'transition':
123           if (!args[i][prop]) {
124             break;
125           }
126           if (!mergeTarget[prop]) {
127             mergeTarget[prop] = {};
128           }
129           mergeTarget[prop] = { ...args[i][prop], ...mergeTarget[prop] };
130           break;
131         // Reassignment strategy (no merge)
132         default:
133           // slot, key, ref, tag, show, keepAlive
134           if (!mergeTarget[prop]) {
135             mergeTarget[prop] = args[i][prop];
136           }
137       }
138     }
139   }
140
141   return mergeTarget;
142 }
143
144 export function mergeStyles(
145   target: undefined | string | object[] | object,
146   source: undefined | string | object[] | object
147 ) {
148   if (!target) return source;
149   if (!source) return target;
150
151   target = wrapInArray(typeof target === 'string' ? parseStyle(target) : target);
152
153   return (target as object[]).concat(typeof source === 'string' ? parseStyle(source) : source);
154 }
155
156 export function mergeClasses(target: any, source: any) {
157   if (!source) return target;
158   if (!target) return source;
159
160   return target ? wrapInArray(target).concat(source) : source;
161 }
162
163 export function mergeListeners(
4ff1c4 164   target: Indexable<Function | Function[]> | undefined,
V 165   source: Indexable<Function | Function[]> | undefined
2f6253 166 ) {
167   if (!target) return source;
168   if (!source) return target;
169
170   let event: string;
171
172   for (event of Object.keys(source)) {
173     // Concat function to array of functions if callback present.
174     if (target[event]) {
175       // Insert current iteration data in beginning of merged array.
176       target[event] = wrapInArray(target[event]);
177       (target[event] as Function[]).push(...wrapInArray(source[event]));
178     } else {
179       // Straight assign.
180       target[event] = source[event];
181     }
182   }
183
184   return target;
185 }