@ikun2274/spiritechoui 0.1.34
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/dist/spiritechoui.es.js +140 -0
- package/dist/spiritechoui.umd.js +143 -0
- package/dist/style.css +85 -0
- package/package.json +31 -0
- package/readme.md +21 -0
- package/src/ComponentInjector.js +37 -0
- package/src/MyUI.js +24 -0
- package/src/components/Button.vue +187 -0
- package/src/index.js +6 -0
- package/src/registerComponents.js +30 -0
- package/vite.config.js +31 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => {
|
|
4
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
+
return value;
|
|
6
|
+
};
|
|
7
|
+
import { openBlock, createElementBlock, normalizeClass, normalizeStyle, renderSlot, createElementVNode, toDisplayString } from "vue";
|
|
8
|
+
class MyUI {
|
|
9
|
+
/**
|
|
10
|
+
* 支持 app.use(MyUI) 注册的静态方法
|
|
11
|
+
* @param {import('vue').App} app Vue 应用实例
|
|
12
|
+
* @param {Object} options 可选配置(如自定义组件前缀等)
|
|
13
|
+
*/
|
|
14
|
+
static install(app, options = {}) {
|
|
15
|
+
Object.keys(this).forEach((category) => {
|
|
16
|
+
const components = this[category];
|
|
17
|
+
Object.keys(components).forEach((componentName) => {
|
|
18
|
+
const component = components[componentName]();
|
|
19
|
+
const kebabCaseName = componentName.replace(/[A-Z]/g, "-$&").toLowerCase();
|
|
20
|
+
app.component(kebabCaseName, component);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
class ComponentInjector {
|
|
26
|
+
constructor(target) {
|
|
27
|
+
// 可选:保留原 register 方法,兼容之前的调用习惯(本质和 registerAsSubMethod 一致)
|
|
28
|
+
__publicField(this, "register", this.registerAsSubMethod);
|
|
29
|
+
this.target = target;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 核心方法:注册组件为「分类的下属函数」
|
|
33
|
+
* @param {string} category 分类名称(如 'form',作为主类的属性)
|
|
34
|
+
* @param {string} subMethodName 下属函数名(如 'myButton',作为分类的下属函数)
|
|
35
|
+
* @param {Object} component 组件定义(.vue 文件)
|
|
36
|
+
* @param {Object} defaultOptions 组件默认配置
|
|
37
|
+
*/
|
|
38
|
+
registerAsSubMethod(category, subMethodName, component, defaultOptions = {}) {
|
|
39
|
+
if (!this.target[category]) {
|
|
40
|
+
this.target[category] = {};
|
|
41
|
+
}
|
|
42
|
+
this.target[category][subMethodName] = (registerOptions = {}) => {
|
|
43
|
+
const mergedConfig = { ...defaultOptions, ...registerOptions };
|
|
44
|
+
return {
|
|
45
|
+
...component,
|
|
46
|
+
props: {
|
|
47
|
+
...component.props,
|
|
48
|
+
default: () => mergedConfig
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const Button_vue_vue_type_style_index_0_lang = "";
|
|
55
|
+
const _export_sfc = (sfc, props) => {
|
|
56
|
+
const target = sfc.__vccOpts || sfc;
|
|
57
|
+
for (const [key, val] of props) {
|
|
58
|
+
target[key] = val;
|
|
59
|
+
}
|
|
60
|
+
return target;
|
|
61
|
+
};
|
|
62
|
+
const _sfc_main = {
|
|
63
|
+
props: {
|
|
64
|
+
// 文本样式类型
|
|
65
|
+
textType: {
|
|
66
|
+
type: String,
|
|
67
|
+
default: "default",
|
|
68
|
+
validator: (val) => ["default", "primary", "success", "danger", "warning"].includes(val)
|
|
69
|
+
},
|
|
70
|
+
// 手动注入文本样式
|
|
71
|
+
textStyle: {
|
|
72
|
+
type: Object,
|
|
73
|
+
default: () => ({})
|
|
74
|
+
},
|
|
75
|
+
// 自定义按钮整体样式
|
|
76
|
+
customStyle: {
|
|
77
|
+
type: Object,
|
|
78
|
+
default: () => ({})
|
|
79
|
+
},
|
|
80
|
+
// 按钮类型(控制背景色)
|
|
81
|
+
type: {
|
|
82
|
+
type: String,
|
|
83
|
+
default: "default",
|
|
84
|
+
validator: (val) => ["default", "primary", "success", "danger", "warning"].includes(val)
|
|
85
|
+
},
|
|
86
|
+
// 按钮尺寸
|
|
87
|
+
size: {
|
|
88
|
+
type: String,
|
|
89
|
+
default: "large",
|
|
90
|
+
validator: (val) => ["small", "medium", "large"].includes(val)
|
|
91
|
+
},
|
|
92
|
+
// 是否圆角
|
|
93
|
+
round: {
|
|
94
|
+
type: Boolean,
|
|
95
|
+
default: false
|
|
96
|
+
},
|
|
97
|
+
// 是否禁用
|
|
98
|
+
disabled: {
|
|
99
|
+
type: Boolean,
|
|
100
|
+
default: false
|
|
101
|
+
},
|
|
102
|
+
// 默认文本(无插槽时显示)
|
|
103
|
+
text: {
|
|
104
|
+
type: String,
|
|
105
|
+
default: "按钮"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const _hoisted_1 = ["disabled"];
|
|
110
|
+
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
111
|
+
return openBlock(), createElementBlock("button", {
|
|
112
|
+
class: normalizeClass(["SpiritEchoBtn", [
|
|
113
|
+
`SpiritEchoBtn--${$props.type}`,
|
|
114
|
+
`SpiritEchoBtn--${$props.size}`,
|
|
115
|
+
{ "SpiritEchoBtn--round": $props.round },
|
|
116
|
+
{ "SpiritEchoBtn--disabled": $props.disabled }
|
|
117
|
+
]]),
|
|
118
|
+
style: normalizeStyle($props.customStyle),
|
|
119
|
+
disabled: $props.disabled
|
|
120
|
+
}, [
|
|
121
|
+
renderSlot(_ctx.$slots, "default", {}, () => [
|
|
122
|
+
createElementVNode("span", {
|
|
123
|
+
class: normalizeClass(["SpiritEchoBtn__text", `SpiritEchoBtn__text--${$props.textType}`]),
|
|
124
|
+
style: normalizeStyle($props.textStyle)
|
|
125
|
+
}, toDisplayString($props.text), 7)
|
|
126
|
+
])
|
|
127
|
+
], 14, _hoisted_1);
|
|
128
|
+
}
|
|
129
|
+
const myButton = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
|
|
130
|
+
const injector = new ComponentInjector(MyUI);
|
|
131
|
+
injector.register("form", "myButton", myButton, {
|
|
132
|
+
type: "default",
|
|
133
|
+
size: "medium"
|
|
134
|
+
});
|
|
135
|
+
MyUI.install = (app) => {
|
|
136
|
+
app.component("MyButton", MyUI.form.myButton({}));
|
|
137
|
+
};
|
|
138
|
+
export {
|
|
139
|
+
MyUI
|
|
140
|
+
};
|
|
@@ -0,0 +1,143 @@
|
|
|
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));
|
|
3
|
+
})(this, function(exports2, vue) {
|
|
4
|
+
"use strict";var __defProp = Object.defineProperty;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __publicField = (obj, key, value) => {
|
|
7
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
8
|
+
return value;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
class MyUI {
|
|
12
|
+
/**
|
|
13
|
+
* 支持 app.use(MyUI) 注册的静态方法
|
|
14
|
+
* @param {import('vue').App} app Vue 应用实例
|
|
15
|
+
* @param {Object} options 可选配置(如自定义组件前缀等)
|
|
16
|
+
*/
|
|
17
|
+
static install(app, options = {}) {
|
|
18
|
+
Object.keys(this).forEach((category) => {
|
|
19
|
+
const components = this[category];
|
|
20
|
+
Object.keys(components).forEach((componentName) => {
|
|
21
|
+
const component = components[componentName]();
|
|
22
|
+
const kebabCaseName = componentName.replace(/[A-Z]/g, "-$&").toLowerCase();
|
|
23
|
+
app.component(kebabCaseName, component);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
class ComponentInjector {
|
|
29
|
+
constructor(target) {
|
|
30
|
+
// 可选:保留原 register 方法,兼容之前的调用习惯(本质和 registerAsSubMethod 一致)
|
|
31
|
+
__publicField(this, "register", this.registerAsSubMethod);
|
|
32
|
+
this.target = target;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 核心方法:注册组件为「分类的下属函数」
|
|
36
|
+
* @param {string} category 分类名称(如 'form',作为主类的属性)
|
|
37
|
+
* @param {string} subMethodName 下属函数名(如 'myButton',作为分类的下属函数)
|
|
38
|
+
* @param {Object} component 组件定义(.vue 文件)
|
|
39
|
+
* @param {Object} defaultOptions 组件默认配置
|
|
40
|
+
*/
|
|
41
|
+
registerAsSubMethod(category, subMethodName, component, defaultOptions = {}) {
|
|
42
|
+
if (!this.target[category]) {
|
|
43
|
+
this.target[category] = {};
|
|
44
|
+
}
|
|
45
|
+
this.target[category][subMethodName] = (registerOptions = {}) => {
|
|
46
|
+
const mergedConfig = { ...defaultOptions, ...registerOptions };
|
|
47
|
+
return {
|
|
48
|
+
...component,
|
|
49
|
+
props: {
|
|
50
|
+
...component.props,
|
|
51
|
+
default: () => mergedConfig
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const Button_vue_vue_type_style_index_0_lang = "";
|
|
58
|
+
const _export_sfc = (sfc, props) => {
|
|
59
|
+
const target = sfc.__vccOpts || sfc;
|
|
60
|
+
for (const [key, val] of props) {
|
|
61
|
+
target[key] = val;
|
|
62
|
+
}
|
|
63
|
+
return target;
|
|
64
|
+
};
|
|
65
|
+
const _sfc_main = {
|
|
66
|
+
props: {
|
|
67
|
+
// 文本样式类型
|
|
68
|
+
textType: {
|
|
69
|
+
type: String,
|
|
70
|
+
default: "default",
|
|
71
|
+
validator: (val) => ["default", "primary", "success", "danger", "warning"].includes(val)
|
|
72
|
+
},
|
|
73
|
+
// 手动注入文本样式
|
|
74
|
+
textStyle: {
|
|
75
|
+
type: Object,
|
|
76
|
+
default: () => ({})
|
|
77
|
+
},
|
|
78
|
+
// 自定义按钮整体样式
|
|
79
|
+
customStyle: {
|
|
80
|
+
type: Object,
|
|
81
|
+
default: () => ({})
|
|
82
|
+
},
|
|
83
|
+
// 按钮类型(控制背景色)
|
|
84
|
+
type: {
|
|
85
|
+
type: String,
|
|
86
|
+
default: "default",
|
|
87
|
+
validator: (val) => ["default", "primary", "success", "danger", "warning"].includes(val)
|
|
88
|
+
},
|
|
89
|
+
// 按钮尺寸
|
|
90
|
+
size: {
|
|
91
|
+
type: String,
|
|
92
|
+
default: "large",
|
|
93
|
+
validator: (val) => ["small", "medium", "large"].includes(val)
|
|
94
|
+
},
|
|
95
|
+
// 是否圆角
|
|
96
|
+
round: {
|
|
97
|
+
type: Boolean,
|
|
98
|
+
default: false
|
|
99
|
+
},
|
|
100
|
+
// 是否禁用
|
|
101
|
+
disabled: {
|
|
102
|
+
type: Boolean,
|
|
103
|
+
default: false
|
|
104
|
+
},
|
|
105
|
+
// 默认文本(无插槽时显示)
|
|
106
|
+
text: {
|
|
107
|
+
type: String,
|
|
108
|
+
default: "按钮"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const _hoisted_1 = ["disabled"];
|
|
113
|
+
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
114
|
+
return vue.openBlock(), vue.createElementBlock("button", {
|
|
115
|
+
class: vue.normalizeClass(["SpiritEchoBtn", [
|
|
116
|
+
`SpiritEchoBtn--${$props.type}`,
|
|
117
|
+
`SpiritEchoBtn--${$props.size}`,
|
|
118
|
+
{ "SpiritEchoBtn--round": $props.round },
|
|
119
|
+
{ "SpiritEchoBtn--disabled": $props.disabled }
|
|
120
|
+
]]),
|
|
121
|
+
style: vue.normalizeStyle($props.customStyle),
|
|
122
|
+
disabled: $props.disabled
|
|
123
|
+
}, [
|
|
124
|
+
vue.renderSlot(_ctx.$slots, "default", {}, () => [
|
|
125
|
+
vue.createElementVNode("span", {
|
|
126
|
+
class: vue.normalizeClass(["SpiritEchoBtn__text", `SpiritEchoBtn__text--${$props.textType}`]),
|
|
127
|
+
style: vue.normalizeStyle($props.textStyle)
|
|
128
|
+
}, vue.toDisplayString($props.text), 7)
|
|
129
|
+
])
|
|
130
|
+
], 14, _hoisted_1);
|
|
131
|
+
}
|
|
132
|
+
const myButton = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
|
|
133
|
+
const injector = new ComponentInjector(MyUI);
|
|
134
|
+
injector.register("form", "myButton", myButton, {
|
|
135
|
+
type: "default",
|
|
136
|
+
size: "medium"
|
|
137
|
+
});
|
|
138
|
+
MyUI.install = (app) => {
|
|
139
|
+
app.component("MyButton", MyUI.form.myButton({}));
|
|
140
|
+
};
|
|
141
|
+
exports2.MyUI = MyUI;
|
|
142
|
+
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
|
143
|
+
});
|
package/dist/style.css
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
.SpiritEchoBtn {
|
|
2
|
+
width: 100%;
|
|
3
|
+
height: 48px;
|
|
4
|
+
border-radius: 2px;
|
|
5
|
+
border: 1px solid #e6d4d4;
|
|
6
|
+
transition: all 0.2s ease;
|
|
7
|
+
cursor: pointer;
|
|
8
|
+
display: inline-flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
.SpiritEchoBtn__text {
|
|
14
|
+
transition: all 0.2s ease;
|
|
15
|
+
}
|
|
16
|
+
.SpiritEchoBtn__text--default {
|
|
17
|
+
color: #541414;
|
|
18
|
+
font-size: 12px;
|
|
19
|
+
font-weight: 500;
|
|
20
|
+
}
|
|
21
|
+
.SpiritEchoBtn__text--primary {
|
|
22
|
+
color: #4b96d7;
|
|
23
|
+
font-size: 14px;
|
|
24
|
+
font-weight: 600;
|
|
25
|
+
}
|
|
26
|
+
.SpiritEchoBtn__text--success {
|
|
27
|
+
color: #67c23a;
|
|
28
|
+
font-size: 14px;
|
|
29
|
+
font-weight: 600;
|
|
30
|
+
}
|
|
31
|
+
.SpiritEchoBtn__text--danger {
|
|
32
|
+
color: #f56c6c;
|
|
33
|
+
font-size: 14px;
|
|
34
|
+
font-weight: 600;
|
|
35
|
+
}
|
|
36
|
+
.SpiritEchoBtn__text--warning {
|
|
37
|
+
color: #e6a23c;
|
|
38
|
+
font-size: 14px;
|
|
39
|
+
font-weight: 600;
|
|
40
|
+
}
|
|
41
|
+
.SpiritEchoBtn--default {
|
|
42
|
+
background: #fff;
|
|
43
|
+
border-color: #ddd;
|
|
44
|
+
}
|
|
45
|
+
.SpiritEchoBtn--primary {
|
|
46
|
+
background: #4b96d7;
|
|
47
|
+
}
|
|
48
|
+
.SpiritEchoBtn--success {
|
|
49
|
+
background: #67c23a;
|
|
50
|
+
}
|
|
51
|
+
.SpiritEchoBtn--danger {
|
|
52
|
+
background: #f56c6c;
|
|
53
|
+
}
|
|
54
|
+
.SpiritEchoBtn--warning {
|
|
55
|
+
background: #e6a23c;
|
|
56
|
+
}
|
|
57
|
+
.SpiritEchoBtn--small {
|
|
58
|
+
height: 36px;
|
|
59
|
+
padding: 0 16px;
|
|
60
|
+
font-size: 12px;
|
|
61
|
+
}
|
|
62
|
+
.SpiritEchoBtn--medium {
|
|
63
|
+
height: 42px;
|
|
64
|
+
padding: 0 16px;
|
|
65
|
+
font-size: 12px;
|
|
66
|
+
}
|
|
67
|
+
.SpiritEchoBtn--large {
|
|
68
|
+
height: 48px;
|
|
69
|
+
padding: 0 16px;
|
|
70
|
+
font-size: 12px;
|
|
71
|
+
}
|
|
72
|
+
.SpiritEchoBtn--round {
|
|
73
|
+
border-radius: 20px;
|
|
74
|
+
}
|
|
75
|
+
.SpiritEchoBtn--disabled {
|
|
76
|
+
cursor: not-allowed;
|
|
77
|
+
opacity: 0.7;
|
|
78
|
+
}
|
|
79
|
+
.SpiritEchoBtn:not(.SpiritEchoBtn--disabled):hover {
|
|
80
|
+
opacity: 0.9;
|
|
81
|
+
transform: translateY(-1px);
|
|
82
|
+
}
|
|
83
|
+
.SpiritEchoBtn:not(.SpiritEchoBtn--disabled):active {
|
|
84
|
+
transform: translateY(0);
|
|
85
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ikun2274/spiritechoui",
|
|
3
|
+
"version": "0.1.34",
|
|
4
|
+
"main": "dist/spiritechoui.umd.cjs",
|
|
5
|
+
"module": "dist/spiritechoui.es.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./dist/spiritechoui.es.js",
|
|
9
|
+
"require": "./dist/spiritechoui.umd.cjs"
|
|
10
|
+
},
|
|
11
|
+
"./style.css": "./dist/style.css"
|
|
12
|
+
},
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"vue": "^3.0.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@vitejs/plugin-vue": "^4.2.3",
|
|
18
|
+
"vite": "^4.4.9",
|
|
19
|
+
"vue": "^3.3.4"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "vite build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [],
|
|
25
|
+
"author": "",
|
|
26
|
+
"license": "ISC",
|
|
27
|
+
"description": "",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@ikun2274/spiritechoui": "^0.1.2"
|
|
30
|
+
}
|
|
31
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# 我的第一个UI组件库 SpiritEchoUI
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## 安装组件
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
npm install @ikun2274/spiritechoui
|
|
8
|
+
```
|
|
9
|
+
npm uninstall @ikun2274/spiritechoui
|
|
10
|
+
## 更新日志
|
|
11
|
+
|
|
12
|
+
#### 0.1.3 (2025-11-06-13:25)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## 后续规划
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
#### v0.2.x:新增表单组件(输入框、选择器等),完善按钮与表单的联动。
|
|
20
|
+
#### v0.3.x:补充布局工具类,支持更灵活的响应式场景。
|
|
21
|
+
#### v0.4.x:还不知道
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// src/ComponentInjector.js
|
|
2
|
+
export default class ComponentInjector {
|
|
3
|
+
constructor(target) {
|
|
4
|
+
this.target = target; // 接收主类 MyUI
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 核心方法:注册组件为「分类的下属函数」
|
|
9
|
+
* @param {string} category 分类名称(如 'form',作为主类的属性)
|
|
10
|
+
* @param {string} subMethodName 下属函数名(如 'myButton',作为分类的下属函数)
|
|
11
|
+
* @param {Object} component 组件定义(.vue 文件)
|
|
12
|
+
* @param {Object} defaultOptions 组件默认配置
|
|
13
|
+
*/
|
|
14
|
+
registerAsSubMethod(category, subMethodName, component, defaultOptions = {}) {
|
|
15
|
+
// 1. 确保主类下存在该分类(不存在则自动创建分类对象)
|
|
16
|
+
if (!this.target[category]) {
|
|
17
|
+
this.target[category] = {}; // 如:MyUI.form = {}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 2. 将组件方法挂载为「分类的下属函数」
|
|
21
|
+
this.target[category][subMethodName] = (registerOptions = {}) => {
|
|
22
|
+
// 合并默认配置和注册时的自定义配置
|
|
23
|
+
const mergedConfig = { ...defaultOptions, ...registerOptions };
|
|
24
|
+
// 返回带配置的组件(供 Vue 注册使用)
|
|
25
|
+
return {
|
|
26
|
+
...component,
|
|
27
|
+
props: {
|
|
28
|
+
...component.props,
|
|
29
|
+
default: () => mergedConfig
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 可选:保留原 register 方法,兼容之前的调用习惯(本质和 registerAsSubMethod 一致)
|
|
36
|
+
register = this.registerAsSubMethod;
|
|
37
|
+
}
|
package/src/MyUI.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// src/MyUI.js
|
|
2
|
+
// 主类:对外暴露组件方法的入口(如MyUI.button()、MyUI.dialog())
|
|
3
|
+
export default class MyUI {
|
|
4
|
+
/**
|
|
5
|
+
* 支持 app.use(MyUI) 注册的静态方法
|
|
6
|
+
* @param {import('vue').App} app Vue 应用实例
|
|
7
|
+
* @param {Object} options 可选配置(如自定义组件前缀等)
|
|
8
|
+
*/
|
|
9
|
+
static install(app, options = {}) {
|
|
10
|
+
// 遍历所有已注册的分类(如 'form'、'feedback' 等)
|
|
11
|
+
Object.keys(this).forEach(category => {
|
|
12
|
+
const components = this[category];
|
|
13
|
+
// 遍历分类下的所有组件方法
|
|
14
|
+
Object.keys(components).forEach(componentName => {
|
|
15
|
+
// 执行组件方法获取带配置的组件(使用默认配置)
|
|
16
|
+
const component = components[componentName]();
|
|
17
|
+
// 转换组件名为 kebab-case(如 myButton → my-button)
|
|
18
|
+
const kebabCaseName = componentName.replace(/[A-Z]/g, '-$&').toLowerCase();
|
|
19
|
+
// 全局注册组件
|
|
20
|
+
app.component(kebabCaseName, component);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<button
|
|
3
|
+
class="SpiritEchoBtn"
|
|
4
|
+
:class="[
|
|
5
|
+
`SpiritEchoBtn--${type}`,
|
|
6
|
+
`SpiritEchoBtn--${size}`,
|
|
7
|
+
{ 'SpiritEchoBtn--round': round },
|
|
8
|
+
{ 'SpiritEchoBtn--disabled': disabled },
|
|
9
|
+
]"
|
|
10
|
+
:style="customStyle"
|
|
11
|
+
:disabled="disabled"
|
|
12
|
+
>
|
|
13
|
+
<!-- 主要内容插槽(支持HTML标签) -->
|
|
14
|
+
<slot>
|
|
15
|
+
<!-- 默认文本(当无插槽内容时显示) -->
|
|
16
|
+
<span
|
|
17
|
+
class="SpiritEchoBtn__text"
|
|
18
|
+
:class="`SpiritEchoBtn__text--${textType}`"
|
|
19
|
+
:style="textStyle"
|
|
20
|
+
>
|
|
21
|
+
{{ text }}
|
|
22
|
+
</span>
|
|
23
|
+
</slot>
|
|
24
|
+
</button>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script>
|
|
28
|
+
export default {
|
|
29
|
+
props: {
|
|
30
|
+
// 文本样式类型
|
|
31
|
+
textType: {
|
|
32
|
+
type: String,
|
|
33
|
+
default: "default",
|
|
34
|
+
validator: (val) =>
|
|
35
|
+
["default", "primary", "success", "danger", "warning"].includes(val),
|
|
36
|
+
},
|
|
37
|
+
// 手动注入文本样式
|
|
38
|
+
textStyle: {
|
|
39
|
+
type: Object,
|
|
40
|
+
default: () => ({}),
|
|
41
|
+
},
|
|
42
|
+
// 自定义按钮整体样式
|
|
43
|
+
customStyle: {
|
|
44
|
+
type: Object,
|
|
45
|
+
default: () => ({}),
|
|
46
|
+
},
|
|
47
|
+
// 按钮类型(控制背景色)
|
|
48
|
+
type: {
|
|
49
|
+
type: String,
|
|
50
|
+
default: "default",
|
|
51
|
+
validator: (val) =>
|
|
52
|
+
["default", "primary", "success", "danger", "warning"].includes(val),
|
|
53
|
+
},
|
|
54
|
+
// 按钮尺寸
|
|
55
|
+
size: {
|
|
56
|
+
type: String,
|
|
57
|
+
default: "large",
|
|
58
|
+
validator: (val) => ["small", "medium", "large"].includes(val),
|
|
59
|
+
},
|
|
60
|
+
// 是否圆角
|
|
61
|
+
round: {
|
|
62
|
+
type: Boolean,
|
|
63
|
+
default: false,
|
|
64
|
+
},
|
|
65
|
+
// 是否禁用
|
|
66
|
+
disabled: {
|
|
67
|
+
type: Boolean,
|
|
68
|
+
default: false,
|
|
69
|
+
},
|
|
70
|
+
// 默认文本(无插槽时显示)
|
|
71
|
+
text: {
|
|
72
|
+
type: String,
|
|
73
|
+
default: "按钮",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<style lang="scss">
|
|
80
|
+
@use 'sass:map';
|
|
81
|
+
|
|
82
|
+
// 核心变量(精简且可维护)
|
|
83
|
+
$btn-height: (
|
|
84
|
+
small: 36px,
|
|
85
|
+
medium: 42px,
|
|
86
|
+
large: 48px
|
|
87
|
+
);
|
|
88
|
+
$btn-border-radius: (
|
|
89
|
+
default: 2px,
|
|
90
|
+
round: 20px
|
|
91
|
+
);
|
|
92
|
+
$btn-border-color: #e6d4d4;
|
|
93
|
+
$btn-transition: all 0.2s ease;
|
|
94
|
+
$hover-opacity: 0.9;
|
|
95
|
+
$disabled-opacity: 0.7;
|
|
96
|
+
|
|
97
|
+
// 文本颜色变量
|
|
98
|
+
$text-colors: (
|
|
99
|
+
default: #541414,
|
|
100
|
+
primary: #4b96d7,
|
|
101
|
+
success: #67c23a,
|
|
102
|
+
danger: #f56c6c,
|
|
103
|
+
warning: #e6a23c
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
// 按钮背景色变量
|
|
107
|
+
$bg-colors: (
|
|
108
|
+
default: #fff,
|
|
109
|
+
primary: #4b96d7,
|
|
110
|
+
success: #67c23a,
|
|
111
|
+
danger: #f56c6c,
|
|
112
|
+
warning: #e6a23c
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
.SpiritEchoBtn {
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
// 基础样式
|
|
120
|
+
width: 100%;
|
|
121
|
+
height: map-get($btn-height, large);
|
|
122
|
+
border-radius: map-get($btn-border-radius, default);
|
|
123
|
+
border: 1px solid $btn-border-color;
|
|
124
|
+
transition: $btn-transition;
|
|
125
|
+
cursor: pointer;
|
|
126
|
+
display: inline-flex; // 支持内部元素对齐
|
|
127
|
+
align-items: center;
|
|
128
|
+
justify-content: center;
|
|
129
|
+
box-sizing: border-box; // 盒模型统一(避免宽度溢出)
|
|
130
|
+
|
|
131
|
+
// 文本样式
|
|
132
|
+
&__text {
|
|
133
|
+
transition: $btn-transition;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 文本主题颜色(循环生成,精简代码)
|
|
137
|
+
@each $key, $color in $text-colors {
|
|
138
|
+
&__text--#{$key} {
|
|
139
|
+
color: $color;
|
|
140
|
+
font-size: if($key == default, 12px, 14px); // 基础文本稍小
|
|
141
|
+
font-weight: if($key == default, 500, 600);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 按钮类型背景色(循环生成)
|
|
146
|
+
@each $key, $color in $bg-colors {
|
|
147
|
+
&--#{$key} {
|
|
148
|
+
background: $color;
|
|
149
|
+
// 默认类型单独处理边框
|
|
150
|
+
@if $key == default {
|
|
151
|
+
border-color: #ddd;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// 尺寸样式(循环生成)
|
|
157
|
+
@each $key, $height in $btn-height {
|
|
158
|
+
&--#{$key} {
|
|
159
|
+
height: $height;
|
|
160
|
+
padding: 0 16px; // 统一内边距,避免内容挤压
|
|
161
|
+
font-size: 12px;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 圆角样式
|
|
166
|
+
&--round {
|
|
167
|
+
border-radius: map-get($btn-border-radius, round);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 禁用状态
|
|
171
|
+
&--disabled {
|
|
172
|
+
cursor: not-allowed;
|
|
173
|
+
opacity: $disabled-opacity;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 交互效果(排除禁用状态)
|
|
177
|
+
&:not(&--disabled) {
|
|
178
|
+
&:hover {
|
|
179
|
+
opacity: $hover-opacity;
|
|
180
|
+
transform: translateY(-1px);
|
|
181
|
+
}
|
|
182
|
+
&:active {
|
|
183
|
+
transform: translateY(0);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
</style>
|
package/src/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// 组件库内部的 registerComponents.js 示例
|
|
2
|
+
import MyUI from './MyUI';
|
|
3
|
+
import ComponentInjector from './ComponentInjector';
|
|
4
|
+
import myButton from './components/Button.vue';
|
|
5
|
+
|
|
6
|
+
const injector = new ComponentInjector(MyUI);
|
|
7
|
+
injector.register('form', 'myButton', myButton, {
|
|
8
|
+
type: 'default',
|
|
9
|
+
size: 'medium'
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
//假设有第二个组件
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
injector.register('form', 'mytext', mytext, {
|
|
16
|
+
type: 'default',
|
|
17
|
+
size: 'medium'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
MyUI.install = (app) => {
|
|
25
|
+
app.component('MyButton', MyUI.form.myButton({}));
|
|
26
|
+
//假设有第二个组件
|
|
27
|
+
//app.component('MyText', MyUI.form.mytext({}));
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default MyUI;
|
package/vite.config.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// 组件库的 vite.config.js
|
|
2
|
+
import { defineConfig } from 'vite';
|
|
3
|
+
import vue from '@vitejs/plugin-vue';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [vue()],
|
|
7
|
+
build: {
|
|
8
|
+
lib: {
|
|
9
|
+
entry: './src/index.js',
|
|
10
|
+
name: 'MyCustomUI',
|
|
11
|
+
fileName: (format) => `spiritechoui.${format}.js`
|
|
12
|
+
},
|
|
13
|
+
rollupOptions: {
|
|
14
|
+
external: ['vue'],
|
|
15
|
+
output: {
|
|
16
|
+
globals: {
|
|
17
|
+
vue: 'Vue'
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
css: {
|
|
22
|
+
extract: {
|
|
23
|
+
filename: 'style.css', // 编译后样式文件名
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
cssCodeSplit: false,
|
|
27
|
+
|
|
28
|
+
minify: false
|
|
29
|
+
// 可选:关闭压缩方便调试
|
|
30
|
+
}
|
|
31
|
+
});
|