@taole/dev-helper 0.1.13 → 0.1.15

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.
package/Tdiv/index.js CHANGED
@@ -33,6 +33,13 @@ function hasValue(value) {
33
33
  return value !== null && value !== undefined && value !== '';
34
34
  }
35
35
 
36
+ function parseClassTokens(value) {
37
+ if (!value) return [];
38
+ return value.trim().split(/\s+/).filter(Boolean);
39
+ }
40
+
41
+ const RESERVED_CLASS = new Set(['tw-img-div', 'click-effect']);
42
+
36
43
  function calc(value, { usePx, viewportWidth, viewportUnit }) {
37
44
  let vWidth = setting.viewportWidth;
38
45
  if (viewportWidth) vWidth = viewportWidth;
@@ -55,10 +62,10 @@ function calc(value, { usePx, viewportWidth, viewportUnit }) {
55
62
  class Tdiv extends HTMLElement {
56
63
  static get observedAttributes() {
57
64
  return [
58
- '_class', 'usePx', '_style', 'src', 'width', 'height', 'absolute', 'fixed',
65
+ 'class', '_class', 'usePx', '_style', 'src', 'width', 'height', 'absolute', 'fixed',
59
66
  'top', 'left', 'right', 'bottom', 'zIndex', 'pointer', 'flex', 'column', 'center',
60
67
  'text', 'color', 'radius', 'border', 'borderColor', 'srcMode', 'onClick', 'debug', 'viewportWidth', 'viewportUnit',
61
- 'dot9', 'dot9Border', 'bold', 'textEllipsis', 'bgColor'
68
+ 'dot9', 'dot9Border', 'bold', 'textEllipsis', 'textDot', 'bgColor'
62
69
  ];
63
70
  }
64
71
 
@@ -68,6 +75,8 @@ class Tdiv extends HTMLElement {
68
75
  this._connected = false;
69
76
  this._iscalcstyle = false;
70
77
  this._unsubscribe = null;
78
+ this._managedClasses = new Set();
79
+ this._syncingClass = false;
71
80
  }
72
81
 
73
82
  connectedCallback() {
@@ -87,8 +96,9 @@ class Tdiv extends HTMLElement {
87
96
  }
88
97
  }
89
98
 
90
- attributeChangedCallback() {
99
+ attributeChangedCallback(name) {
91
100
  if (!this._connected) return;
101
+ if (this._iscalcstyle || this._syncingClass) return;
92
102
  this._update();
93
103
  }
94
104
 
@@ -111,11 +121,48 @@ class Tdiv extends HTMLElement {
111
121
  return val;
112
122
  }
113
123
 
124
+ _getUserClassTokens() {
125
+ const tokens = new Set();
126
+ parseClassTokens(this._getAttr('_class') || '').forEach((t) => tokens.add(t));
127
+ parseClassTokens(this.getAttribute('class') || '')
128
+ .filter((t) => !RESERVED_CLASS.has(t))
129
+ .forEach((t) => tokens.add(t));
130
+ return tokens;
131
+ }
132
+
133
+ _syncClasses(desiredManaged) {
134
+ let changed = false;
135
+ for (const cls of this._managedClasses) {
136
+ if (!desiredManaged.has(cls)) changed = true;
137
+ }
138
+ if (!changed) {
139
+ for (const cls of desiredManaged) {
140
+ if (!this._managedClasses.has(cls)) {
141
+ changed = true;
142
+ break;
143
+ }
144
+ }
145
+ }
146
+ if (!changed) return;
147
+
148
+ this._syncingClass = true;
149
+ try {
150
+ for (const cls of this._managedClasses) {
151
+ if (!desiredManaged.has(cls)) this.classList.remove(cls);
152
+ }
153
+ for (const cls of desiredManaged) {
154
+ this.classList.add(cls);
155
+ }
156
+ this._managedClasses = desiredManaged;
157
+ } finally {
158
+ this._syncingClass = false;
159
+ }
160
+ }
161
+
114
162
  _update() {
115
163
  if (this._iscalcstyle) return;
116
164
  this._iscalcstyle = true;
117
165
  // 读取所有属性
118
- const _class = this._getAttr('_class') || '';
119
166
  const usePx = this._getAttr('usePx', 'boolean');
120
167
  const styleAttr = this._getAttr('_style') || '';
121
168
  const src = this._getAttr('src') || '';
@@ -143,14 +190,15 @@ class Tdiv extends HTMLElement {
143
190
  const debug = this._getAttr('debug', 'boolean');
144
191
  const viewportWidth = this._getAttr('viewportWidth', 'number');
145
192
  const viewportUnit = this._getAttr('viewportUnit');
146
- const textEllipsis = this._getAttr('textEllipsis');
193
+ const textEllipsis = this.hasAttribute('textEllipsis')
194
+ ? this._getAttr('textEllipsis')
195
+ : this._getAttr('textDot');
147
196
  let dot9 = (this._getAttr('dot9', 'string') || '').split(" ");
148
197
  let dot9Border = (this._getAttr('dot9Border', 'string') || this._getAttr('dot9', 'string') || '').split(" ");
149
198
 
150
- // class
151
- let extraClass = ['tw-img-div'];
152
- if (_class) extraClass.push(_class);
153
- if (setting.useButtonEffect && this._getAttr('onClick')) extraClass.push('click-effect');
199
+ // class(组件托管:tw-img-div、class/_class 空格分拆、click-effect)
200
+ const desiredManaged = new Set(['tw-img-div', ...this._getUserClassTokens()]);
201
+ if (setting.useButtonEffect && this._getAttr('onClick')) desiredManaged.add('click-effect');
154
202
  // 分组样式
155
203
  const calcOpt = { usePx, viewportWidth, viewportUnit };
156
204
  let layoutStyle = '';
@@ -278,9 +326,7 @@ class Tdiv extends HTMLElement {
278
326
  if (debug) {
279
327
  console.log('layoutStyle', layoutStyle);
280
328
  }
281
- const currentList = Array.from(this.classList);
282
- const classNeeded = extraClass.filter(item => !currentList.includes(item));
283
- this.classList.add(...classNeeded);
329
+ this._syncClasses(desiredManaged);
284
330
  this.style.cssText = layoutStyle;
285
331
  this._iscalcstyle = false;
286
332
  }
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const packageRoot = resolve(__dirname, '..');
8
+ const PACKAGE_NAME = '@taole/dev-helper';
9
+ const HTML_DATA_ENTRY = `./node_modules/${PACKAGE_NAME}/custom-data/t-div.html-data.json`;
10
+
11
+ function getProjectRoot() {
12
+ return process.env.INIT_CWD ? resolve(process.env.INIT_CWD) : process.cwd();
13
+ }
14
+
15
+ function printUsage() {
16
+ console.log(`用法: npx ${PACKAGE_NAME} init-t-div`);
17
+ console.log(' 在项目的 .vscode/settings.json 中写入 html.customData 配置');
18
+ }
19
+
20
+ function parseSettings(content) {
21
+ try {
22
+ return JSON.parse(content);
23
+ } catch {
24
+ console.error('无法解析 .vscode/settings.json,请确保为合法 JSON(不支持注释)。');
25
+ process.exit(1);
26
+ }
27
+ }
28
+
29
+ function hasHtmlDataEntry(list) {
30
+ const target = HTML_DATA_ENTRY.replace(/\\/g, '/');
31
+ return list.some((item) => {
32
+ if (typeof item !== 'string') return false;
33
+ const normalized = item.replace(/\\/g, '/');
34
+ return (
35
+ normalized === target ||
36
+ normalized.endsWith('/custom-data/t-div.html-data.json')
37
+ );
38
+ });
39
+ }
40
+
41
+ function getHtmlCustomData(settings) {
42
+ if (!settings || settings['html.customData'] == null) return [];
43
+ const data = settings['html.customData'];
44
+ return Array.isArray(data) ? data : [data];
45
+ }
46
+
47
+ function getInstalledDataPath(projectRoot) {
48
+ return join(
49
+ projectRoot,
50
+ 'node_modules',
51
+ '@taole',
52
+ 'dev-helper',
53
+ 'custom-data',
54
+ 't-div.html-data.json',
55
+ );
56
+ }
57
+
58
+ function shouldSkipPostinstall(projectRoot) {
59
+ if (process.env.CI === 'true' || process.env.DEV_HELPER_SKIP_INIT === '1') {
60
+ return true;
61
+ }
62
+ if (!process.env.INIT_CWD) {
63
+ return true;
64
+ }
65
+ if (resolve(projectRoot) === packageRoot) {
66
+ return true;
67
+ }
68
+ return false;
69
+ }
70
+
71
+ function initTDiv({ silent = false } = {}) {
72
+ const projectRoot = getProjectRoot();
73
+ const vscodeDir = join(projectRoot, '.vscode');
74
+ const settingsPath = join(vscodeDir, 'settings.json');
75
+ const installedDataPath = getInstalledDataPath(projectRoot);
76
+
77
+ if (existsSync(settingsPath)) {
78
+ const existing = getHtmlCustomData(parseSettings(readFileSync(settingsPath, 'utf8')));
79
+ if (hasHtmlDataEntry(existing)) {
80
+ if (!silent) console.log('html.customData 已包含 t-div 配置,跳过。');
81
+ return;
82
+ }
83
+ }
84
+
85
+ if (!existsSync(installedDataPath)) {
86
+ const message = `未在项目中找到 ${HTML_DATA_ENTRY},请先安装: npm install ${PACKAGE_NAME}`;
87
+ if (silent) return;
88
+ console.error(message);
89
+ process.exit(1);
90
+ }
91
+
92
+ let settings = existsSync(settingsPath)
93
+ ? parseSettings(readFileSync(settingsPath, 'utf8'))
94
+ : {};
95
+
96
+ if (!Array.isArray(settings['html.customData'])) {
97
+ settings['html.customData'] = settings['html.customData']
98
+ ? [settings['html.customData']]
99
+ : [];
100
+ }
101
+
102
+ settings['html.customData'].push(HTML_DATA_ENTRY);
103
+ mkdirSync(vscodeDir, { recursive: true });
104
+ writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`, 'utf8');
105
+ if (!silent) {
106
+ console.log(`已写入 ${settingsPath}`);
107
+ console.log(` html.customData += "${HTML_DATA_ENTRY}"`);
108
+ }
109
+ }
110
+
111
+ function runPostinstall() {
112
+ const projectRoot = getProjectRoot();
113
+ if (shouldSkipPostinstall(projectRoot)) return;
114
+ initTDiv({ silent: true });
115
+ }
116
+
117
+ const command = process.argv[2];
118
+
119
+ if (command === 'init-t-div') {
120
+ initTDiv();
121
+ } else if (command === 'postinstall') {
122
+ runPostinstall();
123
+ } else if (command) {
124
+ console.error(`未知命令: ${command}\n`);
125
+ printUsage();
126
+ process.exit(1);
127
+ } else {
128
+ printUsage();
129
+ }
@@ -0,0 +1,173 @@
1
+ {
2
+ "version": 1.1,
3
+ "tags": [
4
+ {
5
+ "name": "t-div",
6
+ "description": "基于设计稿尺寸的布局容器 Web Component。数值属性会按 viewportWidth(默认 750)换算为 vw;设置 usePx 后按 px 输出。支持背景图、九宫格 border-image、flex 布局与文本省略。需先引入 tdiv.umd.js。",
7
+ "attributes": [
8
+ {
9
+ "name": "class",
10
+ "description": "class属性"
11
+ },
12
+ {
13
+ "name": "_class",
14
+ "description": "(兼容)同 class,与 class 合并生效;推荐直接使用 class属性"
15
+ },
16
+ {
17
+ "name": "usePx",
18
+ "description": "为 true 时 width/height/top 等数值属性直接输出 px,否则按 viewportWidth 换算为 viewportUnit(默认 vw)。可覆盖全局 setting.usePx。"
19
+ },
20
+ {
21
+ "name": "_style",
22
+ "description": "追加到计算后内联 style 末尾的原始 CSS 字符串。"
23
+ },
24
+ {
25
+ "name": "src",
26
+ "description": "背景图或九宫格图源。非 http(s) 路径会补全为 dynamics-share CDN;以 -- 开头时作为 CSS 变量(如 --bg1 → var(--bg1))。支持 WebP 自动处理。"
27
+ },
28
+ {
29
+ "name": "srcMode",
30
+ "description": "非九宫格时 background-size 模式。",
31
+ "valueSet": "tdiv-srcMode"
32
+ },
33
+ {
34
+ "name": "dot9",
35
+ "description": "九宫格 border-image slice,4 个空格分隔数值(上 右 下 左)"
36
+ },
37
+ {
38
+ "name": "dot9Border",
39
+ "description": "九宫格 border-width,4 个空格分隔数值;未设置时回退为 dot9 的值。"
40
+ },
41
+ {
42
+ "name": "width",
43
+ "description": "宽度,数字或数字字符串"
44
+ },
45
+ {
46
+ "name": "height",
47
+ "description": "高度,数字或数字字符串"
48
+ },
49
+ {
50
+ "name": "absolute",
51
+ "description": "为 true 时使用 position: absolute,top/left/right/bottom 作为定位偏移。"
52
+ },
53
+ {
54
+ "name": "fixed",
55
+ "description": "为 true 时使用 position: fixed(优先于 absolute),top/left/right/bottom 作为定位偏移。"
56
+ },
57
+ {
58
+ "name": "top",
59
+ "description": "absolute/fixed 时为 top;否则为 margin-top。"
60
+ },
61
+ {
62
+ "name": "left",
63
+ "description": "absolute/fixed 时为 left;否则为 margin-left。"
64
+ },
65
+ {
66
+ "name": "right",
67
+ "description": "absolute/fixed 时为 right;否则为 margin-right。"
68
+ },
69
+ {
70
+ "name": "bottom",
71
+ "description": "absolute/fixed 时为 bottom;否则为 margin-bottom。"
72
+ },
73
+ {
74
+ "name": "zIndex",
75
+ "description": "z-index 层叠顺序。"
76
+ },
77
+ {
78
+ "name": "pointer",
79
+ "description": "为 true 时 cursor: pointer。未设置且存在 onClick 时也会显示手型光标。"
80
+ },
81
+ {
82
+ "name": "flex",
83
+ "description": "为 true 时 display: flex。"
84
+ },
85
+ {
86
+ "name": "column",
87
+ "description": "flex 为 true 时设置 flex-direction: column。"
88
+ },
89
+ {
90
+ "name": "center",
91
+ "description": "flex 为 true 时水平垂直居中;否则 text-align: center。"
92
+ },
93
+ {
94
+ "name": "text",
95
+ "description": "字号,数值经 calc 换算为 font-size。"
96
+ },
97
+ {
98
+ "name": "bold",
99
+ "description": "为 true 时 font-weight: bold。"
100
+ },
101
+ {
102
+ "name": "color",
103
+ "description": "文字颜色。以 -- 开头时使用 var(--xxx)。"
104
+ },
105
+ {
106
+ "name": "bgColor",
107
+ "description": "背景色。以 -- 开头时使用 var(--xxx)。"
108
+ },
109
+ {
110
+ "name": "radius",
111
+ "description": "圆角 border-radius,数值经 calc 换算。"
112
+ },
113
+ {
114
+ "name": "border",
115
+ "description": "边框宽度,数值经 calc 换算;与 borderColor 组合为 solid 边框。"
116
+ },
117
+ {
118
+ "name": "borderColor",
119
+ "description": "边框颜色,默认 #000;以 -- 开头时使用 var(--xxx)。仅设 borderColor 时只改 border-color。"
120
+ },
121
+ {
122
+ "name": "textEllipsis",
123
+ "description": "文本省略:非纯数字时为单行省略;纯数字时为多行省略(-webkit-line-clamp 行数)。"
124
+ },
125
+ {
126
+ "name": "textDot",
127
+ "description": "textEllipsis 的别名,行为相同。"
128
+ },
129
+ {
130
+ "name": "onClick",
131
+ "description": "点击回调:填写挂载在 window 上的函数名字符串;全局 useButtonEffect 为 true 时会附加 click-effect 样式。不推荐使用onClick属性,推荐使用click事件"
132
+ },
133
+ {
134
+ "name": "debug",
135
+ "description": "为 true 时在控制台输出计算后的 layoutStyle。"
136
+ },
137
+ {
138
+ "name": "viewportWidth",
139
+ "description": "覆盖本次样式计算的设计稿基准宽度(默认 750)。"
140
+ },
141
+ {
142
+ "name": "viewportUnit",
143
+ "description": "覆盖数值换算单位(默认 vw)。"
144
+ }
145
+ ],
146
+ "references": [
147
+ {
148
+ "name": "Tdiv 源码",
149
+ "url": "https://codeup.aliyun.com/5ec8bb7bd1d1abe63b55cd33/PC_Web/web-libs/blob/master/dev-helper/Tdiv/index.js"
150
+ }
151
+ ]
152
+ }
153
+ ],
154
+ "valueSets": [
155
+ {
156
+ "name": "tdiv-srcMode",
157
+ "values": [
158
+ {
159
+ "name": "auto",
160
+ "description": "默认,background-size: 100% auto(仅顶部对齐拉伸宽度)。"
161
+ },
162
+ {
163
+ "name": "fill",
164
+ "description": "background-size: 100% 100%,铺满容器。"
165
+ },
166
+ {
167
+ "name": "cover",
168
+ "description": "background-size: cover,等比覆盖。"
169
+ }
170
+ ]
171
+ }
172
+ ]
173
+ }
@@ -48,10 +48,10 @@
48
48
  });
49
49
  }
50
50
  let id = 1;
51
- function defineTag() {
52
- customElements.define(
53
- "open-diandain-app",
54
- class extends HTMLElement {
51
+ const OPEN_DIANDIAN_TAG_NAMES = ['open-diandain-app', 'open-diandian-app'];
52
+
53
+ function createOpenDiandianElementClass() {
54
+ return class extends HTMLElement {
55
55
  static get observedAttributes() {
56
56
  return ['appid', 'extinfo', 'debug', 'scene'];
57
57
  }
@@ -367,8 +367,15 @@
367
367
  this._alink.href = this._alink_link;
368
368
  }
369
369
  }
370
- },
371
- );
370
+ };
371
+ }
372
+
373
+ function defineTag() {
374
+ OPEN_DIANDIAN_TAG_NAMES.forEach((tagName) => {
375
+ if (!customElements.get(tagName)) {
376
+ customElements.define(tagName, createOpenDiandianElementClass());
377
+ }
378
+ });
372
379
  }
373
380
 
374
381
  let isRegister = false;
package/dist/tdiv.umd.js CHANGED
@@ -117,6 +117,13 @@
117
117
  return value !== null && value !== undefined && value !== '';
118
118
  }
119
119
 
120
+ function parseClassTokens(value) {
121
+ if (!value) return [];
122
+ return value.trim().split(/\s+/).filter(Boolean);
123
+ }
124
+
125
+ const RESERVED_CLASS = new Set(['tw-img-div', 'click-effect']);
126
+
120
127
  function calc(value, { usePx, viewportWidth, viewportUnit }) {
121
128
  let vWidth = config.viewportWidth;
122
129
  if (viewportWidth) vWidth = viewportWidth;
@@ -139,10 +146,10 @@
139
146
  class Tdiv extends HTMLElement {
140
147
  static get observedAttributes() {
141
148
  return [
142
- '_class', 'usePx', '_style', 'src', 'width', 'height', 'absolute', 'fixed',
149
+ 'class', '_class', 'usePx', '_style', 'src', 'width', 'height', 'absolute', 'fixed',
143
150
  'top', 'left', 'right', 'bottom', 'zIndex', 'pointer', 'flex', 'column', 'center',
144
151
  'text', 'color', 'radius', 'border', 'borderColor', 'srcMode', 'onClick', 'debug', 'viewportWidth', 'viewportUnit',
145
- 'dot9', 'dot9Border', 'bold', 'textEllipsis', 'bgColor'
152
+ 'dot9', 'dot9Border', 'bold', 'textEllipsis', 'textDot', 'bgColor'
146
153
  ];
147
154
  }
148
155
 
@@ -152,6 +159,8 @@
152
159
  this._connected = false;
153
160
  this._iscalcstyle = false;
154
161
  this._unsubscribe = null;
162
+ this._managedClasses = new Set();
163
+ this._syncingClass = false;
155
164
  }
156
165
 
157
166
  connectedCallback() {
@@ -171,8 +180,9 @@
171
180
  }
172
181
  }
173
182
 
174
- attributeChangedCallback() {
183
+ attributeChangedCallback(name) {
175
184
  if (!this._connected) return;
185
+ if (this._iscalcstyle || this._syncingClass) return;
176
186
  this._update();
177
187
  }
178
188
 
@@ -195,11 +205,48 @@
195
205
  return val;
196
206
  }
197
207
 
208
+ _getUserClassTokens() {
209
+ const tokens = new Set();
210
+ parseClassTokens(this._getAttr('_class') || '').forEach((t) => tokens.add(t));
211
+ parseClassTokens(this.getAttribute('class') || '')
212
+ .filter((t) => !RESERVED_CLASS.has(t))
213
+ .forEach((t) => tokens.add(t));
214
+ return tokens;
215
+ }
216
+
217
+ _syncClasses(desiredManaged) {
218
+ let changed = false;
219
+ for (const cls of this._managedClasses) {
220
+ if (!desiredManaged.has(cls)) changed = true;
221
+ }
222
+ if (!changed) {
223
+ for (const cls of desiredManaged) {
224
+ if (!this._managedClasses.has(cls)) {
225
+ changed = true;
226
+ break;
227
+ }
228
+ }
229
+ }
230
+ if (!changed) return;
231
+
232
+ this._syncingClass = true;
233
+ try {
234
+ for (const cls of this._managedClasses) {
235
+ if (!desiredManaged.has(cls)) this.classList.remove(cls);
236
+ }
237
+ for (const cls of desiredManaged) {
238
+ this.classList.add(cls);
239
+ }
240
+ this._managedClasses = desiredManaged;
241
+ } finally {
242
+ this._syncingClass = false;
243
+ }
244
+ }
245
+
198
246
  _update() {
199
247
  if (this._iscalcstyle) return;
200
248
  this._iscalcstyle = true;
201
249
  // 读取所有属性
202
- const _class = this._getAttr('_class') || '';
203
250
  const usePx = this._getAttr('usePx', 'boolean');
204
251
  const styleAttr = this._getAttr('_style') || '';
205
252
  const src = this._getAttr('src') || '';
@@ -227,14 +274,15 @@
227
274
  const debug = this._getAttr('debug', 'boolean');
228
275
  const viewportWidth = this._getAttr('viewportWidth', 'number');
229
276
  const viewportUnit = this._getAttr('viewportUnit');
230
- const textEllipsis = this._getAttr('textEllipsis');
277
+ const textEllipsis = this.hasAttribute('textEllipsis')
278
+ ? this._getAttr('textEllipsis')
279
+ : this._getAttr('textDot');
231
280
  let dot9 = (this._getAttr('dot9', 'string') || '').split(" ");
232
281
  let dot9Border = (this._getAttr('dot9Border', 'string') || this._getAttr('dot9', 'string') || '').split(" ");
233
282
 
234
- // class
235
- let extraClass = ['tw-img-div'];
236
- if (_class) extraClass.push(_class);
237
- if (config.useButtonEffect && this._getAttr('onClick')) extraClass.push('click-effect');
283
+ // class(组件托管:tw-img-div、class/_class 空格分拆、click-effect)
284
+ const desiredManaged = new Set(['tw-img-div', ...this._getUserClassTokens()]);
285
+ if (config.useButtonEffect && this._getAttr('onClick')) desiredManaged.add('click-effect');
238
286
  // 分组样式
239
287
  const calcOpt = { usePx, viewportWidth, viewportUnit };
240
288
  let layoutStyle = '';
@@ -362,9 +410,7 @@
362
410
  if (debug) {
363
411
  console.log('layoutStyle', layoutStyle);
364
412
  }
365
- const currentList = Array.from(this.classList);
366
- const classNeeded = extraClass.filter(item => !currentList.includes(item));
367
- this.classList.add(...classNeeded);
413
+ this._syncClasses(desiredManaged);
368
414
  this.style.cssText = layoutStyle;
369
415
  this._iscalcstyle = false;
370
416
  }
@@ -43,10 +43,10 @@ function resolveTwKit() {
43
43
  });
44
44
  }
45
45
  let id = 1;
46
- function defineTag() {
47
- customElements.define(
48
- "open-diandain-app",
49
- class extends HTMLElement {
46
+ const OPEN_DIANDIAN_TAG_NAMES = ['open-diandain-app', 'open-diandian-app'];
47
+
48
+ function createOpenDiandianElementClass() {
49
+ return class extends HTMLElement {
50
50
  static get observedAttributes() {
51
51
  return ['appid', 'extinfo', 'debug', 'scene'];
52
52
  }
@@ -362,8 +362,15 @@ function defineTag() {
362
362
  this._alink.href = this._alink_link;
363
363
  }
364
364
  }
365
- },
366
- );
365
+ };
366
+ }
367
+
368
+ function defineTag() {
369
+ OPEN_DIANDIAN_TAG_NAMES.forEach((tagName) => {
370
+ if (!customElements.get(tagName)) {
371
+ customElements.define(tagName, createOpenDiandianElementClass());
372
+ }
373
+ });
367
374
  }
368
375
 
369
376
  let isRegister = false;
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "@taole/dev-helper",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "type": "module",
5
+ "bin": {
6
+ "dev-helper": "./bin/dev-helper.js"
7
+ },
5
8
  "scripts": {
6
9
  "build": "npx -y rimraf dist && rollup -c",
10
+ "postinstall": "node ./bin/dev-helper.js postinstall",
7
11
  "test": "echo \"Error: no test specified\" && exit 1"
8
12
  },
9
13
  "keywords": [],
@@ -14,7 +18,9 @@
14
18
  "files": [
15
19
  "Tdiv",
16
20
  "open-diandian",
17
- "dist"
21
+ "dist",
22
+ "custom-data",
23
+ "bin"
18
24
  ],
19
25
  "author": "",
20
26
  "license": "ISC",
package/Tdiv/index.svelte DELETED
@@ -1,314 +0,0 @@
1
- <script>
2
- import { createEventDispatcher } from "svelte";
3
- import setting from "./setting";
4
-
5
- /**
6
- * @type {string}
7
- * 传入的class请务必放在global下
8
- */
9
- export let _class = "";
10
-
11
- /**
12
- * @type {boolean}
13
- * 默认false, 传入true表示直接使用px单位,一般使用场景比如pc
14
- */
15
- export let usePx = null;
16
-
17
- /**
18
- * @type {string}
19
- * 请不要传入数值相关的style, 因为这部分不会被转换成vw单位
20
- */
21
- export let style = "";
22
-
23
- /**
24
- * @type {string}
25
- * 图片地址
26
- * 传入完整url或者path,组件会自动拼上`https://dynamics-share.tuwan.com/${src}?x-oss-process=image/format,webp/ignore-error,1`
27
- */
28
- export let src = "";
29
- /**
30
- * @type {number|string}
31
- * 宽度
32
- */
33
- export let width = null;
34
- /**
35
- * @type {number|string}
36
- * 高度
37
- */
38
- export let height = null;
39
- /**
40
- * @type {boolean}
41
- * 使用绝对布局, false则为相对布局
42
- */
43
- export let absolute = false;
44
-
45
- /**
46
- * @type {number|string}
47
- * 绝对布局下为top,相对布局下为margin-top
48
- */
49
- export let top = null;
50
- /**
51
- * @type {number|string}
52
- * 绝对布局下为left,相对布局下为margin-left
53
- */
54
- export let left = null;
55
- /**
56
- * @type {number|string}
57
- * 绝对布局下为right,相对布局下为margin-right
58
- */
59
- export let right = null;
60
- /**
61
- * @type {number|string}
62
- * 绝对布局下为bottom,相对布局下为margin-bottom
63
- */
64
- export let bottom = null;
65
- /**
66
- * @type {number}
67
- * z-index层级
68
- */
69
- export let zIndex = null;
70
- /**
71
- * @type {boolean}
72
- * cursor:pointer
73
- */
74
- export let pointer = null;
75
- /**
76
- * @type {boolean}
77
- * 使用flex布局
78
- */
79
- export let flex = false;
80
- /**
81
- * @type {boolean}
82
- * flex布局下,flex-direction:column
83
- */
84
- export let column = false;
85
- /**
86
- * @type {boolean}
87
- * flex布局下,align-items:center;justify-content: center;
88
- */
89
- export let center = false;
90
- /**
91
- * @type {number|string}
92
- * 内部文本的大小
93
- */
94
- export let text = null;
95
- /**
96
- * @type {string}
97
- * 内部文本的颜色
98
- */
99
- export let color = "";
100
-
101
- /**
102
- * @type {number|string}
103
- * 圆角大小
104
- */
105
- export let radius = null;
106
-
107
- /**
108
- * @type {string}
109
- * 边框宽度
110
- */
111
- export let border = null;
112
-
113
- /**
114
- * @type {string}
115
- * 边框颜色
116
- */
117
- export let borderColor = null;
118
-
119
-
120
- /**
121
- * @type {'auto'|'fill'|'cover'|'contain'}
122
- * src传入时有效, 图片的填充模式: 默认auto
123
- * - fill: 长款拉伸填充
124
- * - auto: 自动填充(按照宽高比自动填充, 不重复不裁剪)
125
- * - cover: 覆盖
126
- * - contain: 包含
127
- */
128
- export let srcMode = "auto";
129
-
130
- /**
131
- * @type {(e) => void}
132
- * 点击事件监听
133
- * - onClick 使用onClick将会自动设置cursor:pointer样式
134
- * - on:click 不会
135
- */
136
- export let onClick = null;
137
-
138
- /**
139
- * @type {boolean}
140
- * 打开后,属性变化的时候会打印最终的所有style
141
- */
142
- export let debug = false;
143
-
144
- // 留个口子
145
- export let viewportWidth = undefined;
146
- export let viewportUnit = undefined;
147
-
148
- const dispatch = createEventDispatcher();
149
-
150
- /**
151
- * 计算宽高
152
- * @param value
153
- * @returns {string}
154
- */
155
- function calc(value) {
156
- let vWidth = setting.viewportWidth;
157
- if(viewportWidth){
158
- vWidth = viewportWidth;
159
- }
160
- let vUnit = setting.viewportUnit;
161
- if(viewportUnit){
162
- vUnit = viewportUnit;
163
- }
164
- let localUsePx = setting.usePx;
165
- if(typeof usePx === 'boolean'){
166
- localUsePx = usePx;
167
- }
168
- // @ts-ignore
169
- if (typeof value === "string" && !isNaN(value)) {
170
- value = Number(value);
171
- }
172
- if (typeof value === "number") {
173
- if (localUsePx) {
174
- return value + "px";
175
- }
176
- let val = ((value / vWidth) * 100).toFixed(4); // 4?
177
- return `${val}${vUnit}`;
178
- }
179
- return value;
180
- }
181
-
182
- function handleOnClick(e) {
183
- if(typeof onClick === 'function'){
184
- onClick(e);
185
- }
186
- dispatch("click", e);
187
- }
188
-
189
- function hasValue(value) {
190
- return value !== null && value !== undefined && value !== "";
191
- }
192
-
193
- // 计算最终样式
194
- $: styleStr = (function fmtStyle() {
195
- let ret = "";
196
- if (hasValue(width)) {
197
- ret += `width: ${calc(width)};`;
198
- }
199
- if (hasValue(height)) {
200
- ret += `height: ${calc(height)};`;
201
- }
202
- if (absolute) {
203
- ret += `position: absolute;`;
204
- if (hasValue(left)) {
205
- ret += `left: ${calc(left)};`;
206
- }
207
- if (hasValue(top)) {
208
- ret += `top: ${calc(top)};`;
209
- }
210
- if (hasValue(right)) {
211
- ret += `right: ${calc(right)};`;
212
- }
213
- if (hasValue(bottom)) {
214
- ret += `bottom: ${calc(bottom)};`;
215
- }
216
- } else {
217
- ret += `position: relative;`;
218
- if (hasValue(top)) {
219
- ret += `margin-top: ${calc(top)};`;
220
- }
221
- if (hasValue(left)) {
222
- ret += `margin-left: ${calc(left)};`;
223
- }
224
- if (hasValue(right)) {
225
- ret += `margin-right: ${calc(right)};`;
226
- }
227
- if (hasValue(bottom)) {
228
- ret += `margin-bottom: ${calc(bottom)};`;
229
- }
230
- }
231
- if(hasValue(radius)){
232
- ret += `border-radius: ${calc(radius)};`;
233
- }
234
- if(hasValue(border)){
235
- ret += `border: ${calc(border)} solid ${borderColor || "#000"};`;
236
- } else if(hasValue(borderColor)){
237
- ret += `border-color: ${borderColor};`;
238
- }
239
-
240
- if (hasValue(zIndex)) {
241
- ret += `z-index: ${zIndex};`;
242
- }
243
- if (pointer === true) {
244
- ret += `cursor: pointer;`;
245
- } else if(typeof onClick === "function" && pointer === null){
246
- ret += `cursor: pointer;`;
247
- }
248
- if (flex) {
249
- ret += "display:flex;";
250
- if (column) {
251
- ret += "flex-direction: column;";
252
- }
253
- if (center) {
254
- ret += "justify-content: center;";
255
- ret += "align-items: center;";
256
- }
257
- } else {
258
- if (center) {
259
- ret += "text-align: center;";
260
- }
261
- }
262
- if (text) {
263
- ret += `font-size: ${calc(text)};`;
264
- }
265
- if (src) {
266
- let realSrc = src;
267
- if(src.indexOf("data:") === 0){
268
- realSrc = src;
269
- }else if (src.indexOf("https://") === -1) {
270
- realSrc = `https://dynamics-share.tuwan.com/${src}?x-oss-process=image/format,webp/ignore-error,1`;
271
- }
272
- ret += `background-image: url(${realSrc});`;
273
- if (srcMode === "fill") {
274
- ret += `background-size: 100% 100%;`;
275
- } else if (srcMode === "cover") {
276
- ret += `background-size: cover;`;
277
- }else if (srcMode === "contain") {
278
- ret += `background-size: contain;`;
279
- }
280
- }
281
- if (color) {
282
- ret += `color: ${color};`;
283
- }
284
- if (style) {
285
- ret += style;
286
- }
287
- if (debug) {
288
- console.log("styleStr", ret);
289
- }
290
- return ret;
291
- })();
292
- </script>
293
-
294
- <div
295
- role="presentation"
296
- on:click={handleOnClick}
297
- class="tw-img-div {_class} {setting.useButtonEffect && onClick ? 'click-effect' : ''}"
298
- style={styleStr}
299
- >
300
- <slot />
301
- </div>
302
-
303
- <style scoped>
304
- .tw-img-div {
305
- background-position: top center;
306
- background-repeat: no-repeat;
307
- background-size: 100% auto;
308
- flex: none;
309
- }
310
- .click-effect:active {
311
- opacity: 0.85;
312
- transform: translateY(1px);
313
- }
314
- </style>
package/Tdiv/index.vue DELETED
@@ -1,150 +0,0 @@
1
- <template>
2
- <div role="presentation" :class="['tw-img-div', _class, setting.useButtonEffect && onClick ? 'click-effect' : '']" :style="styleStr" @click="handleOnClick">
3
- <slot />
4
- </div>
5
- </template>
6
-
7
- <script>
8
- import setting from "./setting";
9
-
10
- export default {
11
- name: 'Tdiv',
12
- props: {
13
- _class: { type: String, default: '' },
14
- usePx: { type: Boolean, default: null },
15
- style: { type: String, default: '' },
16
- src: { type: String, default: '' },
17
- width: { type: [Number, String], default: null },
18
- height: { type: [Number, String], default: null },
19
- absolute: { type: Boolean, default: false },
20
- top: { type: [Number, String], default: null },
21
- left: { type: [Number, String], default: null },
22
- right: { type: [Number, String], default: null },
23
- bottom: { type: [Number, String], default: null },
24
- zIndex: { type: [Number, String], default: null },
25
- pointer: { type: Boolean, default: null },
26
- flex: { type: Boolean, default: false },
27
- column: { type: Boolean, default: false },
28
- center: { type: Boolean, default: false },
29
- text: { type: [Number, String], default: null },
30
- color: { type: String, default: '' },
31
- radius: { type: [Number, String], default: null },
32
- border: { type: [Number, String], default: null },
33
- borderColor: { type: String, default: null },
34
- srcMode: { type: String, default: 'auto' },
35
- onClick: { type: Function, default: null },
36
- debug: { type: Boolean, default: false },
37
- viewportWidth: { type: Number, default: null },
38
- viewportUnit: { type: String, default: null },
39
- },
40
- data() {
41
- return {
42
- setting,
43
- };
44
- },
45
- computed: {
46
- styleStr() {
47
- let vWidth = setting.viewportWidth;
48
- if (this.viewportWidth) {
49
- vWidth = this.viewportWidth;
50
- }
51
- let vUnit = setting.viewportUnit;
52
- if (this.viewportUnit) {
53
- vUnit = this.viewportUnit;
54
- }
55
- let localUsePx = setting.usePx;
56
- if (typeof this.usePx === 'boolean') {
57
- localUsePx = this.usePx;
58
- }
59
- const calc = (value) => {
60
-
61
- if (typeof value === 'string' && !isNaN(value)) value = Number(value);
62
- if (typeof value === 'number') {
63
- if (localUsePx) return value + 'px';
64
- let val = ((value / vWidth) * 100).toFixed(4);
65
- return `${val}${vUnit}`;
66
- }
67
- return value;
68
- };
69
- const hasValue = (value) => value !== null && value !== undefined && value !== '';
70
- let ret = '';
71
- if (hasValue(this.width)) ret += `width: ${calc(this.width)};`;
72
- if (hasValue(this.height)) ret += `height: ${calc(this.height)};`;
73
- if (this.absolute) {
74
- ret += 'position: absolute;';
75
- if (hasValue(this.left)) ret += `left: ${calc(this.left)};`;
76
- if (hasValue(this.top)) ret += `top: ${calc(this.top)};`;
77
- if (hasValue(this.right)) ret += `right: ${calc(this.right)};`;
78
- if (hasValue(this.bottom)) ret += `bottom: ${calc(this.bottom)};`;
79
- } else {
80
- ret += 'position: relative;';
81
- if (hasValue(this.top)) ret += `margin-top: ${calc(this.top)};`;
82
- if (hasValue(this.left)) ret += `margin-left: ${calc(this.left)};`;
83
- if (hasValue(this.right)) ret += `margin-right: ${calc(this.right)};`;
84
- if (hasValue(this.bottom)) ret += `margin-bottom: ${calc(this.bottom)};`;
85
- }
86
- if (hasValue(this.radius)) ret += `border-radius: ${calc(this.radius)};`;
87
- if (hasValue(this.border)) {
88
- ret += `border: ${calc(this.border)} solid ${this.borderColor || "#000"};`;
89
- } else if(hasValue(this.borderColor)){
90
- ret += `border-color: ${this.borderColor};`;
91
- }
92
- if (hasValue(this.zIndex)) ret += `z-index: ${this.zIndex};`;
93
- if (this.pointer === true) {
94
- ret += 'cursor: pointer;';
95
- } else if (typeof this.onClick === 'function' && this.pointer === null) {
96
- ret += 'cursor: pointer;';
97
- }
98
- if (this.flex) {
99
- ret += 'display:flex;';
100
- if (this.column) ret += 'flex-direction: column;';
101
- if (this.center) {
102
- ret += 'justify-content: center;';
103
- ret += 'align-items: center;';
104
- }
105
- } else {
106
- if (this.center) ret += 'text-align: center;';
107
- }
108
- if (this.text) ret += `font-size: ${calc(this.text)};`;
109
- if (this.src) {
110
- let realSrc = this.src;
111
- if (this.src.indexOf('https://') === -1) {
112
- realSrc = `https://dynamics-share.tuwan.com/${this.src}?x-oss-process=image/format,webp/ignore-error,1`;
113
- }
114
- ret += `background-image: url(${realSrc});`;
115
- if (this.srcMode === 'fill') {
116
- ret += 'background-size: 100% 100%;';
117
- } else if (this.srcMode === 'cover') {
118
- ret += 'background-size: cover;';
119
- }
120
- }
121
- if (this.color) ret += `color: ${this.color};`;
122
- if (this.style) ret += this.style;
123
- if (this.debug) console.log('styleStr', ret);
124
- return ret;
125
- },
126
- },
127
- methods: {
128
- handleOnClick(e) {
129
- if (typeof this.onClick === 'function') {
130
- this.onClick(e);
131
- }
132
- this.$emit('click', e);
133
- },
134
- },
135
- };
136
- </script>
137
-
138
- <style scoped>
139
- .tw-img-div {
140
- background-position: top center;
141
- background-repeat: no-repeat;
142
- background-size: 100% auto;
143
- flex: none;
144
- }
145
-
146
- .click-effect:active {
147
- opacity: 0.85;
148
- transform: translateY(1px);
149
- }
150
- </style>