@ikun2274/spiritechoui 0.1.35 → 0.1.40

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.
@@ -4,7 +4,7 @@ var __publicField = (obj, key, value) => {
4
4
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  return value;
6
6
  };
7
- import { openBlock, createElementBlock, normalizeClass, normalizeStyle, renderSlot, createElementVNode, toDisplayString } from "vue";
7
+ import { openBlock, createElementBlock, normalizeClass, normalizeStyle, renderSlot, createElementVNode, toDisplayString, defineComponent, withDirectives, vModelDynamic } from "vue";
8
8
  class MyUI {
9
9
  /**
10
10
  * 支持 app.use(MyUI) 注册的静态方法
@@ -59,7 +59,7 @@ const _export_sfc = (sfc, props) => {
59
59
  }
60
60
  return target;
61
61
  };
62
- const _sfc_main = {
62
+ const _sfc_main$1 = {
63
63
  props: {
64
64
  // 文本样式类型
65
65
  textType: {
@@ -106,8 +106,8 @@ const _sfc_main = {
106
106
  }
107
107
  }
108
108
  };
109
- const _hoisted_1 = ["disabled"];
110
- function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
109
+ const _hoisted_1$1 = ["disabled"];
110
+ function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
111
111
  return openBlock(), createElementBlock("button", {
112
112
  class: normalizeClass(["SpiritEchoBtn", [
113
113
  `SpiritEchoBtn--${$props.type}`,
@@ -124,16 +124,155 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
124
124
  style: normalizeStyle($props.textStyle)
125
125
  }, toDisplayString($props.text), 7)
126
126
  ])
127
- ], 14, _hoisted_1);
127
+ ], 14, _hoisted_1$1);
128
+ }
129
+ const myButton = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render$1]]);
130
+ const _sfc_main = defineComponent({
131
+ name: "SpInput",
132
+ props: {
133
+ modelValue: {
134
+ type: [String, Number],
135
+ default: ""
136
+ },
137
+ type: {
138
+ type: String,
139
+ default: "text"
140
+ },
141
+ placeholder: { type: String, default: "" },
142
+ disabled: { type: Boolean, default: false },
143
+ maxlength: {
144
+ type: Number,
145
+ default: void 0
146
+ },
147
+ name: { type: String, default: "" },
148
+ readonly: { type: Boolean, default: false },
149
+ // 新增:校验规则
150
+ rules: {
151
+ type: Object,
152
+ default: () => ({})
153
+ // 默认空对象,不影响原有使用
154
+ },
155
+ // 新增:自定义校验函数(被动触发)
156
+ customValidator: {
157
+ type: Function,
158
+ default: void 0
159
+ }
160
+ },
161
+ data() {
162
+ return {
163
+ inputLength: 0,
164
+ inputValue: this.modelValue + ""
165
+ //
166
+ };
167
+ },
168
+ emits: [
169
+ "update:modelValue",
170
+ "focus",
171
+ "blur",
172
+ "change",
173
+ "validateResult"
174
+ // "cca",
175
+ ],
176
+ created() {
177
+ },
178
+ watch: {
179
+ inputValue(newVal) {
180
+ console.log("子组件emit的值:", newVal);
181
+ this.inputLength = newVal.length;
182
+ this.$emit("update:modelValue", newVal);
183
+ this.doValidate(newVal);
184
+ }
185
+ },
186
+ methods: {
187
+ // 新增:核心校验方法(被动触发,逻辑和之前一致)
188
+ doValidate(val) {
189
+ let result = { isValid: true, message: "" };
190
+ const { rules, customValidator } = this;
191
+ if (rules) {
192
+ const finalMaxlength = rules.maxlength ?? this.maxlength;
193
+ if (finalMaxlength !== void 0 && val.length > finalMaxlength) {
194
+ result = {
195
+ isValid: false,
196
+ message: `输入不能/超过/exceed/${finalMaxlength}位`
197
+ };
198
+ }
199
+ if (rules.minlength !== void 0 && val.length < rules.minlength) {
200
+ result = {
201
+ isValid: false,
202
+ message: `输入不能少于${rules.minlength}位`
203
+ };
204
+ }
205
+ if (rules.type) {
206
+ switch (rules.type) {
207
+ case "number":
208
+ if (!/^\d+$/.test(val))
209
+ result = { isValid: false, message: "请输入纯数字" };
210
+ break;
211
+ case "letter":
212
+ if (!/^[a-zA-Z]+$/.test(val))
213
+ result = { isValid: false, message: "请输入纯字母" };
214
+ break;
215
+ case "mixed":
216
+ if (!/^[a-zA-Z0-9]+$/.test(val))
217
+ result = { isValid: false, message: "请输入字母+数字组合" };
218
+ break;
219
+ }
220
+ }
221
+ if (rules.pattern && val) {
222
+ let reg;
223
+ if (typeof rules.pattern === "string") {
224
+ reg = new RegExp(rules.pattern, rules.patternFlags);
225
+ } else {
226
+ reg = rules.pattern;
227
+ }
228
+ if (!reg.test(val)) {
229
+ result = {
230
+ isValid: false,
231
+ // 优先用自定义提示,否则用默认文案
232
+ message: rules.patternMessage || "输入格式不正确"
233
+ };
234
+ }
235
+ }
236
+ }
237
+ if (result.isValid && customValidator) {
238
+ result = customValidator(val);
239
+ }
240
+ this.$emit("validateResult", result);
241
+ }
242
+ }
243
+ });
244
+ const SpInput_vue_vue_type_style_index_0_lang = "";
245
+ const _hoisted_1 = { class: "SPInput-container" };
246
+ const _hoisted_2 = ["type", "placeholder", "disabled", "maxlength", "name", "readonly"];
247
+ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
248
+ return openBlock(), createElementBlock("div", _hoisted_1, [
249
+ withDirectives(createElementVNode("input", {
250
+ type: _ctx.type,
251
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => _ctx.inputValue = $event),
252
+ placeholder: _ctx.placeholder,
253
+ disabled: _ctx.disabled,
254
+ maxlength: _ctx.maxlength,
255
+ name: _ctx.name,
256
+ readonly: _ctx.readonly,
257
+ onFocus: _cache[1] || (_cache[1] = ($event) => _ctx.$emit("focus", $event)),
258
+ onBlur: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("blur", $event)),
259
+ onChange: _cache[3] || (_cache[3] = ($event) => _ctx.$emit("change", $event)),
260
+ class: "SPInput"
261
+ }, null, 40, _hoisted_2), [
262
+ [vModelDynamic, _ctx.inputValue]
263
+ ])
264
+ ]);
128
265
  }
129
- const myButton = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
266
+ const myinput = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
130
267
  const injector = new ComponentInjector(MyUI);
131
268
  injector.register("form", "myButton", myButton, {
132
269
  type: "default",
133
270
  size: "medium"
134
271
  });
272
+ injector.register("form", "myinput", myinput);
135
273
  MyUI.install = (app) => {
136
- app.component("MyButton", MyUI.form.myButton({}));
274
+ app.component("SPE-Button", MyUI.form.myButton({}));
275
+ app.component("SPE-Input", MyUI.form.myinput({}));
137
276
  };
138
277
  export {
139
278
  MyUI
@@ -1,5 +1,5 @@
1
1
  (function(global, factory) {
2
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("vue")) : typeof define === "function" && define.amd ? define(["exports", "vue"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.MyCustomUI = {}, global.Vue));
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("vue")) : typeof define === "function" && define.amd ? define(["exports", "vue"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.SpiritEchoUI = {}, global.Vue));
3
3
  })(this, function(exports2, vue) {
4
4
  "use strict";var __defProp = Object.defineProperty;
5
5
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -62,7 +62,7 @@ var __publicField = (obj, key, value) => {
62
62
  }
63
63
  return target;
64
64
  };
65
- const _sfc_main = {
65
+ const _sfc_main$1 = {
66
66
  props: {
67
67
  // 文本样式类型
68
68
  textType: {
@@ -109,8 +109,8 @@ var __publicField = (obj, key, value) => {
109
109
  }
110
110
  }
111
111
  };
112
- const _hoisted_1 = ["disabled"];
113
- function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
112
+ const _hoisted_1$1 = ["disabled"];
113
+ function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
114
114
  return vue.openBlock(), vue.createElementBlock("button", {
115
115
  class: vue.normalizeClass(["SpiritEchoBtn", [
116
116
  `SpiritEchoBtn--${$props.type}`,
@@ -127,16 +127,155 @@ var __publicField = (obj, key, value) => {
127
127
  style: vue.normalizeStyle($props.textStyle)
128
128
  }, vue.toDisplayString($props.text), 7)
129
129
  ])
130
- ], 14, _hoisted_1);
130
+ ], 14, _hoisted_1$1);
131
+ }
132
+ const myButton = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render$1]]);
133
+ const _sfc_main = vue.defineComponent({
134
+ name: "SpInput",
135
+ props: {
136
+ modelValue: {
137
+ type: [String, Number],
138
+ default: ""
139
+ },
140
+ type: {
141
+ type: String,
142
+ default: "text"
143
+ },
144
+ placeholder: { type: String, default: "" },
145
+ disabled: { type: Boolean, default: false },
146
+ maxlength: {
147
+ type: Number,
148
+ default: void 0
149
+ },
150
+ name: { type: String, default: "" },
151
+ readonly: { type: Boolean, default: false },
152
+ // 新增:校验规则
153
+ rules: {
154
+ type: Object,
155
+ default: () => ({})
156
+ // 默认空对象,不影响原有使用
157
+ },
158
+ // 新增:自定义校验函数(被动触发)
159
+ customValidator: {
160
+ type: Function,
161
+ default: void 0
162
+ }
163
+ },
164
+ data() {
165
+ return {
166
+ inputLength: 0,
167
+ inputValue: this.modelValue + ""
168
+ //
169
+ };
170
+ },
171
+ emits: [
172
+ "update:modelValue",
173
+ "focus",
174
+ "blur",
175
+ "change",
176
+ "validateResult"
177
+ // "cca",
178
+ ],
179
+ created() {
180
+ },
181
+ watch: {
182
+ inputValue(newVal) {
183
+ console.log("子组件emit的值:", newVal);
184
+ this.inputLength = newVal.length;
185
+ this.$emit("update:modelValue", newVal);
186
+ this.doValidate(newVal);
187
+ }
188
+ },
189
+ methods: {
190
+ // 新增:核心校验方法(被动触发,逻辑和之前一致)
191
+ doValidate(val) {
192
+ let result = { isValid: true, message: "" };
193
+ const { rules, customValidator } = this;
194
+ if (rules) {
195
+ const finalMaxlength = rules.maxlength ?? this.maxlength;
196
+ if (finalMaxlength !== void 0 && val.length > finalMaxlength) {
197
+ result = {
198
+ isValid: false,
199
+ message: `输入不能/超过/exceed/${finalMaxlength}位`
200
+ };
201
+ }
202
+ if (rules.minlength !== void 0 && val.length < rules.minlength) {
203
+ result = {
204
+ isValid: false,
205
+ message: `输入不能少于${rules.minlength}位`
206
+ };
207
+ }
208
+ if (rules.type) {
209
+ switch (rules.type) {
210
+ case "number":
211
+ if (!/^\d+$/.test(val))
212
+ result = { isValid: false, message: "请输入纯数字" };
213
+ break;
214
+ case "letter":
215
+ if (!/^[a-zA-Z]+$/.test(val))
216
+ result = { isValid: false, message: "请输入纯字母" };
217
+ break;
218
+ case "mixed":
219
+ if (!/^[a-zA-Z0-9]+$/.test(val))
220
+ result = { isValid: false, message: "请输入字母+数字组合" };
221
+ break;
222
+ }
223
+ }
224
+ if (rules.pattern && val) {
225
+ let reg;
226
+ if (typeof rules.pattern === "string") {
227
+ reg = new RegExp(rules.pattern, rules.patternFlags);
228
+ } else {
229
+ reg = rules.pattern;
230
+ }
231
+ if (!reg.test(val)) {
232
+ result = {
233
+ isValid: false,
234
+ // 优先用自定义提示,否则用默认文案
235
+ message: rules.patternMessage || "输入格式不正确"
236
+ };
237
+ }
238
+ }
239
+ }
240
+ if (result.isValid && customValidator) {
241
+ result = customValidator(val);
242
+ }
243
+ this.$emit("validateResult", result);
244
+ }
245
+ }
246
+ });
247
+ const SpInput_vue_vue_type_style_index_0_lang = "";
248
+ const _hoisted_1 = { class: "SPInput-container" };
249
+ const _hoisted_2 = ["type", "placeholder", "disabled", "maxlength", "name", "readonly"];
250
+ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
251
+ return vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
252
+ vue.withDirectives(vue.createElementVNode("input", {
253
+ type: _ctx.type,
254
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => _ctx.inputValue = $event),
255
+ placeholder: _ctx.placeholder,
256
+ disabled: _ctx.disabled,
257
+ maxlength: _ctx.maxlength,
258
+ name: _ctx.name,
259
+ readonly: _ctx.readonly,
260
+ onFocus: _cache[1] || (_cache[1] = ($event) => _ctx.$emit("focus", $event)),
261
+ onBlur: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("blur", $event)),
262
+ onChange: _cache[3] || (_cache[3] = ($event) => _ctx.$emit("change", $event)),
263
+ class: "SPInput"
264
+ }, null, 40, _hoisted_2), [
265
+ [vue.vModelDynamic, _ctx.inputValue]
266
+ ])
267
+ ]);
131
268
  }
132
- const myButton = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
269
+ const myinput = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
133
270
  const injector = new ComponentInjector(MyUI);
134
271
  injector.register("form", "myButton", myButton, {
135
272
  type: "default",
136
273
  size: "medium"
137
274
  });
275
+ injector.register("form", "myinput", myinput);
138
276
  MyUI.install = (app) => {
139
- app.component("MyButton", MyUI.form.myButton({}));
277
+ app.component("SPE-Button", MyUI.form.myButton({}));
278
+ app.component("SPE-Input", MyUI.form.myinput({}));
140
279
  };
141
280
  exports2.MyUI = MyUI;
142
281
  Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
package/dist/style.css CHANGED
@@ -82,4 +82,28 @@
82
82
  }
83
83
  .SpiritEchoBtn:not(.SpiritEchoBtn--disabled):active {
84
84
  transform: translateY(0);
85
+ }.SPInput-container {
86
+ width: 100%;
87
+ }
88
+ .SPInput {
89
+ width: 100%;
90
+ padding: 8px 12px;
91
+ height: 40px;
92
+ border: 2px solid #c3bfbf;
93
+ border-radius: 4px;
94
+ font-size: 14px;
95
+ box-sizing: border-box;
96
+ background-color: rgba(255, 255, 255, 0.968627451);
97
+ }
98
+ .SPInput:focus {
99
+ outline: none;
100
+ border-color: #4096ff;
101
+ }
102
+ .SPInput:disabled {
103
+ background-color: #f5f7fa;
104
+ cursor: not-allowed;
105
+ opacity: 0.8;
106
+ }
107
+ .SPInput:read-only {
108
+ background-color: #f5f7fa;
85
109
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikun2274/spiritechoui",
3
- "version": "0.1.35",
3
+ "version": "0.1.40",
4
4
  "main": "dist/spiritechoui.umd.cjs",
5
5
  "module": "dist/spiritechoui.es.js",
6
6
  "exports": {
@@ -14,9 +14,12 @@
14
14
  "vue": "^3.0.0"
15
15
  },
16
16
  "devDependencies": {
17
+ "@types/node": "^24.10.1",
17
18
  "@vitejs/plugin-vue": "^4.2.3",
19
+ "typescript": "^5.9.3",
18
20
  "vite": "^4.4.9",
19
- "vue": "^3.3.4"
21
+ "vue": "^3.3.4",
22
+ "vue-tsc": "^3.1.3"
20
23
  },
21
24
  "scripts": {
22
25
  "build": "vite build"
@@ -26,6 +29,6 @@
26
29
  "license": "ISC",
27
30
  "description": "",
28
31
  "dependencies": {
29
- "@ikun2274/spiritechoui": "^0.1.2"
32
+ "log": "^6.3.2"
30
33
  }
31
34
  }
package/readme.md CHANGED
@@ -1,12 +1,21 @@
1
1
  # 我的第一个UI组件库 SpiritEchoUI
2
2
 
3
+ ### 目前还是0.1.36版本
4
+
3
5
 
4
6
  ## 安装组件
5
7
 
6
8
  ```
7
9
  npm install @ikun2274/spiritechoui
8
10
  ```
9
- npm uninstall @ikun2274/spiritechoui
11
+
12
+ ## 卸载组件
13
+
14
+
15
+ ```
16
+ npm uninstall @ikun2274/spiritechoui
17
+ ```
18
+
10
19
  ## 更新日志
11
20
 
12
21
  #### 0.1.3 (2025-11-06-13:25)
@@ -0,0 +1,214 @@
1
+ <!-- SpInput.vue -->
2
+ <template>
3
+ <div class="SPInput-container">
4
+ <input
5
+ :type="type"
6
+ v-model="inputValue"
7
+ :placeholder="placeholder"
8
+ :disabled="disabled"
9
+ :maxlength="maxlength"
10
+ :name="name"
11
+ :readonly="readonly"
12
+ @focus="$emit('focus', $event)"
13
+ @blur="$emit('blur', $event)"
14
+ @change="$emit('change', $event)"
15
+ class="SPInput" />
16
+ </div>
17
+ </template>
18
+
19
+ <script lang="ts">
20
+ /**
21
+ * @component SpInput
22
+ * @description 带实时校验的输入框组件,支持双向数据绑定、自定义校验规则和函数,适用于表单场景的输入校验需求。
23
+ *
24
+ *
25
+ *
26
+ *
27
+ */
28
+
29
+ import { defineComponent, PropType } from "vue";
30
+ // 定义 rules 类型(和之前一致)
31
+ type InputRules = {
32
+ maxlength?: number;
33
+ minlength?: number;
34
+ type?: "number" | "letter" | "mixed";
35
+ // 新增:自定义正则(支持正则对象/字符串)
36
+ pattern?: RegExp | string;
37
+ // 新增:正则校验失败的提示文案(可选)
38
+ patternMessage?: string;
39
+ // 可选:正则的 flags(比如 i 忽略大小写,g 全局匹配)
40
+ patternFlags?: string;
41
+ };
42
+
43
+ export default defineComponent({
44
+ name: "SpInput",
45
+
46
+ props: {
47
+ modelValue: {
48
+ type: [String, Number] as PropType<string | number>,
49
+ default: "",
50
+ },
51
+ type: {
52
+ type: String as PropType<
53
+ "text" | "password" | "number" | "tel" | "email" | string
54
+ >,
55
+ default: "text",
56
+ },
57
+ placeholder: { type: String, default: "" },
58
+ disabled: { type: Boolean, default: false },
59
+ maxlength: {
60
+ type: Number as PropType<number | undefined>,
61
+ default: undefined,
62
+ },
63
+ name: { type: String, default: "" },
64
+ readonly: { type: Boolean, default: false },
65
+ // 新增:校验规则
66
+ rules: {
67
+ type: Object as PropType<InputRules>,
68
+ default: () => ({}), // 默认空对象,不影响原有使用
69
+ },
70
+ // 新增:自定义校验函数(被动触发)
71
+ customValidator: {
72
+ type: Function as PropType<
73
+ (val: string) => { isValid: boolean; message: string }
74
+ >,
75
+ default: undefined,
76
+ },
77
+ },
78
+
79
+ data() {
80
+ return {
81
+ inputLength: 0,
82
+ inputValue: this.modelValue + "",
83
+ //
84
+ };
85
+ },
86
+
87
+ emits: [
88
+ "update:modelValue",
89
+ "focus",
90
+ "blur",
91
+ "change",
92
+ "validateResult",
93
+ // "cca",
94
+ ],
95
+ created() {},
96
+
97
+ watch: {
98
+ inputValue(newVal) {
99
+ console.log("子组件emit的值:", newVal); // 退格到空时,应输出 ""
100
+
101
+ this.inputLength = newVal.length;
102
+ this.$emit("update:modelValue", newVal);
103
+
104
+ this.doValidate(newVal);
105
+ },
106
+ },
107
+ methods: {
108
+ // 新增:核心校验方法(被动触发,逻辑和之前一致)
109
+ doValidate(val: string) {
110
+ let result = { isValid: true, message: "" };
111
+ const { rules, customValidator } = this;
112
+
113
+ // ① 执行 rules 基础校验(长度、类型)
114
+ if (rules) {
115
+ // 长度校验:rules.maxlength 优先级高于单独传的 maxlength
116
+ const finalMaxlength = rules.maxlength ?? this.maxlength;
117
+ if (finalMaxlength !== undefined && val.length > finalMaxlength) {
118
+ result = {
119
+ isValid: false,
120
+ message: `输入不能/超过/exceed/${finalMaxlength}位`,
121
+ };
122
+ }
123
+ /////////
124
+ if (rules.minlength !== undefined && val.length < rules.minlength) {
125
+ result = {
126
+ isValid: false,
127
+ message: `输入不能少于${rules.minlength}位`,
128
+ };
129
+ }
130
+ //////////////
131
+ // 类型校验(纯数字/纯字母/字母+数字)
132
+ if (rules.type) {
133
+ switch (rules.type) {
134
+ case "number":
135
+ if (!/^\d+$/.test(val))
136
+ result = { isValid: false, message: "请输入纯数字" };
137
+ break;
138
+ case "letter":
139
+ if (!/^[a-zA-Z]+$/.test(val))
140
+ result = { isValid: false, message: "请输入纯字母" };
141
+ break;
142
+ case "mixed":
143
+ if (!/^[a-zA-Z0-9]+$/.test(val))
144
+ result = { isValid: false, message: "请输入字母+数字组合" };
145
+ break;
146
+ }
147
+ }
148
+ //////////
149
+ // ③ 新增:自定义正则校验(优先级高于预设类型)
150
+ if (rules.pattern && val) {
151
+ // 处理正则:如果是字符串,转成 RegExp 对象(支持 flags)
152
+ let reg: RegExp;
153
+ if (typeof rules.pattern === "string") {
154
+ reg = new RegExp(rules.pattern, rules.patternFlags);
155
+ } else {
156
+ reg = rules.pattern;
157
+ }
158
+ // 执行正则校验
159
+ if (!reg.test(val)) {
160
+ result = {
161
+ isValid: false,
162
+ // 优先用自定义提示,否则用默认文案
163
+ message: rules.patternMessage || "输入格式不正确",
164
+ };
165
+ }
166
+ }
167
+
168
+ //////////////
169
+ }
170
+
171
+ // ② 执行父组件传的 customValidator(被动触发,优先级更高)
172
+ if (result.isValid && customValidator) {
173
+ result = customValidator(val);
174
+ }
175
+ ///////////////////////
176
+ // ③ 抛校验结果给父组件(父组件监听这个事件)
177
+ this.$emit("validateResult", result);
178
+ },
179
+ },
180
+ });
181
+ </script>
182
+
183
+ <style lang="scss">
184
+ // 样式保持不变,Sass兼容CSS语法,可直接使用
185
+ .SPInput-container {
186
+ width: 100%;
187
+ }
188
+
189
+ .SPInput {
190
+ width: 100%;
191
+ padding: 8px 12px;
192
+ height: 40px;
193
+ border: 2px solid #c3bfbf;
194
+ border-radius: 4px;
195
+ font-size: 14px;
196
+ box-sizing: border-box;
197
+
198
+ background-color: #fffffff7;
199
+ &:focus {
200
+ outline: none;
201
+ border-color: #4096ff;
202
+ }
203
+
204
+ &:disabled {
205
+ background-color: #f5f7fa;
206
+ cursor: not-allowed;
207
+ opacity: 0.8;
208
+ }
209
+
210
+ &:read-only {
211
+ background-color: #f5f7fa;
212
+ }
213
+ }
214
+ </style>
package/src/index.js CHANGED
@@ -3,4 +3,9 @@ import MyUI from './registerComponents';
3
3
 
4
4
  export { MyUI };
5
5
  // 若需按需导出单个方法,可添加:
6
- // export const myButton = MyUI.myButton;
6
+ // export const myButton = MyUI.myButton;
7
+
8
+
9
+
10
+ //
11
+ // npm run build
@@ -1,30 +1,30 @@
1
1
  // 组件库内部的 registerComponents.js 示例
2
2
  import MyUI from './MyUI';
3
3
  import ComponentInjector from './ComponentInjector';
4
+
5
+ //引入组件
4
6
  import myButton from './components/Button.vue';
7
+ import myinput from './components/SpInput.vue';
5
8
 
6
9
  const injector = new ComponentInjector(MyUI);
10
+
7
11
  injector.register('form', 'myButton', myButton, {
8
12
  type: 'default',
9
13
  size: 'medium'
10
14
  });
11
15
 
12
16
  //假设有第二个组件
17
+ injector.register('form', 'myinput', myinput);
13
18
 
14
- /*
15
- injector.register('form', 'mytext', mytext, {
16
- type: 'default',
17
- size: 'medium'
18
- });
19
-
20
-
21
- */
19
+ //Spirit EchoUI
22
20
 
21
+ //全局激活组件
23
22
 
24
23
  MyUI.install = (app) => {
25
- app.component('MyButton', MyUI.form.myButton({}));
26
- //假设有第二个组件
27
- //app.component('MyText', MyUI.form.mytext({}));
24
+ app.component('SPE-Button', MyUI.form.myButton({}));
25
+ app.component('SPE-Input', MyUI.form.myinput({}));
26
+
27
+
28
28
  };
29
29
 
30
30
  export default MyUI;
@@ -0,0 +1,10 @@
1
+ // src/types/global.d.ts
2
+ import { SpInput } from "../components/SpInput.vue";
3
+ import { Button } from "../components/Button.vue"; // 若有其他组件也需声明
4
+
5
+ declare module "vue" {
6
+ export interface GlobalComponents {
7
+ SpInput: typeof SpInput;
8
+ Button: typeof Button;
9
+ }
10
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "module": "ESNext",
6
+ "moduleResolution": "Node",
7
+ "strict": true,
8
+ "jsx": "preserve",
9
+ "sourceMap": true,
10
+ "resolveJsonModule": true,
11
+ "isolatedModules": true,
12
+ "esModuleInterop": true,
13
+ "lib": ["ES2020", "DOM"],
14
+ "skipLibCheck": true,
15
+ "noEmit": true,
16
+ "allowJs": true, // 允许同时编译 JS 文件
17
+ "vueCompilerOptions": {
18
+ "scriptSetup": true,
19
+ "strictTemplates": true
20
+ }
21
+ },
22
+ "include": ["src/**/*.ts", "src/**/*.vue", "src/types/**/*.d.ts"],
23
+ "exclude": ["node_modules"]
24
+ }
package/vite.config.js CHANGED
@@ -1,4 +1,4 @@
1
- // 组件库的 vite.config.js
1
+ // 组件库的 vite.config.ts
2
2
  import { defineConfig } from 'vite';
3
3
  import vue from '@vitejs/plugin-vue';
4
4
 
@@ -7,7 +7,7 @@ export default defineConfig({
7
7
  build: {
8
8
  lib: {
9
9
  entry: './src/index.js',
10
- name: 'MyCustomUI',
10
+ name: 'SpiritEchoUI',
11
11
  fileName: (format) => `spiritechoui.${format}.js`
12
12
  },
13
13
  rollupOptions: {