km-card-layout-component-miniprogram 0.1.17 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/miniprogram_dist/components/card-layout/elements/custom-element/index.wxml +6 -4
  2. package/miniprogram_dist/components/card-layout/elements/icon-element/index.wxml +6 -4
  3. package/miniprogram_dist/components/card-layout/elements/image-element/index.wxml +10 -8
  4. package/miniprogram_dist/components/card-layout/elements/text-element/index.wxml +2 -0
  5. package/miniprogram_dist/components/card-layout/elements/text-element/index.wxss +0 -4
  6. package/miniprogram_dist/components/card-layout/index.js +83 -15
  7. package/miniprogram_dist/components/card-layout/index.json +1 -7
  8. package/miniprogram_dist/components/card-layout/index.wxml +21 -4
  9. package/miniprogram_dist/components/card-layout/index.wxss +83 -0
  10. package/miniprogram_dist/vendor/wxml2canvas-2d/canvas.js +1116 -0
  11. package/miniprogram_dist/vendor/wxml2canvas-2d/constants.js +42 -0
  12. package/miniprogram_dist/vendor/wxml2canvas-2d/element.js +420 -0
  13. package/miniprogram_dist/vendor/wxml2canvas-2d/gradient.js +634 -0
  14. package/miniprogram_dist/vendor/wxml2canvas-2d/index.js +169 -0
  15. package/miniprogram_dist/vendor/wxml2canvas-2d/index.json +4 -0
  16. package/miniprogram_dist/vendor/wxml2canvas-2d/index.wxml +7 -0
  17. package/miniprogram_dist/vendor/wxml2canvas-2d/index.wxss +5 -0
  18. package/package.json +1 -1
  19. package/src/components/card-layout/elements/custom-element/index.wxml +6 -4
  20. package/src/components/card-layout/elements/icon-element/index.wxml +6 -4
  21. package/src/components/card-layout/elements/image-element/index.wxml +10 -8
  22. package/src/components/card-layout/elements/text-element/index.wxml +2 -0
  23. package/src/components/card-layout/elements/text-element/index.wxss +0 -4
  24. package/src/components/card-layout/index.json +1 -7
  25. package/src/components/card-layout/index.ts +108 -16
  26. package/src/components/card-layout/index.wxml +21 -4
  27. package/src/components/card-layout/index.wxss +83 -0
  28. package/src/vendor/km-card-layout-core/types.d.ts +7 -1
  29. package/src/vendor/wxml2canvas-2d/canvas.js +1116 -0
  30. package/src/vendor/wxml2canvas-2d/constants.js +42 -0
  31. package/src/vendor/wxml2canvas-2d/element.js +420 -0
  32. package/src/vendor/wxml2canvas-2d/gradient.js +634 -0
  33. package/src/vendor/wxml2canvas-2d/index.js +169 -0
  34. package/src/vendor/wxml2canvas-2d/index.json +4 -0
  35. package/src/vendor/wxml2canvas-2d/index.wxml +7 -0
  36. package/src/vendor/wxml2canvas-2d/index.wxss +5 -0
@@ -0,0 +1,42 @@
1
+ /** CSS 默认行高 */
2
+ export const DEFAULT_LINE_HEIGHT = 1.4;
3
+ /** 字体大小位置校准 */
4
+ // CSS 与 画布 的 font-size 存在数值偏差,暂时以常数换算实现近似结果
5
+ export const FONT_SIZE_OFFSET = 0.88;
6
+ /** 换行符 */
7
+ export const LINE_BREAK_SYMBOL = '\n';
8
+ /** 系统信息 */
9
+ export const {
10
+ platform: SYS_PLATFORM,
11
+ pixelRatio: SYS_DPR,
12
+ windowWidth: SYS_WIDTH,
13
+ } = wx.getSystemInfoSync();
14
+ /** 是否为 iOS 平台 */
15
+ export const IS_IOS = SYS_PLATFORM === 'ios';
16
+ /** 是否为 macOS 平台 */
17
+ export const IS_MAC = SYS_PLATFORM === 'mac';
18
+ /** 是否为 Android 平台 */
19
+ export const IS_ANDROID = SYS_PLATFORM === 'android';
20
+ /** 是否为微信开发者工具 */
21
+ export const IS_DEVTOOL = SYS_PLATFORM === 'devtools';
22
+ /** 是否为 Windows 平台 */
23
+ export const IS_WINDOWS = SYS_PLATFORM === 'windows';
24
+ /** 是否为移动设备 */
25
+ export const IS_MOBILE = IS_ANDROID || IS_IOS;
26
+ /** 设备像素与 750px 设计图比例 */
27
+ export const RPX_RATIO = 750 / SYS_WIDTH;
28
+ /** 三角函数值 转换 弧度 换算比例 */
29
+ export const TRI2RAD_RATIO = Math.PI / 180;
30
+ /** 椭圆形径向渐变的长短轴比例 */
31
+ // 暂未找到 CSS 中椭圆形径向渐变的长短轴生成规律,以常数代替实现近似结果
32
+ export const SIDE2CORNER_RATIO = 1.4141;
33
+ /** 视频海报的裁剪、缩放模式 */
34
+ export const VIDEO_POSTER_MODES = {
35
+ contain: 'aspectFit',
36
+ cover: 'aspectFill',
37
+ fill: 'scaleToFill',
38
+ };
39
+ /** 位置列表 */
40
+ export const POSITIONS = ['left', 'top', 'right', 'bottom'];
41
+ /** 双实线宽度与单实线宽度比例 */
42
+ export const DOUBLE_LINE_RATIO = 2 / 7;
@@ -0,0 +1,420 @@
1
+ import { POSITIONS } from './constants';
2
+
3
+ /**
4
+ * 获取部分指定字段(与布局位置字段重名)
5
+ * @param {Object} nodesRef WXML 节点信息对象
6
+ * @returns {Object} 指定字段对象
7
+ */
8
+ const getComputedRect = (nodesRef) => {
9
+ let {
10
+ left, right,
11
+ bottom, top,
12
+ width, height,
13
+ } = nodesRef;
14
+ if (left !== 'auto') left = parseFloat(left);
15
+ if (right !== 'auto') right = parseFloat(right);
16
+ if (top !== 'auto') top = parseFloat(top);
17
+ if (bottom !== 'auto') bottom = parseFloat(bottom);
18
+ if (width !== 'auto') width = parseFloat(width);
19
+ if (height !== 'auto') height = parseFloat(height);
20
+ return {
21
+ left, right, bottom, top, width, height,
22
+ };
23
+ };
24
+
25
+ /**
26
+ * wxml 元素工具类
27
+ *
28
+ * 实例化:
29
+ * ```javascript
30
+ * const element = new Element(nodesRef);
31
+ * ```
32
+ */
33
+ class Element {
34
+ constructor(nodesRef) {
35
+ Object.assign(this, nodesRef);
36
+ }
37
+
38
+ /**
39
+ * 获取 wxml 元素的顶点坐标:左上、右上、右下、左下
40
+ * @param {String} sizing 盒子模型描述
41
+ * @return {Array} 顶点坐标
42
+ */
43
+ getVertex(sizing = 'border') {
44
+ const key = `__${sizing}Vertex`;
45
+ if (this[key]) return this[key];
46
+ const content = this.getBoxSize(sizing);
47
+ const leftTop = [content.left, content.top];
48
+ const rightTop = [content.left + content.width, content.top];
49
+ const leftBottom = [content.left, content.top + content.height];
50
+ const rightBottom = [content.left + content.width, content.top + content.height];
51
+ /** 顶点坐标:左上、右上、右下、左下 */
52
+ const vertex = [leftTop, rightTop, rightBottom, leftBottom];
53
+ Object.assign(this, { [key]: vertex });
54
+ return vertex;
55
+ }
56
+
57
+ /**
58
+ * 获取 wxml 元素的内容盒子大小数据
59
+ * @param {String} sizing 盒子模型描述
60
+ * @returns {Object} 盒子大小数据
61
+ */
62
+ getBoxSize(sizing = 'border') {
63
+ const key = `__${sizing}Box`;
64
+ if (this[key]) return this[key];
65
+
66
+ let offsetLeft = this.left;
67
+ let offsetTop = this.top;
68
+ let offsetRight = this.right;
69
+ let offsetBottom = this.bottom;
70
+ let offsetWidth = this.width;
71
+ let offsetHeight = this.height;
72
+
73
+ switch (sizing) {
74
+ case 'content': {
75
+ const padLeft = parseFloat(this['padding-left']);
76
+ const padTop = parseFloat(this['padding-top']);
77
+ const padRight = parseFloat(this['padding-right']);
78
+ const padBottom = parseFloat(this['padding-bottom']);
79
+ offsetLeft += padLeft;
80
+ offsetTop += padTop;
81
+ offsetRight -= padRight;
82
+ offsetBottom -= padBottom;
83
+ offsetWidth -= (padLeft + padRight);
84
+ offsetHeight -= (padTop + padBottom);
85
+ }
86
+ case 'padding': {
87
+ const border = this.getBorder();
88
+ offsetLeft += border.left.width;
89
+ offsetTop += border.top.width;
90
+ offsetRight -= border.right.width;
91
+ offsetBottom -= border.bottom.width;
92
+ offsetWidth -= border.left.width + border.right.width;
93
+ offsetHeight -= border.top.width + border.bottom.width;
94
+ break;
95
+ }
96
+ default:
97
+ }
98
+ Object.assign(this, {
99
+ [key]: {
100
+ left: offsetLeft,
101
+ top: offsetTop,
102
+ right: offsetRight,
103
+ bottom: offsetBottom,
104
+ width: offsetWidth,
105
+ height: offsetHeight,
106
+ },
107
+ });
108
+ return this[key];
109
+ }
110
+
111
+ /**
112
+ * 获取 wxml 元素的边框数据
113
+ * @returns {Object} 边框数据
114
+ */
115
+ getBorder() {
116
+ if (this.__border) return this.__border;
117
+ let borderWidth = 0;
118
+ let borderStyle = '';
119
+ let borderColor = '';
120
+ Object.assign(this, { __border: {} });
121
+ if (this.border) {
122
+ [borderWidth, borderStyle, ...borderColor] = this.border.split(' ');
123
+ if (borderStyle === 'none') {
124
+ borderWidth = 0;
125
+ } else {
126
+ borderWidth = parseFloat(borderWidth);
127
+ }
128
+ borderColor = borderColor.join(' ');
129
+ Object.assign(this.__border, {
130
+ width: borderWidth,
131
+ style: borderStyle,
132
+ color: borderColor,
133
+ });
134
+ }
135
+ POSITIONS.map((key) => {
136
+ [borderWidth, borderStyle, ...borderColor] = this[`border-${key}`].split(' ');
137
+ if (borderStyle === 'none') {
138
+ borderWidth = 0;
139
+ } else {
140
+ borderWidth = parseFloat(borderWidth);
141
+ }
142
+ borderColor = borderColor.join(' ');
143
+ Object.assign(this.__border, {
144
+ [`${key}`]: {
145
+ width: borderWidth,
146
+ style: borderStyle,
147
+ color: borderColor,
148
+ },
149
+ });
150
+ return key;
151
+ });
152
+ return this.__border;
153
+ }
154
+
155
+ /**
156
+ * 获取 wxml 元素的背景色数据
157
+ * @returns {Object} 背景色数据
158
+ */
159
+ getBackgroundColor() {
160
+ if (this.__backgroundColor) return this.__backgroundColor;
161
+ let rColor = 0;
162
+ let gColor = 0;
163
+ let bColor = 0;
164
+ let alpha = 0;
165
+
166
+ [rColor, gColor, bColor, alpha] = this['background-color'].split(', ');
167
+ rColor = +rColor.slice(rColor.indexOf('(') + 1);
168
+ gColor = +gColor;
169
+ if (!alpha) {
170
+ alpha = 1;
171
+ bColor = +bColor.slice(0, -1);
172
+ } else {
173
+ bColor = +bColor;
174
+ alpha = +alpha.slice(0, -1);
175
+ }
176
+ Object.assign(this, {
177
+ __backgroundColor: {
178
+ rColor,
179
+ gColor,
180
+ bColor,
181
+ alpha,
182
+ },
183
+ });
184
+ return this.__backgroundColor;
185
+ }
186
+
187
+ /**
188
+ * 获取 wxml 元素的阴影数据
189
+ * @returns {Object} 阴影数据
190
+ */
191
+ getBoxShadow() {
192
+ if (this.__boxShadow) return this.__boxShadow;
193
+ let color = '';
194
+ let blur = 0;
195
+ let offsetX = 0;
196
+ let offsetY = 0;
197
+ if (this['box-shadow'] !== 'none') {
198
+ let tempStr;
199
+ [tempStr, offsetY, blur] = this['box-shadow'].split('px ');
200
+ const tempIdx = tempStr.lastIndexOf(' ');
201
+ color = tempStr.slice(0, tempIdx);
202
+ offsetX = tempStr.slice(tempIdx + 1);
203
+ }
204
+ Object.assign(this, {
205
+ __boxShadow: {
206
+ blur,
207
+ color,
208
+ offsetX,
209
+ offsetY,
210
+ },
211
+ });
212
+ return this.__boxShadow;
213
+ }
214
+
215
+ /**
216
+ * 获取 wxml 文本的阴影数据
217
+ * @returns {Object} 阴影数据
218
+ */
219
+ getTextShadow() {
220
+ if (this.__textShadow) return this.__textShadow;
221
+ let color = '';
222
+ let blur = 0;
223
+ let offsetX = 0;
224
+ let offsetY = 0;
225
+ if (this['text-shadow'] !== 'none') {
226
+ let tempStr;
227
+ [tempStr, offsetY, blur] = this['text-shadow'].split('px ');
228
+ const tempIdx = tempStr.lastIndexOf(' ');
229
+ color = tempStr.slice(0, tempIdx);
230
+ offsetX = tempStr.slice(tempIdx + 1);
231
+ blur = parseFloat(blur);
232
+ }
233
+ Object.assign(this, {
234
+ __textShadow: {
235
+ blur,
236
+ color,
237
+ offsetX,
238
+ offsetY,
239
+ },
240
+ });
241
+ return this.__textShadow;
242
+ }
243
+
244
+ /**
245
+ * 获取 wxml 元素的边缘圆角数据
246
+ * @returns {Object} 圆角数据
247
+ */
248
+ getBorderRadius() {
249
+ if (this.__borderRadius) return this.__borderRadius;
250
+ let [leftTop, topLeft] = this['border-top-left-radius'].split(' ');
251
+ let [rightTop, topRight] = this['border-top-right-radius'].split(' ');
252
+ let [leftBottom, bottomLeft] = this['border-bottom-left-radius'].split(' ');
253
+ let [rightBottom, bottomRight] = this['border-bottom-right-radius'].split(' ');
254
+
255
+ if (/%/.test(topLeft ?? leftTop)) {
256
+ topLeft = this.height * (parseFloat(topLeft ?? leftTop) / 100);
257
+ } else {
258
+ topLeft = parseFloat(topLeft ?? leftTop);
259
+ }
260
+ if (/%/.test(leftTop)) {
261
+ leftTop = this.width * (parseFloat(leftTop) / 100);
262
+ } else {
263
+ leftTop = parseFloat(leftTop);
264
+ }
265
+
266
+ if (/%/.test(topRight ?? rightTop)) {
267
+ topRight = this.height * (parseFloat(topRight ?? rightTop) / 100);
268
+ } else {
269
+ topRight = parseFloat(topRight ?? rightTop);
270
+ }
271
+ if (/%/.test(rightTop)) {
272
+ rightTop = this.width * (parseFloat(rightTop) / 100);
273
+ } else {
274
+ rightTop = parseFloat(rightTop);
275
+ }
276
+
277
+ if (/%/.test(bottomLeft ?? leftBottom)) {
278
+ bottomLeft = this.height * (parseFloat(bottomLeft ?? leftBottom) / 100);
279
+ } else {
280
+ bottomLeft = parseFloat(bottomLeft ?? leftBottom);
281
+ }
282
+ if (/%/.test(leftBottom)) {
283
+ leftBottom = this.width * (parseFloat(leftBottom) / 100);
284
+ } else {
285
+ leftBottom = parseFloat(leftBottom);
286
+ }
287
+
288
+ if (/%/.test(bottomRight ?? rightBottom)) {
289
+ bottomRight = this.height * (parseFloat(bottomRight ?? rightBottom) / 100);
290
+ } else {
291
+ bottomRight = parseFloat(bottomRight ?? rightBottom);
292
+ }
293
+ if (/%/.test(rightBottom)) {
294
+ rightBottom = this.width * (parseFloat(rightBottom) / 100);
295
+ } else {
296
+ rightBottom = parseFloat(rightBottom);
297
+ }
298
+
299
+ /** 各个圆角的缩放比例 */
300
+ let rScale;
301
+ if (
302
+ (leftTop + rightTop) > this.width
303
+ || (leftBottom + rightBottom) > this.width
304
+ || (topLeft + bottomLeft) > this.height
305
+ || (topRight + bottomRight) > this.height
306
+ ) {
307
+ // 由各边长度以及对应的圆角半径决定
308
+ rScale = Math.min(
309
+ this.height / (topLeft + bottomLeft),
310
+ this.height / (topRight + bottomRight),
311
+ this.width / (leftTop + rightTop),
312
+ this.width / (leftBottom + rightBottom),
313
+ );
314
+ leftTop *= rScale;
315
+ rightTop *= rScale;
316
+ leftBottom *= rScale;
317
+ rightBottom *= rScale;
318
+ topLeft *= rScale;
319
+ topRight *= rScale;
320
+ bottomLeft *= rScale;
321
+ bottomRight *= rScale;
322
+ }
323
+ Object.assign(this, {
324
+ __borderRadius: {
325
+ leftTop,
326
+ rightTop,
327
+ leftBottom,
328
+ rightBottom,
329
+ topLeft,
330
+ topRight,
331
+ bottomLeft,
332
+ bottomRight,
333
+ },
334
+ });
335
+ return this.__borderRadius;
336
+ }
337
+ }
338
+
339
+ /** 节点通用属性名 */
340
+ Element.COMMON_PROPERTIES = [];
341
+ /** 节点固定样式名(可能与节点其他字段重名) */
342
+ Element.CONSTANT_COMPUTED_STYLE = [
343
+ 'width', 'height', 'left', 'top', 'right', 'bottom',
344
+ ];
345
+ /** 节点通用样式名 */
346
+ Element.COMMON_COMPUTED_STYLE = [
347
+ 'background-color', 'border-radius', 'background-image',
348
+ 'background-position', 'background-size', 'background-repeat',
349
+ 'padding-top', 'padding-left', 'padding-right', 'padding-bottom',
350
+ 'border', 'box-shadow', 'opacity', 'background-clip',
351
+ 'border-top-left-radius', 'border-top-right-radius',
352
+ 'border-bottom-right-radius', 'border-bottom-left-radius',
353
+ 'overflow', 'filter', 'transform', 'transform-origin',
354
+ 'border-top', 'border-right', 'border-bottom', 'border-left',
355
+ ];
356
+ /** 文字节点特殊属性名 */
357
+ Element.TEXT_PROPERTIES = [];
358
+ /** 文字节点特殊样式名 */
359
+ Element.TEXT_COMPUTED_STYLE = [
360
+ 'font-family', 'font-size', 'font-weight', 'text-align',
361
+ 'line-height', 'text-overflow', 'color', 'text-indent',
362
+ 'text-shadow', 'letter-spacing', 'word-spacing', 'direction',
363
+ 'text-decoration-style', 'text-decoration-line', 'text-decoration-color',
364
+ 'writing-mode',
365
+ ];
366
+ /** 图片节点特殊属性名 */
367
+ Element.IMAGE_PROPERTIES = [
368
+ 'src', 'mode',
369
+ ];
370
+ /** 图片节点特殊样式名 */
371
+ Element.IMAGE_COMPUTED_STYLE = [];
372
+ /** 视频节点特殊属性名 */
373
+ Element.VIDEO_PROPERTIES = [
374
+ 'src', 'object-fit', 'poster',
375
+ ];
376
+ /** 视频节点特殊样式名 */
377
+ Element.VIDEO_COMPUTED_STYLE = [];
378
+ /** 视频节点特殊属性名 */
379
+ Element.CANVAS_PROPERTIES = [
380
+ 'type', 'canvas-id',
381
+ ];
382
+ /** 画布节点特殊属性名 */
383
+ Element.CANVAS_COMPUTED_STYLE = [];
384
+ /** 富文本节点特殊属性名 */
385
+ Element.RICHTEXT_PROPERTIES = ['nodes'];
386
+ /** 富文本节点特殊样式名 */
387
+ Element.RICHTEXT_COMPUTED_STYLE = [];
388
+
389
+ /**
390
+ * 获取 WXML 节点信息对象
391
+ * @param {String} selector 选择器
392
+ * @param {Object} fields 节点信息字段
393
+ * @param {PageObject} page 页面实例对象
394
+ * @param {ComponentObject} component 组件实例对象
395
+ * @returns {Promise<object>} 节点信息
396
+ */
397
+ Element.getNodesRef = (selector, fields, page, component) => new Promise((resolve) => {
398
+ const query = page.createSelectorQuery();
399
+ if (component) { query.in(component); }
400
+ const refs = query.selectAll(selector);
401
+ refs.fields(fields);
402
+ refs.fields({
403
+ computedStyle: Element.CONSTANT_COMPUTED_STYLE,
404
+ });
405
+ refs.node();
406
+ query.exec((res) => {
407
+ if (res && res.length > 0) {
408
+ res[0].map((item, index) => {
409
+ Object.assign(item, {
410
+ __computedRect: getComputedRect(res[1][index]),
411
+ ...res[2][index],
412
+ });
413
+ return item;
414
+ });
415
+ }
416
+ resolve(res[0]);
417
+ });
418
+ });
419
+
420
+ export default Element;