vue-clean-tabs 1.0.0 → 1.1.0
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/README.md +104 -129
- package/dist/index.esm.js +85 -80
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +67 -67
- package/src/components/ConfigurableSimpleTabs.vue +85 -37
- package/src/index.ts +19 -18
- package/src/types.ts +181 -180
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineComponent as
|
|
1
|
+
import { defineComponent as A, useCssVars as D, ref as T, computed as p, onMounted as L, onUnmounted as W, nextTick as E, openBlock as b, createElementBlock as f, normalizeClass as m, normalizeStyle as x, createElementVNode as y, Fragment as I, renderList as N, createCommentVNode as w, toDisplayString as V } from "vue";
|
|
2
2
|
const U = {
|
|
3
3
|
activeTextColor: "rgb(20, 23, 26)",
|
|
4
4
|
inactiveTextColor: "rgb(76, 82, 89)",
|
|
@@ -44,44 +44,44 @@ const U = {
|
|
|
44
44
|
gap: "16px"
|
|
45
45
|
}
|
|
46
46
|
}, P = {
|
|
47
|
-
line: (
|
|
47
|
+
line: (a, o) => ({
|
|
48
48
|
position: "absolute",
|
|
49
49
|
bottom: "0",
|
|
50
50
|
left: "12px",
|
|
51
51
|
right: "12px",
|
|
52
52
|
height: o,
|
|
53
|
-
backgroundColor:
|
|
53
|
+
backgroundColor: a,
|
|
54
54
|
borderRadius: "0"
|
|
55
55
|
}),
|
|
56
|
-
underline: (
|
|
56
|
+
underline: (a, o) => ({
|
|
57
57
|
position: "absolute",
|
|
58
58
|
bottom: "0",
|
|
59
59
|
left: "0",
|
|
60
60
|
right: "0",
|
|
61
61
|
height: o,
|
|
62
|
-
backgroundColor:
|
|
62
|
+
backgroundColor: a,
|
|
63
63
|
borderRadius: "0"
|
|
64
64
|
}),
|
|
65
|
-
dot: (
|
|
65
|
+
dot: (a, o) => ({
|
|
66
66
|
position: "absolute",
|
|
67
67
|
bottom: "4px",
|
|
68
68
|
left: "50%",
|
|
69
69
|
transform: "translateX(-50%)",
|
|
70
70
|
width: o,
|
|
71
71
|
height: o,
|
|
72
|
-
backgroundColor:
|
|
72
|
+
backgroundColor: a,
|
|
73
73
|
borderRadius: "50%"
|
|
74
74
|
}),
|
|
75
|
-
pill: (
|
|
75
|
+
pill: (a, o) => ({
|
|
76
76
|
position: "absolute",
|
|
77
77
|
bottom: "4px",
|
|
78
78
|
left: "8px",
|
|
79
79
|
right: "8px",
|
|
80
80
|
height: o,
|
|
81
|
-
backgroundColor:
|
|
81
|
+
backgroundColor: a,
|
|
82
82
|
borderRadius: o
|
|
83
83
|
})
|
|
84
|
-
}, X = (
|
|
84
|
+
}, X = (a, o, l) => P[a](o, l), h = (a, o) => ({ ...a, ...o }), G = (a, o, l) => !a || !l ? o : { ...o, ...l }, J = ["disabled", "onClick", "onMouseenter", "onMouseleave"], K = ["innerHTML"], Q = { class: "tab-text" }, Y = /* @__PURE__ */ A({
|
|
85
85
|
__name: "ConfigurableSimpleTabs",
|
|
86
86
|
props: {
|
|
87
87
|
tabs: {},
|
|
@@ -98,83 +98,84 @@ const U = {
|
|
|
98
98
|
scrollable: { type: Boolean, default: !1 }
|
|
99
99
|
},
|
|
100
100
|
emits: ["tab-change", "tab-click", "tab-hover", "tab-leave"],
|
|
101
|
-
setup(
|
|
101
|
+
setup(a, { expose: o, emit: l }) {
|
|
102
102
|
var z;
|
|
103
|
-
|
|
104
|
-
"
|
|
105
|
-
"
|
|
103
|
+
D((e) => ({
|
|
104
|
+
"001f7dcf": i.value.inactiveTextColor,
|
|
105
|
+
"78d6cd4f": i.value.fontFamily,
|
|
106
|
+
"37ab6550": i.value.indicatorColor,
|
|
107
|
+
"10278ad8": i.value.activeTextColor,
|
|
108
|
+
"6a0edb99": i.value.backgroundColor
|
|
106
109
|
}));
|
|
107
|
-
const t =
|
|
108
|
-
() =>
|
|
109
|
-
),
|
|
110
|
-
() =>
|
|
111
|
-
),
|
|
112
|
-
() =>
|
|
113
|
-
),
|
|
114
|
-
() => y(j[t.size], t.style)
|
|
115
|
-
), u = v(
|
|
110
|
+
const t = a, d = l, s = T(t.defaultActive || ((z = t.tabs[0]) == null ? void 0 : z.id) || ""), v = T(!1), C = T(null), i = p(() => h(U, t.theme)), c = p(
|
|
111
|
+
() => h(q, t.animation)
|
|
112
|
+
), g = p(
|
|
113
|
+
() => h(O, t.responsive)
|
|
114
|
+
), R = p(
|
|
115
|
+
() => h(j[t.size], t.style)
|
|
116
|
+
), u = p(
|
|
116
117
|
() => G(
|
|
117
|
-
|
|
118
|
+
v.value && g.value.enabled,
|
|
118
119
|
R.value,
|
|
119
120
|
g.value.mobileStyle
|
|
120
121
|
)
|
|
121
|
-
),
|
|
122
|
-
g.value.enabled && (
|
|
123
|
-
}, M = (e) => e.disabled ? i.value.inactiveTextColor :
|
|
122
|
+
), k = () => {
|
|
123
|
+
g.value.enabled && (v.value = window.innerWidth <= g.value.mobileBreakpoint);
|
|
124
|
+
}, M = (e) => e.disabled ? i.value.inactiveTextColor : s.value === e.id ? i.value.activeTextColor : C.value === e.id ? i.value.hoverTextColor : i.value.inactiveTextColor, H = () => X(
|
|
124
125
|
u.value.indicatorStyle,
|
|
125
126
|
i.value.indicatorColor,
|
|
126
127
|
u.value.indicatorHeight
|
|
127
|
-
),
|
|
128
|
-
e.disabled || (
|
|
128
|
+
), B = (e, r) => {
|
|
129
|
+
e.disabled || (s.value = e.id, d("tab-change", e.id, e), d("tab-click", e.id, e, r), e.route && console.log("Navigate to:", e.route));
|
|
129
130
|
}, $ = (e) => {
|
|
130
|
-
e.disabled || (
|
|
131
|
-
},
|
|
132
|
-
e.disabled || (
|
|
131
|
+
e.disabled || (C.value = e.id, d("tab-hover", e.id, e));
|
|
132
|
+
}, F = (e) => {
|
|
133
|
+
e.disabled || (C.value = null, d("tab-leave", e.id, e));
|
|
133
134
|
}, _ = () => {
|
|
134
|
-
|
|
135
|
+
k();
|
|
135
136
|
};
|
|
136
137
|
return L(() => {
|
|
137
|
-
|
|
138
|
+
k(), window.addEventListener("resize", _);
|
|
138
139
|
}), W(() => {
|
|
139
140
|
window.removeEventListener("resize", _);
|
|
140
141
|
}), o({
|
|
141
|
-
activeTab:
|
|
142
|
+
activeTab: s,
|
|
142
143
|
setActiveTab: (e) => {
|
|
143
|
-
const
|
|
144
|
-
|
|
144
|
+
const r = t.tabs.find((n) => n.id === e);
|
|
145
|
+
r && !r.disabled && (s.value = e, d("tab-change", e, r));
|
|
145
146
|
},
|
|
146
|
-
getActiveTab: () => t.tabs.find((e) => e.id ===
|
|
147
|
+
getActiveTab: () => t.tabs.find((e) => e.id === s.value),
|
|
147
148
|
scrollToTab: (e) => {
|
|
148
149
|
t.scrollable && E(() => {
|
|
149
|
-
const
|
|
150
|
-
|
|
150
|
+
const r = document.querySelector(`[data-tab-id="${e}"]`);
|
|
151
|
+
r && r.scrollIntoView({ behavior: "smooth", inline: "center" });
|
|
151
152
|
});
|
|
152
153
|
}
|
|
153
|
-
}), (e,
|
|
154
|
-
class:
|
|
154
|
+
}), (e, r) => (b(), f("div", {
|
|
155
|
+
class: m(["simple-tabs-container", [
|
|
155
156
|
`size-${t.size}`,
|
|
156
157
|
{
|
|
157
158
|
"tabs-block": t.block,
|
|
158
159
|
"tabs-centered": t.centered,
|
|
159
160
|
"tabs-scrollable": t.scrollable,
|
|
160
|
-
"is-mobile":
|
|
161
|
+
"is-mobile": v.value
|
|
161
162
|
},
|
|
162
163
|
t.className
|
|
163
164
|
]]),
|
|
164
|
-
style:
|
|
165
|
+
style: x({
|
|
165
166
|
backgroundColor: i.value.backgroundColor,
|
|
166
167
|
boxShadow: i.value.boxShadow,
|
|
167
168
|
flexShrink: 0,
|
|
168
169
|
...t.customStyle
|
|
169
170
|
})
|
|
170
171
|
}, [
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
class:
|
|
174
|
-
"flex-wrap": t.scrollable && !
|
|
175
|
-
"overflow-x-auto": t.scrollable &&
|
|
172
|
+
y("nav", null, [
|
|
173
|
+
y("ul", {
|
|
174
|
+
class: m(["tabs-list", {
|
|
175
|
+
"flex-wrap": t.scrollable && !v.value,
|
|
176
|
+
"overflow-x-auto": t.scrollable && v.value
|
|
176
177
|
}]),
|
|
177
|
-
style:
|
|
178
|
+
style: x({
|
|
178
179
|
display: "flex",
|
|
179
180
|
gap: u.value.gap,
|
|
180
181
|
justifyContent: t.centered ? "center" : "flex-start",
|
|
@@ -183,39 +184,43 @@ const U = {
|
|
|
183
184
|
listStyle: "none"
|
|
184
185
|
})
|
|
185
186
|
}, [
|
|
186
|
-
(b(!0), f(I, null, N(t.tabs, (
|
|
187
|
-
key:
|
|
188
|
-
class:
|
|
189
|
-
"tab-active":
|
|
190
|
-
"tab-disabled":
|
|
187
|
+
(b(!0), f(I, null, N(t.tabs, (n) => (b(), f("li", {
|
|
188
|
+
key: n.id,
|
|
189
|
+
class: m(["tab-item", {
|
|
190
|
+
"tab-active": s.value === n.id,
|
|
191
|
+
"tab-disabled": n.disabled
|
|
191
192
|
}])
|
|
192
193
|
}, [
|
|
193
|
-
|
|
194
|
-
class: "tab-button",
|
|
195
|
-
|
|
196
|
-
|
|
194
|
+
y("button", {
|
|
195
|
+
class: m(["tab-button", {
|
|
196
|
+
"tab-button-active": s.value === n.id,
|
|
197
|
+
"tab-button-disabled": n.disabled
|
|
198
|
+
}]),
|
|
199
|
+
disabled: n.disabled,
|
|
200
|
+
style: x({
|
|
197
201
|
position: "relative",
|
|
198
202
|
display: "flex",
|
|
199
203
|
alignItems: "center",
|
|
200
204
|
background: "none",
|
|
201
205
|
border: "none",
|
|
202
|
-
cursor:
|
|
206
|
+
cursor: n.disabled ? "not-allowed" : "pointer",
|
|
203
207
|
textDecoration: "none",
|
|
204
208
|
transition: c.value.enabled ? `color ${c.value.transitionDuration} ${c.value.easing}` : "none",
|
|
205
209
|
padding: u.value.padding,
|
|
206
210
|
fontSize: u.value.fontSize,
|
|
207
|
-
fontWeight: u.value.fontWeight,
|
|
211
|
+
fontWeight: s.value === n.id ? "500" : u.value.fontWeight,
|
|
208
212
|
fontFamily: i.value.fontFamily,
|
|
209
|
-
color: M(
|
|
210
|
-
opacity:
|
|
213
|
+
color: M(n),
|
|
214
|
+
opacity: n.disabled ? 0.5 : 1,
|
|
211
215
|
borderRadius: u.value.borderRadius || "0",
|
|
212
|
-
whiteSpace: "nowrap"
|
|
216
|
+
whiteSpace: "nowrap",
|
|
217
|
+
lineHeight: 1.25
|
|
213
218
|
}),
|
|
214
|
-
onClick: (
|
|
215
|
-
onMouseenter: (
|
|
216
|
-
onMouseleave: (
|
|
219
|
+
onClick: (S) => B(n, S),
|
|
220
|
+
onMouseenter: (S) => $(n),
|
|
221
|
+
onMouseleave: (S) => F(n)
|
|
217
222
|
}, [
|
|
218
|
-
|
|
223
|
+
n.icon ? (b(), f("span", {
|
|
219
224
|
key: 0,
|
|
220
225
|
class: "tab-icon",
|
|
221
226
|
style: {
|
|
@@ -223,30 +228,30 @@ const U = {
|
|
|
223
228
|
fontSize: "1em",
|
|
224
229
|
lineHeight: 1
|
|
225
230
|
},
|
|
226
|
-
innerHTML:
|
|
231
|
+
innerHTML: n.icon
|
|
227
232
|
}, null, 8, K)) : w("", !0),
|
|
228
|
-
|
|
229
|
-
|
|
233
|
+
y("span", Q, V(n.name), 1),
|
|
234
|
+
s.value === n.id ? (b(), f("span", {
|
|
230
235
|
key: 1,
|
|
231
236
|
class: "tab-indicator",
|
|
232
|
-
style:
|
|
233
|
-
...
|
|
237
|
+
style: x({
|
|
238
|
+
...H(),
|
|
234
239
|
transition: c.value.enabled ? `all ${c.value.indicatorTransition || c.value.transitionDuration} ${c.value.easing}` : "none"
|
|
235
240
|
})
|
|
236
241
|
}, null, 4)) : w("", !0)
|
|
237
|
-
],
|
|
242
|
+
], 46, J)
|
|
238
243
|
], 2))), 128))
|
|
239
244
|
], 6)
|
|
240
245
|
])
|
|
241
246
|
], 6));
|
|
242
247
|
}
|
|
243
248
|
});
|
|
244
|
-
const Z = (
|
|
245
|
-
const l =
|
|
246
|
-
for (const [t,
|
|
247
|
-
l[t] =
|
|
249
|
+
const Z = (a, o) => {
|
|
250
|
+
const l = a.__vccOpts || a;
|
|
251
|
+
for (const [t, d] of o)
|
|
252
|
+
l[t] = d;
|
|
248
253
|
return l;
|
|
249
|
-
}, te = /* @__PURE__ */ Z(Y, [["__scopeId", "data-v-
|
|
254
|
+
}, te = /* @__PURE__ */ Z(Y, [["__scopeId", "data-v-28fbd600"]]);
|
|
250
255
|
export {
|
|
251
256
|
te as ConfigurableSimpleTabs,
|
|
252
257
|
te as default,
|
|
@@ -256,7 +261,7 @@ export {
|
|
|
256
261
|
X as getIndicatorStyle,
|
|
257
262
|
G as getResponsiveStyle,
|
|
258
263
|
P as indicatorStyles,
|
|
259
|
-
|
|
264
|
+
h as mergeConfig,
|
|
260
265
|
j as sizeConfigs
|
|
261
266
|
};
|
|
262
267
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../src/types.ts","../src/components/ConfigurableSimpleTabs.vue"],"sourcesContent":["// 简洁标签页组件的类型定义\r\n\r\n// 标签项接口\r\nexport interface TabItem {\r\n id: string;\r\n name: string;\r\n disabled?: boolean; // 是否禁用\r\n route?: string; // 可选路由地址\r\n icon?: string; // 可选图标\r\n}\r\n\r\n// 尺寸类型\r\nexport type TabSize = 'small' | 'medium' | 'large';\r\n\r\n// 指示器样式类型\r\nexport type IndicatorStyle = 'line' | 'dot' | 'pill' | 'underline';\r\n\r\n// 主题配置接口\r\nexport interface SimpleTabsTheme {\r\n // 激活状态文字颜色\r\n activeTextColor: string;\r\n // 非激活状态文字颜色\r\n inactiveTextColor: string;\r\n // 悬浮状态文字颜色\r\n hoverTextColor: string;\r\n // 背景色\r\n backgroundColor: string;\r\n // 激活指示器颜色\r\n indicatorColor: string;\r\n // 字体系列\r\n fontFamily: string;\r\n // 边框颜色(如果需要)\r\n borderColor?: string;\r\n // 阴影(如果需要)\r\n boxShadow?: string;\r\n}\r\n\r\n// 样式配置接口\r\nexport interface StyleConfig {\r\n // 内边距\r\n padding: string;\r\n // 字体大小\r\n fontSize: string;\r\n // 字体粗细\r\n fontWeight: string;\r\n // 指示器高度\r\n indicatorHeight: string;\r\n // 指示器样式\r\n indicatorStyle: IndicatorStyle;\r\n // 圆角大小\r\n borderRadius?: string;\r\n // 标签间距\r\n gap?: string;\r\n}\r\n\r\n// 动画配置接口\r\nexport interface AnimationConfig {\r\n // 过渡时长\r\n transitionDuration: string;\r\n // 缓动函数\r\n easing: string;\r\n // 是否启用动画\r\n enabled: boolean;\r\n // 指示器动画时长\r\n indicatorTransition?: string;\r\n}\r\n\r\n// 响应式配置接口\r\nexport interface ResponsiveConfig {\r\n // 移动端断点\r\n mobileBreakpoint: number;\r\n // 移动端样式\r\n mobileStyle?: Partial<StyleConfig>;\r\n // 是否启用响应式\r\n enabled: boolean;\r\n}\r\n\r\n// 主组件Props接口\r\nexport interface SimpleTabsProps {\r\n // 标签页数据\r\n tabs: TabItem[];\r\n \r\n // 默认激活的标签ID\r\n defaultActive?: string;\r\n \r\n // 尺寸\r\n size?: TabSize;\r\n \r\n // 主题配置\r\n theme?: Partial<SimpleTabsTheme>;\r\n \r\n // 样式配置\r\n style?: Partial<StyleConfig>;\r\n \r\n // 动画配置\r\n animation?: Partial<AnimationConfig>;\r\n \r\n // 响应式配置\r\n responsive?: Partial<ResponsiveConfig>;\r\n \r\n // 自定义类名\r\n className?: string;\r\n \r\n // 自定义内联样式\r\n customStyle?: Record<string, any>;\r\n \r\n // 是否显示为块级元素\r\n block?: boolean;\r\n \r\n // 居中对齐\r\n centered?: boolean;\r\n \r\n // 是否可滚动(当标签过多时)\r\n scrollable?: boolean;\r\n}\r\n\r\n// 事件接口\r\nexport interface SimpleTabsEvents {\r\n 'tab-change': [tabId: string, tab: TabItem];\r\n 'tab-click': [tabId: string, tab: TabItem, event: Event];\r\n 'tab-hover': [tabId: string, tab: TabItem];\r\n 'tab-leave': [tabId: string, tab: TabItem];\r\n}\r\n\r\n// 默认主题\r\nexport const defaultTheme: SimpleTabsTheme = {\r\n activeTextColor: 'rgb(20, 23, 26)',\r\n inactiveTextColor: 'rgb(76, 82, 89)',\r\n hoverTextColor: 'rgb(55, 65, 81)',\r\n backgroundColor: '#ffffff',\r\n indicatorColor: 'rgb(20, 23, 26)',\r\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"SF Pro Display\", \"Inter\", sans-serif',\r\n};\r\n\r\n// 尺寸配置\r\nexport const sizeConfigs: Record<TabSize, StyleConfig> = {\r\n small: {\r\n padding: '8px 10px',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '16px',\r\n },\r\n medium: {\r\n padding: '14px 12px',\r\n fontSize: '16px',\r\n fontWeight: '600',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '20px',\r\n },\r\n large: {\r\n padding: '16px 16px',\r\n fontSize: '18px',\r\n fontWeight: '700',\r\n indicatorHeight: '3px',\r\n indicatorStyle: 'line',\r\n gap: '24px',\r\n },\r\n};\r\n\r\n// 默认动画配置\r\nexport const defaultAnimation: AnimationConfig = {\r\n transitionDuration: '0.2s',\r\n easing: 'ease',\r\n enabled: true,\r\n indicatorTransition: '0.3s ease',\r\n};\r\n\r\n// 默认响应式配置\r\nexport const defaultResponsive: ResponsiveConfig = {\r\n mobileBreakpoint: 768,\r\n enabled: true,\r\n mobileStyle: {\r\n padding: '14px 0',\r\n gap: '16px',\r\n },\r\n};\r\n\r\n// 指示器样式映射\r\nexport const indicatorStyles: Record<IndicatorStyle, (color: string, height: string) => Record<string, string>> = {\r\n line: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '12px',\r\n right: '12px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n \r\n underline: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '0',\r\n right: '0',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n \r\n dot: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '50%',\r\n transform: 'translateX(-50%)',\r\n width: height,\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '50%',\r\n }),\r\n \r\n pill: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '8px',\r\n right: '8px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: height,\r\n }),\r\n};\r\n\r\n// 工具函数:获取指示器样式\r\nexport const getIndicatorStyle = (\r\n style: IndicatorStyle, \r\n color: string, \r\n height: string\r\n): Record<string, string> => {\r\n return indicatorStyles[style](color, height);\r\n};\r\n\r\n// 工具函数:合并配置\r\nexport const mergeConfig = <T extends Record<string, any>>(\r\n defaultConfig: T,\r\n userConfig?: Partial<T>\r\n): T => {\r\n return { ...defaultConfig, ...userConfig };\r\n};\r\n\r\n// 工具函数:获取响应式样式\r\nexport const getResponsiveStyle = (\r\n isMobile: boolean,\r\n baseStyle: StyleConfig,\r\n mobileStyle?: Partial<StyleConfig>\r\n): StyleConfig => {\r\n if (!isMobile || !mobileStyle) return baseStyle;\r\n return { ...baseStyle, ...mobileStyle };\r\n};\r\n","<template>\r\n <div\r\n class=\"simple-tabs-container\"\r\n :class=\"[\r\n `size-${props.size}`,\r\n {\r\n 'tabs-block': props.block,\r\n 'tabs-centered': props.centered,\r\n 'tabs-scrollable': props.scrollable,\r\n 'is-mobile': isMobile,\r\n },\r\n props.className,\r\n ]\"\r\n :style=\"{\r\n backgroundColor: computedTheme.backgroundColor,\r\n boxShadow: computedTheme.boxShadow,\r\n flexShrink: 0,\r\n ...props.customStyle,\r\n }\"\r\n >\r\n <nav>\r\n <ul\r\n class=\"tabs-list\"\r\n :class=\"{\r\n 'flex-wrap': props.scrollable && !isMobile,\r\n 'overflow-x-auto': props.scrollable && isMobile,\r\n }\"\r\n :style=\"{\r\n display: 'flex',\r\n gap: computedStyleConfig.gap,\r\n justifyContent: props.centered ? 'center' : 'flex-start',\r\n margin: 0,\r\n padding: 0,\r\n listStyle: 'none',\r\n }\"\r\n >\r\n <li\r\n v-for=\"tab in props.tabs\"\r\n :key=\"tab.id\"\r\n class=\"tab-item\"\r\n :class=\"{\r\n 'tab-active': activeTab === tab.id,\r\n 'tab-disabled': tab.disabled,\r\n }\"\r\n >\r\n <button\r\n class=\"tab-button\"\r\n :disabled=\"tab.disabled\"\r\n :style=\"{\r\n position: 'relative',\r\n display: 'flex',\r\n alignItems: 'center',\r\n background: 'none',\r\n border: 'none',\r\n cursor: tab.disabled ? 'not-allowed' : 'pointer',\r\n textDecoration: 'none',\r\n transition: computedAnimation.enabled\r\n ? `color ${computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n padding: computedStyleConfig.padding,\r\n fontSize: computedStyleConfig.fontSize,\r\n fontWeight: computedStyleConfig.fontWeight,\r\n fontFamily: computedTheme.fontFamily,\r\n color: getTabTextColor(tab),\r\n opacity: tab.disabled ? 0.5 : 1,\r\n borderRadius: computedStyleConfig.borderRadius || '0',\r\n whiteSpace: 'nowrap',\r\n }\"\r\n @click=\"handleTabClick(tab, $event)\"\r\n @mouseenter=\"handleTabHover(tab)\"\r\n @mouseleave=\"handleTabLeave(tab)\"\r\n >\r\n <!-- 图标 -->\r\n <span\r\n v-if=\"tab.icon\"\r\n class=\"tab-icon\"\r\n :style=\"{\r\n marginRight: '8px',\r\n fontSize: '1em',\r\n lineHeight: 1,\r\n }\"\r\n v-html=\"tab.icon\"\r\n />\r\n \r\n <!-- 标签文本 -->\r\n <span class=\"tab-text\">{{ tab.name }}</span>\r\n \r\n <!-- 激活指示器 -->\r\n <span\r\n v-if=\"activeTab === tab.id\"\r\n class=\"tab-indicator\"\r\n :style=\"{\r\n ...getIndicatorStyleComputed(),\r\n transition: computedAnimation.enabled\r\n ? `all ${computedAnimation.indicatorTransition || computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n }\"\r\n />\r\n </button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted, onUnmounted, nextTick } from 'vue';\r\nimport type { SimpleTabsProps, SimpleTabsEvents, TabItem } from '../types';\r\nimport {\r\n defaultTheme,\r\n sizeConfigs,\r\n defaultAnimation,\r\n defaultResponsive,\r\n mergeConfig,\r\n getResponsiveStyle,\r\n getIndicatorStyle,\r\n} from '../types';\r\n\r\n// Props定义\r\nconst props = withDefaults(defineProps<SimpleTabsProps>(), {\r\n size: 'medium',\r\n block: false,\r\n centered: false,\r\n scrollable: false,\r\n});\r\n\r\n// Events定义\r\nconst emit = defineEmits<SimpleTabsEvents>();\r\n\r\n// 响应式状态\r\nconst activeTab = ref(props.defaultActive || props.tabs[0]?.id || '');\r\nconst isMobile = ref(false);\r\nconst hoveredTab = ref<string | null>(null);\r\n\r\n// 计算属性\r\nconst computedTheme = computed(() => \r\n mergeConfig(defaultTheme, props.theme)\r\n);\r\n\r\nconst computedAnimation = computed(() => \r\n mergeConfig(defaultAnimation, props.animation)\r\n);\r\n\r\nconst computedResponsive = computed(() => \r\n mergeConfig(defaultResponsive, props.responsive)\r\n);\r\n\r\nconst baseStyleConfig = computed(() => \r\n mergeConfig(sizeConfigs[props.size], props.style)\r\n);\r\n\r\nconst computedStyleConfig = computed(() => \r\n getResponsiveStyle(\r\n isMobile.value && computedResponsive.value.enabled,\r\n baseStyleConfig.value,\r\n computedResponsive.value.mobileStyle\r\n )\r\n);\r\n\r\n// 工具方法\r\nconst checkMobile = () => {\r\n if (computedResponsive.value.enabled) {\r\n isMobile.value = window.innerWidth <= computedResponsive.value.mobileBreakpoint;\r\n }\r\n};\r\n\r\nconst getTabTextColor = (tab: TabItem): string => {\r\n if (tab.disabled) {\r\n return computedTheme.value.inactiveTextColor;\r\n }\r\n \r\n if (activeTab.value === tab.id) {\r\n return computedTheme.value.activeTextColor;\r\n }\r\n \r\n if (hoveredTab.value === tab.id) {\r\n return computedTheme.value.hoverTextColor;\r\n }\r\n \r\n return computedTheme.value.inactiveTextColor;\r\n};\r\n\r\nconst getIndicatorStyleComputed = () => {\r\n return getIndicatorStyle(\r\n computedStyleConfig.value.indicatorStyle,\r\n computedTheme.value.indicatorColor,\r\n computedStyleConfig.value.indicatorHeight\r\n );\r\n};\r\n\r\n// 事件处理\r\nconst handleTabClick = (tab: TabItem, event: Event) => {\r\n if (tab.disabled) return;\r\n \r\n activeTab.value = tab.id;\r\n emit('tab-change', tab.id, tab);\r\n emit('tab-click', tab.id, tab, event);\r\n \r\n // 路由跳转逻辑(如果需要)\r\n if (tab.route) {\r\n console.log('Navigate to:', tab.route);\r\n // 这里可以集成 vue-router\r\n }\r\n};\r\n\r\nconst handleTabHover = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = tab.id;\r\n emit('tab-hover', tab.id, tab);\r\n};\r\n\r\nconst handleTabLeave = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = null;\r\n emit('tab-leave', tab.id, tab);\r\n};\r\n\r\n// 窗口尺寸变化监听\r\nconst handleResize = () => {\r\n checkMobile();\r\n};\r\n\r\n// 生命周期\r\nonMounted(() => {\r\n checkMobile();\r\n window.addEventListener('resize', handleResize);\r\n});\r\n\r\nonUnmounted(() => {\r\n window.removeEventListener('resize', handleResize);\r\n});\r\n\r\n// 暴露给父组件\r\ndefineExpose({\r\n activeTab,\r\n setActiveTab: (tabId: string) => {\r\n const tab = props.tabs.find(t => t.id === tabId);\r\n if (tab && !tab.disabled) {\r\n activeTab.value = tabId;\r\n emit('tab-change', tabId, tab);\r\n }\r\n },\r\n getActiveTab: () => {\r\n return props.tabs.find(t => t.id === activeTab.value);\r\n },\r\n scrollToTab: (tabId: string) => {\r\n if (!props.scrollable) return;\r\n nextTick(() => {\r\n const tabElement = document.querySelector(`[data-tab-id=\"${tabId}\"]`);\r\n if (tabElement) {\r\n tabElement.scrollIntoView({ behavior: 'smooth', inline: 'center' });\r\n }\r\n });\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.simple-tabs-container {\r\n width: 100%;\r\n}\r\n\r\n.simple-tabs-container.tabs-block {\r\n display: block;\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list {\r\n overflow-x: auto;\r\n scrollbar-width: none; /* Firefox */\r\n -ms-overflow-style: none; /* IE and Edge */\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list::-webkit-scrollbar {\r\n display: none; /* Chrome, Safari, Opera */\r\n}\r\n\r\n.tab-item {\r\n flex-shrink: 0;\r\n position: relative;\r\n}\r\n\r\n.tab-button {\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n}\r\n\r\n.tab-button:focus {\r\n outline: none;\r\n}\r\n\r\n.tab-button:focus-visible {\r\n outline: 2px solid v-bind('computedTheme.indicatorColor');\r\n outline-offset: 2px;\r\n}\r\n\r\n/* 移动端优化 */\r\n.simple-tabs-container.is-mobile .tab-button {\r\n -webkit-touch-callout: none;\r\n -webkit-user-select: none;\r\n -khtml-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n}\r\n\r\n/* 禁用状态样式 */\r\n.tab-disabled .tab-button {\r\n cursor: not-allowed;\r\n}\r\n\r\n/* 响应式样式 */\r\n@media (max-width: 768px) {\r\n .simple-tabs-container.is-mobile .tab-indicator {\r\n left: 0 !important;\r\n right: 0 !important;\r\n }\r\n}\r\n\r\n/* 滚动优化 */\r\n.tabs-scrollable {\r\n position: relative;\r\n}\r\n\r\n.tabs-scrollable::before,\r\n.tabs-scrollable::after {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n bottom: 0;\r\n width: 20px;\r\n pointer-events: none;\r\n z-index: 1;\r\n}\r\n\r\n.tabs-scrollable::before {\r\n left: 0;\r\n background: linear-gradient(to right, v-bind('computedTheme.backgroundColor'), transparent);\r\n}\r\n\r\n.tabs-scrollable::after {\r\n right: 0;\r\n background: linear-gradient(to left, v-bind('computedTheme.backgroundColor'), transparent);\r\n}\r\n\r\n/* 不同尺寸的样式 */\r\n.size-small .tab-button {\r\n min-height: 32px;\r\n}\r\n\r\n.size-medium .tab-button {\r\n min-height: 40px;\r\n}\r\n\r\n.size-large .tab-button {\r\n min-height: 48px;\r\n}\r\n\r\n/* 居中对齐样式 */\r\n.tabs-centered .tabs-list {\r\n justify-content: center;\r\n}\r\n\r\n/* 图标样式 */\r\n.tab-icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.tab-icon svg {\r\n width: 1em;\r\n height: 1em;\r\n fill: currentColor;\r\n}\r\n\r\n/* 指示器样式基类 */\r\n.tab-indicator {\r\n pointer-events: none;\r\n}\r\n\r\n/* 动画性能优化 */\r\n.tab-button,\r\n.tab-indicator {\r\n will-change: color, background-color, transform;\r\n}\r\n\r\n/* 高对比度模式支持 */\r\n@media (prefers-contrast: high) {\r\n .tab-button {\r\n border: 1px solid currentColor;\r\n }\r\n \r\n .tab-indicator {\r\n border: 2px solid currentColor;\r\n }\r\n}\r\n\r\n/* 减少动画模式支持 */\r\n@media (prefers-reduced-motion: reduce) {\r\n .tab-button,\r\n .tab-indicator {\r\n transition: none !important;\r\n }\r\n}\r\n</style>\r\n"],"names":["defaultTheme","sizeConfigs","defaultAnimation","defaultResponsive","indicatorStyles","color","height","getIndicatorStyle","style","mergeConfig","defaultConfig","userConfig","getResponsiveStyle","isMobile","baseStyle","mobileStyle","props","__props","emit","__emit","activeTab","ref","_a","hoveredTab","computedTheme","computed","computedAnimation","computedResponsive","baseStyleConfig","computedStyleConfig","checkMobile","getTabTextColor","tab","getIndicatorStyleComputed","handleTabClick","event","handleTabHover","handleTabLeave","handleResize","onMounted","onUnmounted","__expose","tabId","t","nextTick","tabElement","_createElementBlock","_normalizeStyle","_createElementVNode","_openBlock","_Fragment","_renderList","$event","_hoisted_3","_toDisplayString"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/types.ts","../src/components/ConfigurableSimpleTabs.vue"],"sourcesContent":["// 简洁标签页组件的类型定义\r\n\r\n// 标签项接口\r\nexport interface TabItem {\r\n id: string;\r\n name: string;\r\n disabled?: boolean; // 是否禁用\r\n route?: string; // 可选路由地址\r\n icon?: string; // 可选图标\r\n}\r\n\r\n// 尺寸类型\r\nexport type TabSize = 'small' | 'medium' | 'large';\r\n\r\n// 指示器样式类型\r\nexport type IndicatorStyle = 'line' | 'dot' | 'pill' | 'underline';\r\n\r\n// 主题配置接口\r\nexport interface SimpleTabsTheme {\r\n // 激活状态文字颜色\r\n activeTextColor: string;\r\n // 非激活状态文字颜色\r\n inactiveTextColor: string;\r\n // 悬浮状态文字颜色\r\n hoverTextColor: string;\r\n // 背景色\r\n backgroundColor: string;\r\n // 激活指示器颜色\r\n indicatorColor: string;\r\n // 字体系列\r\n fontFamily: string;\r\n // 边框颜色(如果需要)\r\n borderColor?: string;\r\n // 阴影(如果需要)\r\n boxShadow?: string;\r\n}\r\n\r\n// 样式配置接口\r\nexport interface StyleConfig {\r\n // 内边距\r\n padding: string;\r\n // 字体大小\r\n fontSize: string;\r\n // 字体粗细\r\n fontWeight: string;\r\n // 指示器高度\r\n indicatorHeight: string;\r\n // 指示器样式\r\n indicatorStyle: IndicatorStyle;\r\n // 圆角大小\r\n borderRadius?: string;\r\n // 标签间距\r\n gap?: string;\r\n}\r\n\r\n// 动画配置接口\r\nexport interface AnimationConfig {\r\n // 过渡时长\r\n transitionDuration: string;\r\n // 缓动函数\r\n easing: string;\r\n // 是否启用动画\r\n enabled: boolean;\r\n // 指示器动画时长\r\n indicatorTransition?: string;\r\n}\r\n\r\n// 响应式配置接口\r\nexport interface ResponsiveConfig {\r\n // 移动端断点\r\n mobileBreakpoint: number;\r\n // 移动端样式\r\n mobileStyle?: Partial<StyleConfig>;\r\n // 是否启用响应式\r\n enabled: boolean;\r\n}\r\n\r\n// 主组件Props接口\r\nexport interface SimpleTabsProps {\r\n // 标签页数据\r\n tabs: TabItem[];\r\n\r\n // 默认激活的标签ID\r\n defaultActive?: string;\r\n\r\n // 尺寸\r\n size?: TabSize;\r\n\r\n // 主题配置\r\n theme?: Partial<SimpleTabsTheme>;\r\n\r\n // 样式配置\r\n style?: Partial<StyleConfig>;\r\n\r\n // 动画配置\r\n animation?: Partial<AnimationConfig>;\r\n\r\n // 响应式配置\r\n responsive?: Partial<ResponsiveConfig>;\r\n\r\n // 自定义类名\r\n className?: string;\r\n\r\n // 自定义内联样式\r\n customStyle?: Record<string, any>;\r\n\r\n // 是否显示为块级元素\r\n block?: boolean;\r\n\r\n // 居中对齐\r\n centered?: boolean;\r\n\r\n // 是否可滚动(当标签过多时)\r\n scrollable?: boolean;\r\n}\r\n\r\n// 事件接口\r\nexport interface SimpleTabsEvents {\r\n 'tab-change': [tabId: string, tab: TabItem];\r\n 'tab-click': [tabId: string, tab: TabItem, event: Event];\r\n 'tab-hover': [tabId: string, tab: TabItem];\r\n 'tab-leave': [tabId: string, tab: TabItem];\r\n}\r\n\r\n// 默认主题\r\nexport const defaultTheme: SimpleTabsTheme = {\r\n activeTextColor: 'rgb(20, 23, 26)',\r\n inactiveTextColor: 'rgb(76, 82, 89)',\r\n hoverTextColor: 'rgb(55, 65, 81)',\r\n backgroundColor: '#ffffff',\r\n indicatorColor: 'rgb(20, 23, 26)',\r\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"SF Pro Display\", \"Inter\", sans-serif',\r\n};\r\n\r\n// 尺寸配置\r\nexport const sizeConfigs: Record<TabSize, StyleConfig> = {\r\n small: {\r\n padding: '8px 10px',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '16px',\r\n },\r\n medium: {\r\n padding: '14px 12px',\r\n fontSize: '16px',\r\n fontWeight: '600',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '20px',\r\n },\r\n large: {\r\n padding: '16px 16px',\r\n fontSize: '18px',\r\n fontWeight: '700',\r\n indicatorHeight: '3px',\r\n indicatorStyle: 'line',\r\n gap: '24px',\r\n },\r\n};\r\n\r\n// 默认动画配置\r\nexport const defaultAnimation: AnimationConfig = {\r\n transitionDuration: '0.2s',\r\n easing: 'ease',\r\n enabled: true,\r\n indicatorTransition: '0.3s ease',\r\n};\r\n\r\n// 默认响应式配置\r\nexport const defaultResponsive: ResponsiveConfig = {\r\n mobileBreakpoint: 768,\r\n enabled: true,\r\n mobileStyle: {\r\n padding: '14px 0',\r\n gap: '16px',\r\n },\r\n};\r\n\r\n// 指示器样式映射\r\nexport const indicatorStyles: Record<IndicatorStyle, (color: string, height: string) => Record<string, string>> = {\r\n line: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '12px',\r\n right: '12px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n\r\n underline: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '0',\r\n right: '0',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n\r\n dot: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '50%',\r\n transform: 'translateX(-50%)',\r\n width: height,\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '50%',\r\n }),\r\n\r\n pill: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '8px',\r\n right: '8px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: height,\r\n }),\r\n};\r\n\r\n// 工具函数:获取指示器样式\r\nexport const getIndicatorStyle = (\r\n style: IndicatorStyle,\r\n color: string,\r\n height: string\r\n): Record<string, string> => {\r\n return indicatorStyles[style](color, height);\r\n};\r\n\r\n// 工具函数:合并配置\r\nexport const mergeConfig = <T extends Record<string, any>>(\r\n defaultConfig: T,\r\n userConfig?: Partial<T>\r\n): T => {\r\n return { ...defaultConfig, ...userConfig };\r\n};\r\n\r\n// 工具函数:获取响应式样式\r\nexport const getResponsiveStyle = (\r\n isMobile: boolean,\r\n baseStyle: StyleConfig,\r\n mobileStyle?: Partial<StyleConfig>\r\n): StyleConfig => {\r\n if (!isMobile || !mobileStyle) return baseStyle;\r\n return { ...baseStyle, ...mobileStyle };\r\n};\r\n\r\n","<template>\r\n <div\r\n class=\"simple-tabs-container\"\r\n :class=\"[\r\n `size-${props.size}`,\r\n {\r\n 'tabs-block': props.block,\r\n 'tabs-centered': props.centered,\r\n 'tabs-scrollable': props.scrollable,\r\n 'is-mobile': isMobile,\r\n },\r\n props.className,\r\n ]\"\r\n :style=\"{\r\n backgroundColor: computedTheme.backgroundColor,\r\n boxShadow: computedTheme.boxShadow,\r\n flexShrink: 0,\r\n ...props.customStyle,\r\n }\"\r\n >\r\n <nav>\r\n <ul\r\n class=\"tabs-list\"\r\n :class=\"{\r\n 'flex-wrap': props.scrollable && !isMobile,\r\n 'overflow-x-auto': props.scrollable && isMobile,\r\n }\"\r\n :style=\"{\r\n display: 'flex',\r\n gap: computedStyleConfig.gap,\r\n justifyContent: props.centered ? 'center' : 'flex-start',\r\n margin: 0,\r\n padding: 0,\r\n listStyle: 'none',\r\n }\"\r\n >\r\n <li\r\n v-for=\"tab in props.tabs\"\r\n :key=\"tab.id\"\r\n class=\"tab-item\"\r\n :class=\"{\r\n 'tab-active': activeTab === tab.id,\r\n 'tab-disabled': tab.disabled,\r\n }\"\r\n >\r\n <button\r\n class=\"tab-button\"\r\n :class=\"{\r\n 'tab-button-active': activeTab === tab.id,\r\n 'tab-button-disabled': tab.disabled,\r\n }\"\r\n :disabled=\"tab.disabled\"\r\n :style=\"{\r\n position: 'relative',\r\n display: 'flex',\r\n alignItems: 'center',\r\n background: 'none',\r\n border: 'none',\r\n cursor: tab.disabled ? 'not-allowed' : 'pointer',\r\n textDecoration: 'none',\r\n transition: computedAnimation.enabled\r\n ? `color ${computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n padding: computedStyleConfig.padding,\r\n fontSize: computedStyleConfig.fontSize,\r\n fontWeight: activeTab === tab.id ? '500' : computedStyleConfig.fontWeight,\r\n fontFamily: computedTheme.fontFamily,\r\n color: getTabTextColor(tab),\r\n opacity: tab.disabled ? 0.5 : 1,\r\n borderRadius: computedStyleConfig.borderRadius || '0',\r\n whiteSpace: 'nowrap',\r\n lineHeight: 1.25,\r\n }\"\r\n @click=\"handleTabClick(tab, $event)\"\r\n @mouseenter=\"handleTabHover(tab)\"\r\n @mouseleave=\"handleTabLeave(tab)\"\r\n >\r\n <!-- 图标 -->\r\n <span\r\n v-if=\"tab.icon\"\r\n class=\"tab-icon\"\r\n :style=\"{\r\n marginRight: '8px',\r\n fontSize: '1em',\r\n lineHeight: 1,\r\n }\"\r\n v-html=\"tab.icon\"\r\n />\r\n\r\n <!-- 标签文本 -->\r\n <span class=\"tab-text\">{{ tab.name }}</span>\r\n\r\n <!-- 激活指示器 -->\r\n <span\r\n v-if=\"activeTab === tab.id\"\r\n class=\"tab-indicator\"\r\n :style=\"{\r\n ...getIndicatorStyleComputed(),\r\n transition: computedAnimation.enabled\r\n ? `all ${computedAnimation.indicatorTransition || computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n }\"\r\n />\r\n </button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted, onUnmounted, nextTick } from \"vue\";\r\nimport type { SimpleTabsProps, SimpleTabsEvents, TabItem } from \"../types\";\r\nimport {\r\n defaultTheme,\r\n sizeConfigs,\r\n defaultAnimation,\r\n defaultResponsive,\r\n mergeConfig,\r\n getResponsiveStyle,\r\n getIndicatorStyle,\r\n} from \"../types\";\r\n\r\n// Props定义\r\nconst props = withDefaults(defineProps<SimpleTabsProps>(), {\r\n size: \"medium\",\r\n block: false,\r\n centered: false,\r\n scrollable: false,\r\n});\r\n\r\n// Events定义\r\nconst emit = defineEmits<SimpleTabsEvents>();\r\n\r\n// 响应式状态\r\nconst activeTab = ref(props.defaultActive || props.tabs[0]?.id || \"\");\r\nconst isMobile = ref(false);\r\nconst hoveredTab = ref<string | null>(null);\r\n\r\n// 计算属性\r\nconst computedTheme = computed(() => mergeConfig(defaultTheme, props.theme));\r\n\r\nconst computedAnimation = computed(() =>\r\n mergeConfig(defaultAnimation, props.animation)\r\n);\r\n\r\nconst computedResponsive = computed(() =>\r\n mergeConfig(defaultResponsive, props.responsive)\r\n);\r\n\r\nconst baseStyleConfig = computed(() =>\r\n mergeConfig(sizeConfigs[props.size], props.style)\r\n);\r\n\r\nconst computedStyleConfig = computed(() =>\r\n getResponsiveStyle(\r\n isMobile.value && computedResponsive.value.enabled,\r\n baseStyleConfig.value,\r\n computedResponsive.value.mobileStyle\r\n )\r\n);\r\n\r\n// 工具方法\r\nconst checkMobile = () => {\r\n if (computedResponsive.value.enabled) {\r\n isMobile.value =\r\n window.innerWidth <= computedResponsive.value.mobileBreakpoint;\r\n }\r\n};\r\n\r\nconst getTabTextColor = (tab: TabItem): string => {\r\n if (tab.disabled) {\r\n return computedTheme.value.inactiveTextColor;\r\n }\r\n\r\n if (activeTab.value === tab.id) {\r\n return computedTheme.value.activeTextColor;\r\n }\r\n\r\n if (hoveredTab.value === tab.id) {\r\n return computedTheme.value.hoverTextColor;\r\n }\r\n\r\n return computedTheme.value.inactiveTextColor;\r\n};\r\n\r\nconst getIndicatorStyleComputed = () => {\r\n return getIndicatorStyle(\r\n computedStyleConfig.value.indicatorStyle,\r\n computedTheme.value.indicatorColor,\r\n computedStyleConfig.value.indicatorHeight\r\n );\r\n};\r\n\r\n// 事件处理\r\nconst handleTabClick = (tab: TabItem, event: Event) => {\r\n if (tab.disabled) return;\r\n\r\n activeTab.value = tab.id;\r\n emit(\"tab-change\", tab.id, tab);\r\n emit(\"tab-click\", tab.id, tab, event);\r\n\r\n // 路由跳转逻辑(如果需要)\r\n if (tab.route) {\r\n console.log(\"Navigate to:\", tab.route);\r\n // 这里可以集成 vue-router\r\n }\r\n};\r\n\r\nconst handleTabHover = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = tab.id;\r\n emit(\"tab-hover\", tab.id, tab);\r\n};\r\n\r\nconst handleTabLeave = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = null;\r\n emit(\"tab-leave\", tab.id, tab);\r\n};\r\n\r\n// 窗口尺寸变化监听\r\nconst handleResize = () => {\r\n checkMobile();\r\n};\r\n\r\n// 生命周期\r\nonMounted(() => {\r\n checkMobile();\r\n window.addEventListener(\"resize\", handleResize);\r\n});\r\n\r\nonUnmounted(() => {\r\n window.removeEventListener(\"resize\", handleResize);\r\n});\r\n\r\n// 暴露给父组件\r\ndefineExpose({\r\n activeTab,\r\n setActiveTab: (tabId: string) => {\r\n const tab = props.tabs.find((t) => t.id === tabId);\r\n if (tab && !tab.disabled) {\r\n activeTab.value = tabId;\r\n emit(\"tab-change\", tabId, tab);\r\n }\r\n },\r\n getActiveTab: () => {\r\n return props.tabs.find((t) => t.id === activeTab.value);\r\n },\r\n scrollToTab: (tabId: string) => {\r\n if (!props.scrollable) return;\r\n nextTick(() => {\r\n const tabElement = document.querySelector(`[data-tab-id=\"${tabId}\"]`);\r\n if (tabElement) {\r\n tabElement.scrollIntoView({ behavior: \"smooth\", inline: \"center\" });\r\n }\r\n });\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.simple-tabs-container {\r\n width: 100%;\r\n}\r\n\r\n.simple-tabs-container.tabs-block {\r\n display: block;\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list {\r\n overflow-x: auto;\r\n scrollbar-width: none; /* Firefox */\r\n -ms-overflow-style: none; /* IE and Edge */\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list::-webkit-scrollbar {\r\n display: none; /* Chrome, Safari, Opera */\r\n}\r\n\r\n.tab-item {\r\n flex-shrink: 0;\r\n position: relative;\r\n}\r\n\r\n.tab-button {\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n text-decoration: none;\r\n background: transparent;\r\n border: 0px;\r\n font-size: 16px;\r\n font-weight: 400;\r\n line-height: 1.25;\r\n padding: 14px 12px;\r\n position: relative;\r\n color: v-bind(\"computedTheme.inactiveTextColor\");\r\n font-family: v-bind(\"computedTheme.fontFamily\");\r\n transition: color 0.2s ease;\r\n}\r\n\r\n.tab-button:focus {\r\n outline: none;\r\n}\r\n\r\n.tab-button:focus-visible {\r\n outline: 2px solid v-bind(\"computedTheme.indicatorColor\");\r\n outline-offset: 2px;\r\n}\r\n\r\n.tab-button-active {\r\n color: v-bind(\"computedTheme.activeTextColor\");\r\n font-weight: 500;\r\n}\r\n\r\n.tab-button-active::before {\r\n position: absolute;\r\n background: v-bind(\"computedTheme.indicatorColor\");\r\n height: 2px;\r\n inset: auto 12px 0px;\r\n content: \"\";\r\n}\r\n\r\n/* 移动端优化 */\r\n.simple-tabs-container.is-mobile .tab-button {\r\n -webkit-touch-callout: none;\r\n -webkit-user-select: none;\r\n -khtml-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n}\r\n\r\n/* 禁用状态样式 */\r\n.tab-disabled .tab-button {\r\n cursor: not-allowed;\r\n}\r\n\r\n/* 响应式样式 */\r\n@media (max-width: 768px) {\r\n .simple-tabs-container.is-mobile .tab-button {\r\n padding: 14px 0;\r\n }\r\n\r\n .simple-tabs-container.is-mobile .tab-button-active::before {\r\n inset: auto 0px 0px;\r\n }\r\n\r\n .simple-tabs-container.is-mobile .tab-indicator {\r\n left: 0 !important;\r\n right: 0 !important;\r\n }\r\n}\r\n\r\n/* 滚动优化 */\r\n.tabs-scrollable {\r\n position: relative;\r\n}\r\n\r\n.tabs-scrollable::before,\r\n.tabs-scrollable::after {\r\n content: \"\";\r\n position: absolute;\r\n top: 0;\r\n bottom: 0;\r\n width: 20px;\r\n pointer-events: none;\r\n z-index: 1;\r\n}\r\n\r\n.tabs-scrollable::before {\r\n left: 0;\r\n background: linear-gradient(\r\n to right,\r\n v-bind(\"computedTheme.backgroundColor\"),\r\n transparent\r\n );\r\n}\r\n\r\n.tabs-scrollable::after {\r\n right: 0;\r\n background: linear-gradient(\r\n to left,\r\n v-bind(\"computedTheme.backgroundColor\"),\r\n transparent\r\n );\r\n}\r\n\r\n/* 不同尺寸的样式 */\r\n.size-small .tab-button {\r\n min-height: 32px;\r\n}\r\n\r\n.size-medium .tab-button {\r\n min-height: 40px;\r\n}\r\n\r\n.size-large .tab-button {\r\n min-height: 48px;\r\n}\r\n\r\n/* 居中对齐样式 */\r\n.tabs-centered .tabs-list {\r\n justify-content: center;\r\n}\r\n\r\n/* 图标样式 */\r\n.tab-icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.tab-icon svg {\r\n width: 1em;\r\n height: 1em;\r\n fill: currentColor;\r\n}\r\n\r\n/* 指示器样式基类 */\r\n.tab-indicator {\r\n pointer-events: none;\r\n}\r\n\r\n/* 动画性能优化 */\r\n.tab-button,\r\n.tab-indicator {\r\n will-change: color, background-color, transform;\r\n}\r\n\r\n/* 高对比度模式支持 */\r\n@media (prefers-contrast: high) {\r\n .tab-button {\r\n border: 1px solid currentColor;\r\n }\r\n\r\n .tab-indicator {\r\n border: 2px solid currentColor;\r\n }\r\n}\r\n\r\n/* 减少动画模式支持 */\r\n@media (prefers-reduced-motion: reduce) {\r\n .tab-button,\r\n .tab-indicator {\r\n transition: none !important;\r\n }\r\n}\r\n</style>\r\n\r\n"],"names":["defaultTheme","sizeConfigs","defaultAnimation","defaultResponsive","indicatorStyles","color","height","getIndicatorStyle","style","mergeConfig","defaultConfig","userConfig","getResponsiveStyle","isMobile","baseStyle","mobileStyle","props","__props","emit","__emit","activeTab","ref","_a","hoveredTab","computedTheme","computed","computedAnimation","computedResponsive","baseStyleConfig","computedStyleConfig","checkMobile","getTabTextColor","tab","getIndicatorStyleComputed","handleTabClick","event","handleTabHover","handleTabLeave","handleResize","onMounted","onUnmounted","__expose","tabId","t","nextTick","tabElement","_createElementBlock","_normalizeStyle","_createElementVNode","_openBlock","_Fragment","_renderList","$event","_hoisted_3","_toDisplayString"],"mappings":"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"}
|
package/dist/index.umd.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(a,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(a=typeof globalThis<"u"?globalThis:a||self,e(a.VueSimpleTabs={},a.Vue))})(this,function(a,e){"use strict";const h={activeTextColor:"rgb(20, 23, 26)",inactiveTextColor:"rgb(76, 82, 89)",hoverTextColor:"rgb(55, 65, 81)",backgroundColor:"#ffffff",indicatorColor:"rgb(20, 23, 26)",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", "SF Pro Display", "Inter", sans-serif'},x={small:{padding:"8px 10px",fontSize:"14px",fontWeight:"500",indicatorHeight:"2px",indicatorStyle:"line",gap:"16px"},medium:{padding:"14px 12px",fontSize:"16px",fontWeight:"600",indicatorHeight:"2px",indicatorStyle:"line",gap:"20px"},large:{padding:"16px 16px",fontSize:"18px",fontWeight:"700",indicatorHeight:"3px",indicatorStyle:"line",gap:"24px"}},C={transitionDuration:"0.2s",easing:"ease",enabled:!0,indicatorTransition:"0.3s ease"},S={mobileBreakpoint:768,enabled:!0,mobileStyle:{padding:"14px 0",gap:"16px"}},k={line:(l,n)=>({position:"absolute",bottom:"0",left:"12px",right:"12px",height:n,backgroundColor:l,borderRadius:"0"}),underline:(l,n)=>({position:"absolute",bottom:"0",left:"0",right:"0",height:n,backgroundColor:l,borderRadius:"0"}),dot:(l,n)=>({position:"absolute",bottom:"4px",left:"50%",transform:"translateX(-50%)",width:n,height:n,backgroundColor:l,borderRadius:"50%"}),pill:(l,n)=>({position:"absolute",bottom:"4px",left:"8px",right:"8px",height:n,backgroundColor:l,borderRadius:n})},T=(l,n,r)=>k[l](n,r),m=(l,n)=>({...l,...n}),_=(l,n,r)=>!l||!r?n:{...n,...r},E=["disabled","onClick","onMouseenter","onMouseleave"],M=["innerHTML"],V={class:"tab-text"},H=e.defineComponent({__name:"ConfigurableSimpleTabs",props:{tabs:{},defaultActive:{},size:{default:"medium"},theme:{},style:{},animation:{},responsive:{},className:{},customStyle:{},block:{type:Boolean,default:!1},centered:{type:Boolean,default:!1},scrollable:{type:Boolean,default:!1}},emits:["tab-change","tab-click","tab-hover","tab-leave"],setup(l,{expose:n,emit:r}){var R;e.useCssVars(t=>({"001f7dcf":s.value.inactiveTextColor,"78d6cd4f":s.value.fontFamily,"37ab6550":s.value.indicatorColor,"10278ad8":s.value.activeTextColor,"6a0edb99":s.value.backgroundColor}));const o=l,u=r,d=e.ref(o.defaultActive||((R=o.tabs[0])==null?void 0:R.id)||""),b=e.ref(!1),v=e.ref(null),s=e.computed(()=>m(h,o.theme)),p=e.computed(()=>m(C,o.animation)),g=e.computed(()=>m(S,o.responsive)),N=e.computed(()=>m(x[o.size],o.style)),f=e.computed(()=>_(b.value&&g.value.enabled,N.value,g.value.mobileStyle)),B=()=>{g.value.enabled&&(b.value=window.innerWidth<=g.value.mobileBreakpoint)},$=t=>t.disabled?s.value.inactiveTextColor:d.value===t.id?s.value.activeTextColor:v.value===t.id?s.value.hoverTextColor:s.value.inactiveTextColor,A=()=>T(f.value.indicatorStyle,s.value.indicatorColor,f.value.indicatorHeight),F=(t,c)=>{t.disabled||(d.value=t.id,u("tab-change",t.id,t),u("tab-click",t.id,t,c),t.route&&console.log("Navigate to:",t.route))},D=t=>{t.disabled||(v.value=t.id,u("tab-hover",t.id,t))},I=t=>{t.disabled||(v.value=null,u("tab-leave",t.id,t))},w=()=>{B()};return e.onMounted(()=>{B(),window.addEventListener("resize",w)}),e.onUnmounted(()=>{window.removeEventListener("resize",w)}),n({activeTab:d,setActiveTab:t=>{const c=o.tabs.find(i=>i.id===t);c&&!c.disabled&&(d.value=t,u("tab-change",t,c))},getActiveTab:()=>o.tabs.find(t=>t.id===d.value),scrollToTab:t=>{o.scrollable&&e.nextTick(()=>{const c=document.querySelector(`[data-tab-id="${t}"]`);c&&c.scrollIntoView({behavior:"smooth",inline:"center"})})}}),(t,c)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["simple-tabs-container",[`size-${o.size}`,{"tabs-block":o.block,"tabs-centered":o.centered,"tabs-scrollable":o.scrollable,"is-mobile":b.value},o.className]]),style:e.normalizeStyle({backgroundColor:s.value.backgroundColor,boxShadow:s.value.boxShadow,flexShrink:0,...o.customStyle})},[e.createElementVNode("nav",null,[e.createElementVNode("ul",{class:e.normalizeClass(["tabs-list",{"flex-wrap":o.scrollable&&!b.value,"overflow-x-auto":o.scrollable&&b.value}]),style:e.normalizeStyle({display:"flex",gap:f.value.gap,justifyContent:o.centered?"center":"flex-start",margin:0,padding:0,listStyle:"none"})},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(o.tabs,i=>(e.openBlock(),e.createElementBlock("li",{key:i.id,class:e.normalizeClass(["tab-item",{"tab-active":d.value===i.id,"tab-disabled":i.disabled}])},[e.createElementVNode("button",{class:e.normalizeClass(["tab-button",{"tab-button-active":d.value===i.id,"tab-button-disabled":i.disabled}]),disabled:i.disabled,style:e.normalizeStyle({position:"relative",display:"flex",alignItems:"center",background:"none",border:"none",cursor:i.disabled?"not-allowed":"pointer",textDecoration:"none",transition:p.value.enabled?`color ${p.value.transitionDuration} ${p.value.easing}`:"none",padding:f.value.padding,fontSize:f.value.fontSize,fontWeight:d.value===i.id?"500":f.value.fontWeight,fontFamily:s.value.fontFamily,color:$(i),opacity:i.disabled?.5:1,borderRadius:f.value.borderRadius||"0",whiteSpace:"nowrap",lineHeight:1.25}),onClick:y=>F(i,y),onMouseenter:y=>D(i),onMouseleave:y=>I(i)},[i.icon?(e.openBlock(),e.createElementBlock("span",{key:0,class:"tab-icon",style:{marginRight:"8px",fontSize:"1em",lineHeight:1},innerHTML:i.icon},null,8,M)):e.createCommentVNode("",!0),e.createElementVNode("span",V,e.toDisplayString(i.name),1),d.value===i.id?(e.openBlock(),e.createElementBlock("span",{key:1,class:"tab-indicator",style:e.normalizeStyle({...A(),transition:p.value.enabled?`all ${p.value.indicatorTransition||p.value.transitionDuration} ${p.value.easing}`:"none"})},null,4)):e.createCommentVNode("",!0)],46,E)],2))),128))],6)])],6))}}),L="",z=((l,n)=>{const r=l.__vccOpts||l;for(const[o,u]of n)r[o]=u;return r})(H,[["__scopeId","data-v-28fbd600"]]);a.ConfigurableSimpleTabs=z,a.default=z,a.defaultAnimation=C,a.defaultResponsive=S,a.defaultTheme=h,a.getIndicatorStyle=T,a.getResponsiveStyle=_,a.indicatorStyles=k,a.mergeConfig=m,a.sizeConfigs=x,Object.defineProperties(a,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
|
2
2
|
//# sourceMappingURL=index.umd.js.map
|
package/dist/index.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.umd.js","sources":["../src/types.ts","../src/components/ConfigurableSimpleTabs.vue"],"sourcesContent":["// 简洁标签页组件的类型定义\r\n\r\n// 标签项接口\r\nexport interface TabItem {\r\n id: string;\r\n name: string;\r\n disabled?: boolean; // 是否禁用\r\n route?: string; // 可选路由地址\r\n icon?: string; // 可选图标\r\n}\r\n\r\n// 尺寸类型\r\nexport type TabSize = 'small' | 'medium' | 'large';\r\n\r\n// 指示器样式类型\r\nexport type IndicatorStyle = 'line' | 'dot' | 'pill' | 'underline';\r\n\r\n// 主题配置接口\r\nexport interface SimpleTabsTheme {\r\n // 激活状态文字颜色\r\n activeTextColor: string;\r\n // 非激活状态文字颜色\r\n inactiveTextColor: string;\r\n // 悬浮状态文字颜色\r\n hoverTextColor: string;\r\n // 背景色\r\n backgroundColor: string;\r\n // 激活指示器颜色\r\n indicatorColor: string;\r\n // 字体系列\r\n fontFamily: string;\r\n // 边框颜色(如果需要)\r\n borderColor?: string;\r\n // 阴影(如果需要)\r\n boxShadow?: string;\r\n}\r\n\r\n// 样式配置接口\r\nexport interface StyleConfig {\r\n // 内边距\r\n padding: string;\r\n // 字体大小\r\n fontSize: string;\r\n // 字体粗细\r\n fontWeight: string;\r\n // 指示器高度\r\n indicatorHeight: string;\r\n // 指示器样式\r\n indicatorStyle: IndicatorStyle;\r\n // 圆角大小\r\n borderRadius?: string;\r\n // 标签间距\r\n gap?: string;\r\n}\r\n\r\n// 动画配置接口\r\nexport interface AnimationConfig {\r\n // 过渡时长\r\n transitionDuration: string;\r\n // 缓动函数\r\n easing: string;\r\n // 是否启用动画\r\n enabled: boolean;\r\n // 指示器动画时长\r\n indicatorTransition?: string;\r\n}\r\n\r\n// 响应式配置接口\r\nexport interface ResponsiveConfig {\r\n // 移动端断点\r\n mobileBreakpoint: number;\r\n // 移动端样式\r\n mobileStyle?: Partial<StyleConfig>;\r\n // 是否启用响应式\r\n enabled: boolean;\r\n}\r\n\r\n// 主组件Props接口\r\nexport interface SimpleTabsProps {\r\n // 标签页数据\r\n tabs: TabItem[];\r\n \r\n // 默认激活的标签ID\r\n defaultActive?: string;\r\n \r\n // 尺寸\r\n size?: TabSize;\r\n \r\n // 主题配置\r\n theme?: Partial<SimpleTabsTheme>;\r\n \r\n // 样式配置\r\n style?: Partial<StyleConfig>;\r\n \r\n // 动画配置\r\n animation?: Partial<AnimationConfig>;\r\n \r\n // 响应式配置\r\n responsive?: Partial<ResponsiveConfig>;\r\n \r\n // 自定义类名\r\n className?: string;\r\n \r\n // 自定义内联样式\r\n customStyle?: Record<string, any>;\r\n \r\n // 是否显示为块级元素\r\n block?: boolean;\r\n \r\n // 居中对齐\r\n centered?: boolean;\r\n \r\n // 是否可滚动(当标签过多时)\r\n scrollable?: boolean;\r\n}\r\n\r\n// 事件接口\r\nexport interface SimpleTabsEvents {\r\n 'tab-change': [tabId: string, tab: TabItem];\r\n 'tab-click': [tabId: string, tab: TabItem, event: Event];\r\n 'tab-hover': [tabId: string, tab: TabItem];\r\n 'tab-leave': [tabId: string, tab: TabItem];\r\n}\r\n\r\n// 默认主题\r\nexport const defaultTheme: SimpleTabsTheme = {\r\n activeTextColor: 'rgb(20, 23, 26)',\r\n inactiveTextColor: 'rgb(76, 82, 89)',\r\n hoverTextColor: 'rgb(55, 65, 81)',\r\n backgroundColor: '#ffffff',\r\n indicatorColor: 'rgb(20, 23, 26)',\r\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"SF Pro Display\", \"Inter\", sans-serif',\r\n};\r\n\r\n// 尺寸配置\r\nexport const sizeConfigs: Record<TabSize, StyleConfig> = {\r\n small: {\r\n padding: '8px 10px',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '16px',\r\n },\r\n medium: {\r\n padding: '14px 12px',\r\n fontSize: '16px',\r\n fontWeight: '600',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '20px',\r\n },\r\n large: {\r\n padding: '16px 16px',\r\n fontSize: '18px',\r\n fontWeight: '700',\r\n indicatorHeight: '3px',\r\n indicatorStyle: 'line',\r\n gap: '24px',\r\n },\r\n};\r\n\r\n// 默认动画配置\r\nexport const defaultAnimation: AnimationConfig = {\r\n transitionDuration: '0.2s',\r\n easing: 'ease',\r\n enabled: true,\r\n indicatorTransition: '0.3s ease',\r\n};\r\n\r\n// 默认响应式配置\r\nexport const defaultResponsive: ResponsiveConfig = {\r\n mobileBreakpoint: 768,\r\n enabled: true,\r\n mobileStyle: {\r\n padding: '14px 0',\r\n gap: '16px',\r\n },\r\n};\r\n\r\n// 指示器样式映射\r\nexport const indicatorStyles: Record<IndicatorStyle, (color: string, height: string) => Record<string, string>> = {\r\n line: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '12px',\r\n right: '12px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n \r\n underline: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '0',\r\n right: '0',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n \r\n dot: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '50%',\r\n transform: 'translateX(-50%)',\r\n width: height,\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '50%',\r\n }),\r\n \r\n pill: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '8px',\r\n right: '8px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: height,\r\n }),\r\n};\r\n\r\n// 工具函数:获取指示器样式\r\nexport const getIndicatorStyle = (\r\n style: IndicatorStyle, \r\n color: string, \r\n height: string\r\n): Record<string, string> => {\r\n return indicatorStyles[style](color, height);\r\n};\r\n\r\n// 工具函数:合并配置\r\nexport const mergeConfig = <T extends Record<string, any>>(\r\n defaultConfig: T,\r\n userConfig?: Partial<T>\r\n): T => {\r\n return { ...defaultConfig, ...userConfig };\r\n};\r\n\r\n// 工具函数:获取响应式样式\r\nexport const getResponsiveStyle = (\r\n isMobile: boolean,\r\n baseStyle: StyleConfig,\r\n mobileStyle?: Partial<StyleConfig>\r\n): StyleConfig => {\r\n if (!isMobile || !mobileStyle) return baseStyle;\r\n return { ...baseStyle, ...mobileStyle };\r\n};\r\n","<template>\r\n <div\r\n class=\"simple-tabs-container\"\r\n :class=\"[\r\n `size-${props.size}`,\r\n {\r\n 'tabs-block': props.block,\r\n 'tabs-centered': props.centered,\r\n 'tabs-scrollable': props.scrollable,\r\n 'is-mobile': isMobile,\r\n },\r\n props.className,\r\n ]\"\r\n :style=\"{\r\n backgroundColor: computedTheme.backgroundColor,\r\n boxShadow: computedTheme.boxShadow,\r\n flexShrink: 0,\r\n ...props.customStyle,\r\n }\"\r\n >\r\n <nav>\r\n <ul\r\n class=\"tabs-list\"\r\n :class=\"{\r\n 'flex-wrap': props.scrollable && !isMobile,\r\n 'overflow-x-auto': props.scrollable && isMobile,\r\n }\"\r\n :style=\"{\r\n display: 'flex',\r\n gap: computedStyleConfig.gap,\r\n justifyContent: props.centered ? 'center' : 'flex-start',\r\n margin: 0,\r\n padding: 0,\r\n listStyle: 'none',\r\n }\"\r\n >\r\n <li\r\n v-for=\"tab in props.tabs\"\r\n :key=\"tab.id\"\r\n class=\"tab-item\"\r\n :class=\"{\r\n 'tab-active': activeTab === tab.id,\r\n 'tab-disabled': tab.disabled,\r\n }\"\r\n >\r\n <button\r\n class=\"tab-button\"\r\n :disabled=\"tab.disabled\"\r\n :style=\"{\r\n position: 'relative',\r\n display: 'flex',\r\n alignItems: 'center',\r\n background: 'none',\r\n border: 'none',\r\n cursor: tab.disabled ? 'not-allowed' : 'pointer',\r\n textDecoration: 'none',\r\n transition: computedAnimation.enabled\r\n ? `color ${computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n padding: computedStyleConfig.padding,\r\n fontSize: computedStyleConfig.fontSize,\r\n fontWeight: computedStyleConfig.fontWeight,\r\n fontFamily: computedTheme.fontFamily,\r\n color: getTabTextColor(tab),\r\n opacity: tab.disabled ? 0.5 : 1,\r\n borderRadius: computedStyleConfig.borderRadius || '0',\r\n whiteSpace: 'nowrap',\r\n }\"\r\n @click=\"handleTabClick(tab, $event)\"\r\n @mouseenter=\"handleTabHover(tab)\"\r\n @mouseleave=\"handleTabLeave(tab)\"\r\n >\r\n <!-- 图标 -->\r\n <span\r\n v-if=\"tab.icon\"\r\n class=\"tab-icon\"\r\n :style=\"{\r\n marginRight: '8px',\r\n fontSize: '1em',\r\n lineHeight: 1,\r\n }\"\r\n v-html=\"tab.icon\"\r\n />\r\n \r\n <!-- 标签文本 -->\r\n <span class=\"tab-text\">{{ tab.name }}</span>\r\n \r\n <!-- 激活指示器 -->\r\n <span\r\n v-if=\"activeTab === tab.id\"\r\n class=\"tab-indicator\"\r\n :style=\"{\r\n ...getIndicatorStyleComputed(),\r\n transition: computedAnimation.enabled\r\n ? `all ${computedAnimation.indicatorTransition || computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n }\"\r\n />\r\n </button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted, onUnmounted, nextTick } from 'vue';\r\nimport type { SimpleTabsProps, SimpleTabsEvents, TabItem } from '../types';\r\nimport {\r\n defaultTheme,\r\n sizeConfigs,\r\n defaultAnimation,\r\n defaultResponsive,\r\n mergeConfig,\r\n getResponsiveStyle,\r\n getIndicatorStyle,\r\n} from '../types';\r\n\r\n// Props定义\r\nconst props = withDefaults(defineProps<SimpleTabsProps>(), {\r\n size: 'medium',\r\n block: false,\r\n centered: false,\r\n scrollable: false,\r\n});\r\n\r\n// Events定义\r\nconst emit = defineEmits<SimpleTabsEvents>();\r\n\r\n// 响应式状态\r\nconst activeTab = ref(props.defaultActive || props.tabs[0]?.id || '');\r\nconst isMobile = ref(false);\r\nconst hoveredTab = ref<string | null>(null);\r\n\r\n// 计算属性\r\nconst computedTheme = computed(() => \r\n mergeConfig(defaultTheme, props.theme)\r\n);\r\n\r\nconst computedAnimation = computed(() => \r\n mergeConfig(defaultAnimation, props.animation)\r\n);\r\n\r\nconst computedResponsive = computed(() => \r\n mergeConfig(defaultResponsive, props.responsive)\r\n);\r\n\r\nconst baseStyleConfig = computed(() => \r\n mergeConfig(sizeConfigs[props.size], props.style)\r\n);\r\n\r\nconst computedStyleConfig = computed(() => \r\n getResponsiveStyle(\r\n isMobile.value && computedResponsive.value.enabled,\r\n baseStyleConfig.value,\r\n computedResponsive.value.mobileStyle\r\n )\r\n);\r\n\r\n// 工具方法\r\nconst checkMobile = () => {\r\n if (computedResponsive.value.enabled) {\r\n isMobile.value = window.innerWidth <= computedResponsive.value.mobileBreakpoint;\r\n }\r\n};\r\n\r\nconst getTabTextColor = (tab: TabItem): string => {\r\n if (tab.disabled) {\r\n return computedTheme.value.inactiveTextColor;\r\n }\r\n \r\n if (activeTab.value === tab.id) {\r\n return computedTheme.value.activeTextColor;\r\n }\r\n \r\n if (hoveredTab.value === tab.id) {\r\n return computedTheme.value.hoverTextColor;\r\n }\r\n \r\n return computedTheme.value.inactiveTextColor;\r\n};\r\n\r\nconst getIndicatorStyleComputed = () => {\r\n return getIndicatorStyle(\r\n computedStyleConfig.value.indicatorStyle,\r\n computedTheme.value.indicatorColor,\r\n computedStyleConfig.value.indicatorHeight\r\n );\r\n};\r\n\r\n// 事件处理\r\nconst handleTabClick = (tab: TabItem, event: Event) => {\r\n if (tab.disabled) return;\r\n \r\n activeTab.value = tab.id;\r\n emit('tab-change', tab.id, tab);\r\n emit('tab-click', tab.id, tab, event);\r\n \r\n // 路由跳转逻辑(如果需要)\r\n if (tab.route) {\r\n console.log('Navigate to:', tab.route);\r\n // 这里可以集成 vue-router\r\n }\r\n};\r\n\r\nconst handleTabHover = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = tab.id;\r\n emit('tab-hover', tab.id, tab);\r\n};\r\n\r\nconst handleTabLeave = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = null;\r\n emit('tab-leave', tab.id, tab);\r\n};\r\n\r\n// 窗口尺寸变化监听\r\nconst handleResize = () => {\r\n checkMobile();\r\n};\r\n\r\n// 生命周期\r\nonMounted(() => {\r\n checkMobile();\r\n window.addEventListener('resize', handleResize);\r\n});\r\n\r\nonUnmounted(() => {\r\n window.removeEventListener('resize', handleResize);\r\n});\r\n\r\n// 暴露给父组件\r\ndefineExpose({\r\n activeTab,\r\n setActiveTab: (tabId: string) => {\r\n const tab = props.tabs.find(t => t.id === tabId);\r\n if (tab && !tab.disabled) {\r\n activeTab.value = tabId;\r\n emit('tab-change', tabId, tab);\r\n }\r\n },\r\n getActiveTab: () => {\r\n return props.tabs.find(t => t.id === activeTab.value);\r\n },\r\n scrollToTab: (tabId: string) => {\r\n if (!props.scrollable) return;\r\n nextTick(() => {\r\n const tabElement = document.querySelector(`[data-tab-id=\"${tabId}\"]`);\r\n if (tabElement) {\r\n tabElement.scrollIntoView({ behavior: 'smooth', inline: 'center' });\r\n }\r\n });\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.simple-tabs-container {\r\n width: 100%;\r\n}\r\n\r\n.simple-tabs-container.tabs-block {\r\n display: block;\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list {\r\n overflow-x: auto;\r\n scrollbar-width: none; /* Firefox */\r\n -ms-overflow-style: none; /* IE and Edge */\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list::-webkit-scrollbar {\r\n display: none; /* Chrome, Safari, Opera */\r\n}\r\n\r\n.tab-item {\r\n flex-shrink: 0;\r\n position: relative;\r\n}\r\n\r\n.tab-button {\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n}\r\n\r\n.tab-button:focus {\r\n outline: none;\r\n}\r\n\r\n.tab-button:focus-visible {\r\n outline: 2px solid v-bind('computedTheme.indicatorColor');\r\n outline-offset: 2px;\r\n}\r\n\r\n/* 移动端优化 */\r\n.simple-tabs-container.is-mobile .tab-button {\r\n -webkit-touch-callout: none;\r\n -webkit-user-select: none;\r\n -khtml-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n}\r\n\r\n/* 禁用状态样式 */\r\n.tab-disabled .tab-button {\r\n cursor: not-allowed;\r\n}\r\n\r\n/* 响应式样式 */\r\n@media (max-width: 768px) {\r\n .simple-tabs-container.is-mobile .tab-indicator {\r\n left: 0 !important;\r\n right: 0 !important;\r\n }\r\n}\r\n\r\n/* 滚动优化 */\r\n.tabs-scrollable {\r\n position: relative;\r\n}\r\n\r\n.tabs-scrollable::before,\r\n.tabs-scrollable::after {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n bottom: 0;\r\n width: 20px;\r\n pointer-events: none;\r\n z-index: 1;\r\n}\r\n\r\n.tabs-scrollable::before {\r\n left: 0;\r\n background: linear-gradient(to right, v-bind('computedTheme.backgroundColor'), transparent);\r\n}\r\n\r\n.tabs-scrollable::after {\r\n right: 0;\r\n background: linear-gradient(to left, v-bind('computedTheme.backgroundColor'), transparent);\r\n}\r\n\r\n/* 不同尺寸的样式 */\r\n.size-small .tab-button {\r\n min-height: 32px;\r\n}\r\n\r\n.size-medium .tab-button {\r\n min-height: 40px;\r\n}\r\n\r\n.size-large .tab-button {\r\n min-height: 48px;\r\n}\r\n\r\n/* 居中对齐样式 */\r\n.tabs-centered .tabs-list {\r\n justify-content: center;\r\n}\r\n\r\n/* 图标样式 */\r\n.tab-icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.tab-icon svg {\r\n width: 1em;\r\n height: 1em;\r\n fill: currentColor;\r\n}\r\n\r\n/* 指示器样式基类 */\r\n.tab-indicator {\r\n pointer-events: none;\r\n}\r\n\r\n/* 动画性能优化 */\r\n.tab-button,\r\n.tab-indicator {\r\n will-change: color, background-color, transform;\r\n}\r\n\r\n/* 高对比度模式支持 */\r\n@media (prefers-contrast: high) {\r\n .tab-button {\r\n border: 1px solid currentColor;\r\n }\r\n \r\n .tab-indicator {\r\n border: 2px solid currentColor;\r\n }\r\n}\r\n\r\n/* 减少动画模式支持 */\r\n@media (prefers-reduced-motion: reduce) {\r\n .tab-button,\r\n .tab-indicator {\r\n transition: none !important;\r\n }\r\n}\r\n</style>\r\n"],"names":["defaultTheme","sizeConfigs","defaultAnimation","defaultResponsive","indicatorStyles","color","height","getIndicatorStyle","style","mergeConfig","defaultConfig","userConfig","getResponsiveStyle","isMobile","baseStyle","mobileStyle","props","__props","emit","__emit","activeTab","ref","_a","hoveredTab","computedTheme","computed","computedAnimation","computedResponsive","baseStyleConfig","computedStyleConfig","checkMobile","getTabTextColor","tab","getIndicatorStyleComputed","handleTabClick","event","handleTabHover","handleTabLeave","handleResize","onMounted","onUnmounted","__expose","tabId","t","nextTick","tabElement","_createElementBlock","_normalizeStyle","_createElementVNode","_openBlock","_Fragment","_renderList","$event","_hoisted_3","_toDisplayString"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.umd.js","sources":["../src/types.ts","../src/components/ConfigurableSimpleTabs.vue"],"sourcesContent":["// 简洁标签页组件的类型定义\r\n\r\n// 标签项接口\r\nexport interface TabItem {\r\n id: string;\r\n name: string;\r\n disabled?: boolean; // 是否禁用\r\n route?: string; // 可选路由地址\r\n icon?: string; // 可选图标\r\n}\r\n\r\n// 尺寸类型\r\nexport type TabSize = 'small' | 'medium' | 'large';\r\n\r\n// 指示器样式类型\r\nexport type IndicatorStyle = 'line' | 'dot' | 'pill' | 'underline';\r\n\r\n// 主题配置接口\r\nexport interface SimpleTabsTheme {\r\n // 激活状态文字颜色\r\n activeTextColor: string;\r\n // 非激活状态文字颜色\r\n inactiveTextColor: string;\r\n // 悬浮状态文字颜色\r\n hoverTextColor: string;\r\n // 背景色\r\n backgroundColor: string;\r\n // 激活指示器颜色\r\n indicatorColor: string;\r\n // 字体系列\r\n fontFamily: string;\r\n // 边框颜色(如果需要)\r\n borderColor?: string;\r\n // 阴影(如果需要)\r\n boxShadow?: string;\r\n}\r\n\r\n// 样式配置接口\r\nexport interface StyleConfig {\r\n // 内边距\r\n padding: string;\r\n // 字体大小\r\n fontSize: string;\r\n // 字体粗细\r\n fontWeight: string;\r\n // 指示器高度\r\n indicatorHeight: string;\r\n // 指示器样式\r\n indicatorStyle: IndicatorStyle;\r\n // 圆角大小\r\n borderRadius?: string;\r\n // 标签间距\r\n gap?: string;\r\n}\r\n\r\n// 动画配置接口\r\nexport interface AnimationConfig {\r\n // 过渡时长\r\n transitionDuration: string;\r\n // 缓动函数\r\n easing: string;\r\n // 是否启用动画\r\n enabled: boolean;\r\n // 指示器动画时长\r\n indicatorTransition?: string;\r\n}\r\n\r\n// 响应式配置接口\r\nexport interface ResponsiveConfig {\r\n // 移动端断点\r\n mobileBreakpoint: number;\r\n // 移动端样式\r\n mobileStyle?: Partial<StyleConfig>;\r\n // 是否启用响应式\r\n enabled: boolean;\r\n}\r\n\r\n// 主组件Props接口\r\nexport interface SimpleTabsProps {\r\n // 标签页数据\r\n tabs: TabItem[];\r\n\r\n // 默认激活的标签ID\r\n defaultActive?: string;\r\n\r\n // 尺寸\r\n size?: TabSize;\r\n\r\n // 主题配置\r\n theme?: Partial<SimpleTabsTheme>;\r\n\r\n // 样式配置\r\n style?: Partial<StyleConfig>;\r\n\r\n // 动画配置\r\n animation?: Partial<AnimationConfig>;\r\n\r\n // 响应式配置\r\n responsive?: Partial<ResponsiveConfig>;\r\n\r\n // 自定义类名\r\n className?: string;\r\n\r\n // 自定义内联样式\r\n customStyle?: Record<string, any>;\r\n\r\n // 是否显示为块级元素\r\n block?: boolean;\r\n\r\n // 居中对齐\r\n centered?: boolean;\r\n\r\n // 是否可滚动(当标签过多时)\r\n scrollable?: boolean;\r\n}\r\n\r\n// 事件接口\r\nexport interface SimpleTabsEvents {\r\n 'tab-change': [tabId: string, tab: TabItem];\r\n 'tab-click': [tabId: string, tab: TabItem, event: Event];\r\n 'tab-hover': [tabId: string, tab: TabItem];\r\n 'tab-leave': [tabId: string, tab: TabItem];\r\n}\r\n\r\n// 默认主题\r\nexport const defaultTheme: SimpleTabsTheme = {\r\n activeTextColor: 'rgb(20, 23, 26)',\r\n inactiveTextColor: 'rgb(76, 82, 89)',\r\n hoverTextColor: 'rgb(55, 65, 81)',\r\n backgroundColor: '#ffffff',\r\n indicatorColor: 'rgb(20, 23, 26)',\r\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"SF Pro Display\", \"Inter\", sans-serif',\r\n};\r\n\r\n// 尺寸配置\r\nexport const sizeConfigs: Record<TabSize, StyleConfig> = {\r\n small: {\r\n padding: '8px 10px',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '16px',\r\n },\r\n medium: {\r\n padding: '14px 12px',\r\n fontSize: '16px',\r\n fontWeight: '600',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '20px',\r\n },\r\n large: {\r\n padding: '16px 16px',\r\n fontSize: '18px',\r\n fontWeight: '700',\r\n indicatorHeight: '3px',\r\n indicatorStyle: 'line',\r\n gap: '24px',\r\n },\r\n};\r\n\r\n// 默认动画配置\r\nexport const defaultAnimation: AnimationConfig = {\r\n transitionDuration: '0.2s',\r\n easing: 'ease',\r\n enabled: true,\r\n indicatorTransition: '0.3s ease',\r\n};\r\n\r\n// 默认响应式配置\r\nexport const defaultResponsive: ResponsiveConfig = {\r\n mobileBreakpoint: 768,\r\n enabled: true,\r\n mobileStyle: {\r\n padding: '14px 0',\r\n gap: '16px',\r\n },\r\n};\r\n\r\n// 指示器样式映射\r\nexport const indicatorStyles: Record<IndicatorStyle, (color: string, height: string) => Record<string, string>> = {\r\n line: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '12px',\r\n right: '12px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n\r\n underline: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '0',\r\n right: '0',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n\r\n dot: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '50%',\r\n transform: 'translateX(-50%)',\r\n width: height,\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '50%',\r\n }),\r\n\r\n pill: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '8px',\r\n right: '8px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: height,\r\n }),\r\n};\r\n\r\n// 工具函数:获取指示器样式\r\nexport const getIndicatorStyle = (\r\n style: IndicatorStyle,\r\n color: string,\r\n height: string\r\n): Record<string, string> => {\r\n return indicatorStyles[style](color, height);\r\n};\r\n\r\n// 工具函数:合并配置\r\nexport const mergeConfig = <T extends Record<string, any>>(\r\n defaultConfig: T,\r\n userConfig?: Partial<T>\r\n): T => {\r\n return { ...defaultConfig, ...userConfig };\r\n};\r\n\r\n// 工具函数:获取响应式样式\r\nexport const getResponsiveStyle = (\r\n isMobile: boolean,\r\n baseStyle: StyleConfig,\r\n mobileStyle?: Partial<StyleConfig>\r\n): StyleConfig => {\r\n if (!isMobile || !mobileStyle) return baseStyle;\r\n return { ...baseStyle, ...mobileStyle };\r\n};\r\n\r\n","<template>\r\n <div\r\n class=\"simple-tabs-container\"\r\n :class=\"[\r\n `size-${props.size}`,\r\n {\r\n 'tabs-block': props.block,\r\n 'tabs-centered': props.centered,\r\n 'tabs-scrollable': props.scrollable,\r\n 'is-mobile': isMobile,\r\n },\r\n props.className,\r\n ]\"\r\n :style=\"{\r\n backgroundColor: computedTheme.backgroundColor,\r\n boxShadow: computedTheme.boxShadow,\r\n flexShrink: 0,\r\n ...props.customStyle,\r\n }\"\r\n >\r\n <nav>\r\n <ul\r\n class=\"tabs-list\"\r\n :class=\"{\r\n 'flex-wrap': props.scrollable && !isMobile,\r\n 'overflow-x-auto': props.scrollable && isMobile,\r\n }\"\r\n :style=\"{\r\n display: 'flex',\r\n gap: computedStyleConfig.gap,\r\n justifyContent: props.centered ? 'center' : 'flex-start',\r\n margin: 0,\r\n padding: 0,\r\n listStyle: 'none',\r\n }\"\r\n >\r\n <li\r\n v-for=\"tab in props.tabs\"\r\n :key=\"tab.id\"\r\n class=\"tab-item\"\r\n :class=\"{\r\n 'tab-active': activeTab === tab.id,\r\n 'tab-disabled': tab.disabled,\r\n }\"\r\n >\r\n <button\r\n class=\"tab-button\"\r\n :class=\"{\r\n 'tab-button-active': activeTab === tab.id,\r\n 'tab-button-disabled': tab.disabled,\r\n }\"\r\n :disabled=\"tab.disabled\"\r\n :style=\"{\r\n position: 'relative',\r\n display: 'flex',\r\n alignItems: 'center',\r\n background: 'none',\r\n border: 'none',\r\n cursor: tab.disabled ? 'not-allowed' : 'pointer',\r\n textDecoration: 'none',\r\n transition: computedAnimation.enabled\r\n ? `color ${computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n padding: computedStyleConfig.padding,\r\n fontSize: computedStyleConfig.fontSize,\r\n fontWeight: activeTab === tab.id ? '500' : computedStyleConfig.fontWeight,\r\n fontFamily: computedTheme.fontFamily,\r\n color: getTabTextColor(tab),\r\n opacity: tab.disabled ? 0.5 : 1,\r\n borderRadius: computedStyleConfig.borderRadius || '0',\r\n whiteSpace: 'nowrap',\r\n lineHeight: 1.25,\r\n }\"\r\n @click=\"handleTabClick(tab, $event)\"\r\n @mouseenter=\"handleTabHover(tab)\"\r\n @mouseleave=\"handleTabLeave(tab)\"\r\n >\r\n <!-- 图标 -->\r\n <span\r\n v-if=\"tab.icon\"\r\n class=\"tab-icon\"\r\n :style=\"{\r\n marginRight: '8px',\r\n fontSize: '1em',\r\n lineHeight: 1,\r\n }\"\r\n v-html=\"tab.icon\"\r\n />\r\n\r\n <!-- 标签文本 -->\r\n <span class=\"tab-text\">{{ tab.name }}</span>\r\n\r\n <!-- 激活指示器 -->\r\n <span\r\n v-if=\"activeTab === tab.id\"\r\n class=\"tab-indicator\"\r\n :style=\"{\r\n ...getIndicatorStyleComputed(),\r\n transition: computedAnimation.enabled\r\n ? `all ${computedAnimation.indicatorTransition || computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n }\"\r\n />\r\n </button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted, onUnmounted, nextTick } from \"vue\";\r\nimport type { SimpleTabsProps, SimpleTabsEvents, TabItem } from \"../types\";\r\nimport {\r\n defaultTheme,\r\n sizeConfigs,\r\n defaultAnimation,\r\n defaultResponsive,\r\n mergeConfig,\r\n getResponsiveStyle,\r\n getIndicatorStyle,\r\n} from \"../types\";\r\n\r\n// Props定义\r\nconst props = withDefaults(defineProps<SimpleTabsProps>(), {\r\n size: \"medium\",\r\n block: false,\r\n centered: false,\r\n scrollable: false,\r\n});\r\n\r\n// Events定义\r\nconst emit = defineEmits<SimpleTabsEvents>();\r\n\r\n// 响应式状态\r\nconst activeTab = ref(props.defaultActive || props.tabs[0]?.id || \"\");\r\nconst isMobile = ref(false);\r\nconst hoveredTab = ref<string | null>(null);\r\n\r\n// 计算属性\r\nconst computedTheme = computed(() => mergeConfig(defaultTheme, props.theme));\r\n\r\nconst computedAnimation = computed(() =>\r\n mergeConfig(defaultAnimation, props.animation)\r\n);\r\n\r\nconst computedResponsive = computed(() =>\r\n mergeConfig(defaultResponsive, props.responsive)\r\n);\r\n\r\nconst baseStyleConfig = computed(() =>\r\n mergeConfig(sizeConfigs[props.size], props.style)\r\n);\r\n\r\nconst computedStyleConfig = computed(() =>\r\n getResponsiveStyle(\r\n isMobile.value && computedResponsive.value.enabled,\r\n baseStyleConfig.value,\r\n computedResponsive.value.mobileStyle\r\n )\r\n);\r\n\r\n// 工具方法\r\nconst checkMobile = () => {\r\n if (computedResponsive.value.enabled) {\r\n isMobile.value =\r\n window.innerWidth <= computedResponsive.value.mobileBreakpoint;\r\n }\r\n};\r\n\r\nconst getTabTextColor = (tab: TabItem): string => {\r\n if (tab.disabled) {\r\n return computedTheme.value.inactiveTextColor;\r\n }\r\n\r\n if (activeTab.value === tab.id) {\r\n return computedTheme.value.activeTextColor;\r\n }\r\n\r\n if (hoveredTab.value === tab.id) {\r\n return computedTheme.value.hoverTextColor;\r\n }\r\n\r\n return computedTheme.value.inactiveTextColor;\r\n};\r\n\r\nconst getIndicatorStyleComputed = () => {\r\n return getIndicatorStyle(\r\n computedStyleConfig.value.indicatorStyle,\r\n computedTheme.value.indicatorColor,\r\n computedStyleConfig.value.indicatorHeight\r\n );\r\n};\r\n\r\n// 事件处理\r\nconst handleTabClick = (tab: TabItem, event: Event) => {\r\n if (tab.disabled) return;\r\n\r\n activeTab.value = tab.id;\r\n emit(\"tab-change\", tab.id, tab);\r\n emit(\"tab-click\", tab.id, tab, event);\r\n\r\n // 路由跳转逻辑(如果需要)\r\n if (tab.route) {\r\n console.log(\"Navigate to:\", tab.route);\r\n // 这里可以集成 vue-router\r\n }\r\n};\r\n\r\nconst handleTabHover = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = tab.id;\r\n emit(\"tab-hover\", tab.id, tab);\r\n};\r\n\r\nconst handleTabLeave = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = null;\r\n emit(\"tab-leave\", tab.id, tab);\r\n};\r\n\r\n// 窗口尺寸变化监听\r\nconst handleResize = () => {\r\n checkMobile();\r\n};\r\n\r\n// 生命周期\r\nonMounted(() => {\r\n checkMobile();\r\n window.addEventListener(\"resize\", handleResize);\r\n});\r\n\r\nonUnmounted(() => {\r\n window.removeEventListener(\"resize\", handleResize);\r\n});\r\n\r\n// 暴露给父组件\r\ndefineExpose({\r\n activeTab,\r\n setActiveTab: (tabId: string) => {\r\n const tab = props.tabs.find((t) => t.id === tabId);\r\n if (tab && !tab.disabled) {\r\n activeTab.value = tabId;\r\n emit(\"tab-change\", tabId, tab);\r\n }\r\n },\r\n getActiveTab: () => {\r\n return props.tabs.find((t) => t.id === activeTab.value);\r\n },\r\n scrollToTab: (tabId: string) => {\r\n if (!props.scrollable) return;\r\n nextTick(() => {\r\n const tabElement = document.querySelector(`[data-tab-id=\"${tabId}\"]`);\r\n if (tabElement) {\r\n tabElement.scrollIntoView({ behavior: \"smooth\", inline: \"center\" });\r\n }\r\n });\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.simple-tabs-container {\r\n width: 100%;\r\n}\r\n\r\n.simple-tabs-container.tabs-block {\r\n display: block;\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list {\r\n overflow-x: auto;\r\n scrollbar-width: none; /* Firefox */\r\n -ms-overflow-style: none; /* IE and Edge */\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list::-webkit-scrollbar {\r\n display: none; /* Chrome, Safari, Opera */\r\n}\r\n\r\n.tab-item {\r\n flex-shrink: 0;\r\n position: relative;\r\n}\r\n\r\n.tab-button {\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n text-decoration: none;\r\n background: transparent;\r\n border: 0px;\r\n font-size: 16px;\r\n font-weight: 400;\r\n line-height: 1.25;\r\n padding: 14px 12px;\r\n position: relative;\r\n color: v-bind(\"computedTheme.inactiveTextColor\");\r\n font-family: v-bind(\"computedTheme.fontFamily\");\r\n transition: color 0.2s ease;\r\n}\r\n\r\n.tab-button:focus {\r\n outline: none;\r\n}\r\n\r\n.tab-button:focus-visible {\r\n outline: 2px solid v-bind(\"computedTheme.indicatorColor\");\r\n outline-offset: 2px;\r\n}\r\n\r\n.tab-button-active {\r\n color: v-bind(\"computedTheme.activeTextColor\");\r\n font-weight: 500;\r\n}\r\n\r\n.tab-button-active::before {\r\n position: absolute;\r\n background: v-bind(\"computedTheme.indicatorColor\");\r\n height: 2px;\r\n inset: auto 12px 0px;\r\n content: \"\";\r\n}\r\n\r\n/* 移动端优化 */\r\n.simple-tabs-container.is-mobile .tab-button {\r\n -webkit-touch-callout: none;\r\n -webkit-user-select: none;\r\n -khtml-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n}\r\n\r\n/* 禁用状态样式 */\r\n.tab-disabled .tab-button {\r\n cursor: not-allowed;\r\n}\r\n\r\n/* 响应式样式 */\r\n@media (max-width: 768px) {\r\n .simple-tabs-container.is-mobile .tab-button {\r\n padding: 14px 0;\r\n }\r\n\r\n .simple-tabs-container.is-mobile .tab-button-active::before {\r\n inset: auto 0px 0px;\r\n }\r\n\r\n .simple-tabs-container.is-mobile .tab-indicator {\r\n left: 0 !important;\r\n right: 0 !important;\r\n }\r\n}\r\n\r\n/* 滚动优化 */\r\n.tabs-scrollable {\r\n position: relative;\r\n}\r\n\r\n.tabs-scrollable::before,\r\n.tabs-scrollable::after {\r\n content: \"\";\r\n position: absolute;\r\n top: 0;\r\n bottom: 0;\r\n width: 20px;\r\n pointer-events: none;\r\n z-index: 1;\r\n}\r\n\r\n.tabs-scrollable::before {\r\n left: 0;\r\n background: linear-gradient(\r\n to right,\r\n v-bind(\"computedTheme.backgroundColor\"),\r\n transparent\r\n );\r\n}\r\n\r\n.tabs-scrollable::after {\r\n right: 0;\r\n background: linear-gradient(\r\n to left,\r\n v-bind(\"computedTheme.backgroundColor\"),\r\n transparent\r\n );\r\n}\r\n\r\n/* 不同尺寸的样式 */\r\n.size-small .tab-button {\r\n min-height: 32px;\r\n}\r\n\r\n.size-medium .tab-button {\r\n min-height: 40px;\r\n}\r\n\r\n.size-large .tab-button {\r\n min-height: 48px;\r\n}\r\n\r\n/* 居中对齐样式 */\r\n.tabs-centered .tabs-list {\r\n justify-content: center;\r\n}\r\n\r\n/* 图标样式 */\r\n.tab-icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.tab-icon svg {\r\n width: 1em;\r\n height: 1em;\r\n fill: currentColor;\r\n}\r\n\r\n/* 指示器样式基类 */\r\n.tab-indicator {\r\n pointer-events: none;\r\n}\r\n\r\n/* 动画性能优化 */\r\n.tab-button,\r\n.tab-indicator {\r\n will-change: color, background-color, transform;\r\n}\r\n\r\n/* 高对比度模式支持 */\r\n@media (prefers-contrast: high) {\r\n .tab-button {\r\n border: 1px solid currentColor;\r\n }\r\n\r\n .tab-indicator {\r\n border: 2px solid currentColor;\r\n }\r\n}\r\n\r\n/* 减少动画模式支持 */\r\n@media (prefers-reduced-motion: reduce) {\r\n .tab-button,\r\n .tab-indicator {\r\n transition: none !important;\r\n }\r\n}\r\n</style>\r\n\r\n"],"names":["defaultTheme","sizeConfigs","defaultAnimation","defaultResponsive","indicatorStyles","color","height","getIndicatorStyle","style","mergeConfig","defaultConfig","userConfig","getResponsiveStyle","isMobile","baseStyle","mobileStyle","props","__props","emit","__emit","activeTab","ref","_a","hoveredTab","computedTheme","computed","computedAnimation","computedResponsive","baseStyleConfig","computedStyleConfig","checkMobile","getTabTextColor","tab","getIndicatorStyleComputed","handleTabClick","event","handleTabHover","handleTabLeave","handleResize","onMounted","onUnmounted","__expose","tabId","t","nextTick","tabElement","_createElementBlock","_normalizeStyle","_createElementVNode","_openBlock","_Fragment","_renderList","$event","_hoisted_3","_toDisplayString"],"mappings":"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"}
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.simple-tabs-container[data-v-
|
|
1
|
+
.simple-tabs-container[data-v-28fbd600]{width:100%}.simple-tabs-container.tabs-block[data-v-28fbd600]{display:block}.simple-tabs-container.tabs-scrollable .tabs-list[data-v-28fbd600]{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.simple-tabs-container.tabs-scrollable .tabs-list[data-v-28fbd600]::-webkit-scrollbar{display:none}.tab-item[data-v-28fbd600]{flex-shrink:0;position:relative}.tab-button[data-v-28fbd600]{outline:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;cursor:pointer;display:flex;align-items:center;text-decoration:none;background:transparent;border:0px;font-size:16px;font-weight:400;line-height:1.25;padding:14px 12px;position:relative;color:var(--001f7dcf);font-family:var(--78d6cd4f);transition:color .2s ease}.tab-button[data-v-28fbd600]:focus{outline:none}.tab-button[data-v-28fbd600]:focus-visible{outline:2px solid var(--37ab6550);outline-offset:2px}.tab-button-active[data-v-28fbd600]{color:var(--10278ad8);font-weight:500}.tab-button-active[data-v-28fbd600]:before{position:absolute;background:var(--37ab6550);height:2px;inset:auto 12px 0px;content:""}.simple-tabs-container.is-mobile .tab-button[data-v-28fbd600]{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tab-disabled .tab-button[data-v-28fbd600]{cursor:not-allowed}@media (max-width: 768px){.simple-tabs-container.is-mobile .tab-button[data-v-28fbd600]{padding:14px 0}.simple-tabs-container.is-mobile .tab-button-active[data-v-28fbd600]:before{inset:auto 0px 0px}.simple-tabs-container.is-mobile .tab-indicator[data-v-28fbd600]{left:0!important;right:0!important}}.tabs-scrollable[data-v-28fbd600]{position:relative}.tabs-scrollable[data-v-28fbd600]:before,.tabs-scrollable[data-v-28fbd600]:after{content:"";position:absolute;top:0;bottom:0;width:20px;pointer-events:none;z-index:1}.tabs-scrollable[data-v-28fbd600]:before{left:0;background:linear-gradient(to right,var(--6a0edb99),transparent)}.tabs-scrollable[data-v-28fbd600]:after{right:0;background:linear-gradient(to left,var(--6a0edb99),transparent)}.size-small .tab-button[data-v-28fbd600]{min-height:32px}.size-medium .tab-button[data-v-28fbd600]{min-height:40px}.size-large .tab-button[data-v-28fbd600]{min-height:48px}.tabs-centered .tabs-list[data-v-28fbd600]{justify-content:center}.tab-icon[data-v-28fbd600]{display:inline-flex;align-items:center;justify-content:center}.tab-icon svg[data-v-28fbd600]{width:1em;height:1em;fill:currentColor}.tab-indicator[data-v-28fbd600]{pointer-events:none}.tab-button[data-v-28fbd600],.tab-indicator[data-v-28fbd600]{will-change:color,background-color,transform}@media (prefers-contrast: high){.tab-button[data-v-28fbd600]{border:1px solid currentColor}.tab-indicator[data-v-28fbd600]{border:2px solid currentColor}}@media (prefers-reduced-motion: reduce){.tab-button[data-v-28fbd600],.tab-indicator[data-v-28fbd600]{transition:none!important}}
|