u
This commit is contained in:
1 parent
8bd73b3786
commit
554fe2945f
15 files changed
+531
-159
No files matched your search
@@ -1,17 +1,7 @@
|
||||
$prefix: 'ao' !default;
|
||||
|
||||
// 主色系
|
||||
$primary-color: #1677ff !default;
|
||||
$primary-hover-color: #0958d9 !default;
|
||||
|
||||
// 功能色
|
||||
$success-color: #52c41a !default;
|
||||
$danger-color: #ff4d4f !default;
|
||||
$warning-color: #faad14 !default;
|
||||
$info-color: #13c2c2 !default;
|
||||
|
||||
// 中性色
|
||||
$background-color: #f5f7fa !default;
|
||||
$border-color: #d9d9d9 !default;
|
||||
$text-color: #000000de !default;
|
||||
$text-secondary-color: #595959 !default;
|
||||
$default-color: #0064fa !default;
|
||||
$primary-color: $default-color !default;
|
||||
$danger-color: #f93920 !default;
|
||||
$warning-color: #fc8800 !default;
|
||||
$success-color: #22c55e !default;
|
||||
@@ -1,29 +1,198 @@
|
||||
@import '../_styles/theme/index.scss';
|
||||
@use 'sass:color';
|
||||
@use '../_styles/theme/index' as *;
|
||||
|
||||
// 按钮基础样式示例
|
||||
.#{$prefix}-btn {
|
||||
padding: 6px 16px;
|
||||
border-radius: 4px;
|
||||
$btn-prefix: #{$prefix}-btn;
|
||||
$btn-hover-bgcolor: #f4f5f5;
|
||||
$btn-active-bgcolor: #eceded;
|
||||
|
||||
/* ====== 通用颜色交互函数 ====== */
|
||||
@function color-hover($color, $amount: 8%) {
|
||||
$l: color.lightness($color);
|
||||
@if $l > 50% {
|
||||
@return color.adjust($color, $lightness: -$amount);
|
||||
} @else {
|
||||
@return color.adjust($color, $lightness: $amount);
|
||||
}
|
||||
}
|
||||
|
||||
@function color-active($color, $amount: 12%) {
|
||||
$l: color.lightness($color);
|
||||
@if $l > 50% {
|
||||
@return color.adjust($color, $lightness: -$amount);
|
||||
} @else {
|
||||
@return color.adjust($color, $lightness: $amount);
|
||||
}
|
||||
}
|
||||
|
||||
.#{$btn-prefix} {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
border-radius: 3px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
font-weight: 600;
|
||||
|
||||
&-default {
|
||||
background: #fff;
|
||||
border-color: $border-color;
|
||||
color: $text-secondary-color;
|
||||
&-block {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-primary {
|
||||
background: $primary-color;
|
||||
color: #fff;
|
||||
&-icon-left {
|
||||
margin-right: 4px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
&-icon-right {
|
||||
margin-left: 4px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $primary-hover-color;
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* ===== Solid 按钮 ===== */
|
||||
&-solid {
|
||||
@each $status,
|
||||
$color
|
||||
in (
|
||||
normal: #d9d9d9,
|
||||
primary: $primary-color,
|
||||
danger: $danger-color,
|
||||
warning: $warning-color,
|
||||
success: $success-color
|
||||
)
|
||||
{
|
||||
&.#{$btn-prefix}-status-#{$status} {
|
||||
@if $status == normal {
|
||||
background: #f4f5f5;
|
||||
color: #000;
|
||||
&:hover:enabled {
|
||||
background: #eceded;
|
||||
}
|
||||
&:active:enabled {
|
||||
background: #e4e4e5;
|
||||
}
|
||||
} @else {
|
||||
background: $color;
|
||||
color: #fff;
|
||||
border: 1px solid transparent;
|
||||
&:hover:enabled {
|
||||
background: color-hover($color, 5%);
|
||||
}
|
||||
&:active:enabled {
|
||||
background: color-active($color, -5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-danger {
|
||||
background: $danger-color;
|
||||
color: #fff;
|
||||
/* ===== Outline 按钮 ===== */
|
||||
&-outline {
|
||||
font-weight: 500;
|
||||
background: transparent;
|
||||
|
||||
@each $status,
|
||||
$color
|
||||
in (
|
||||
normal: $primary-color,
|
||||
primary: $primary-color,
|
||||
danger: $danger-color,
|
||||
warning: $warning-color,
|
||||
success: $success-color
|
||||
)
|
||||
{
|
||||
&.#{$btn-prefix}-status-#{$status} {
|
||||
color: if($status == normal, #000, $color);
|
||||
border-color: if($status == normal, #d9d9d9, $color);
|
||||
&:hover:enabled {
|
||||
background-color: $btn-hover-bgcolor;
|
||||
}
|
||||
&:active:enabled {
|
||||
background-color: $btn-active-bgcolor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Dashed 按钮 ===== */
|
||||
&-dashed {
|
||||
font-weight: 500;
|
||||
background: transparent;
|
||||
border: 1px dashed currentColor;
|
||||
|
||||
@each $status,
|
||||
$color
|
||||
in (
|
||||
normal: #000,
|
||||
primary: $primary-color,
|
||||
danger: $danger-color,
|
||||
warning: $warning-color,
|
||||
success: $success-color
|
||||
)
|
||||
{
|
||||
&.#{$btn-prefix}-status-#{$status} {
|
||||
color: $color;
|
||||
border-color: if($status == normal, #d9d9d9, $color);
|
||||
&:hover:enabled {
|
||||
background-color: $btn-hover-bgcolor;
|
||||
}
|
||||
&:active:enabled {
|
||||
background-color: $btn-active-bgcolor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Text 按钮 ===== */
|
||||
&-text {
|
||||
font-weight: 500;
|
||||
background: transparent;
|
||||
border: none;
|
||||
|
||||
@each $status,
|
||||
$color
|
||||
in (
|
||||
normal: #000,
|
||||
primary: $primary-color,
|
||||
danger: $danger-color,
|
||||
warning: $warning-color,
|
||||
success: $success-color
|
||||
)
|
||||
{
|
||||
&.#{$btn-prefix}-status-#{$status} {
|
||||
color: $color;
|
||||
&:hover:enabled {
|
||||
background-color: $btn-hover-bgcolor;
|
||||
}
|
||||
&:active:enabled {
|
||||
background-color: $btn-active-bgcolor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 尺寸 ===== */
|
||||
&-small {
|
||||
height: 24px;
|
||||
padding: 0 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
&-medium {
|
||||
height: 28px;
|
||||
padding: 0 14px;
|
||||
font-size: 14px;
|
||||
}
|
||||
&-large {
|
||||
height: 32px;
|
||||
padding: 0 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,70 @@
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||
import Icon from '../icon'
|
||||
import './index.scss'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'AButton',
|
||||
name: 'Button',
|
||||
props: {
|
||||
type: { type: String as () => 'primary' | 'danger' | 'default', default: 'default' },
|
||||
type: {
|
||||
type: String as () => 'solid' | 'outline' | 'text' | 'dashed',
|
||||
default: 'solid',
|
||||
},
|
||||
status: {
|
||||
type: String as () => 'primary' | 'danger' | 'warning' | 'success' | 'normal',
|
||||
default: 'normal',
|
||||
},
|
||||
disabled: { type: Boolean, default: false },
|
||||
loading: { type: Boolean, default: false },
|
||||
icon: { type: String, default: '' },
|
||||
iconPosition: { type: String as () => 'left' | 'right', default: 'left' },
|
||||
size: { type: String as () => 'small' | 'medium' | 'large', default: 'medium' },
|
||||
block: { type: Boolean, default: false },
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
const prefixCls = getPrefixCls('btn')
|
||||
const cls = computed(() => [prefixCls, `${prefixCls}-${props.type}`])
|
||||
return () => <button class={cls.value}>{slots.default?.()}</button>
|
||||
|
||||
const cls = computed(() => [
|
||||
prefixCls,
|
||||
`${prefixCls}-${props.type}`,
|
||||
`${prefixCls}-status-${props.status}`,
|
||||
`${prefixCls}-${props.size}`,
|
||||
props.block && `${prefixCls}-block`,
|
||||
])
|
||||
|
||||
const iconSize = computed(() => {
|
||||
const map = { small: 14, medium: 16, large: 16 }
|
||||
return map[props.size]
|
||||
})
|
||||
|
||||
return () => (
|
||||
<button class={cls.value} disabled={props.disabled || props.loading}>
|
||||
{/* 左侧图标 */}
|
||||
{props.iconPosition === 'left' && (props.loading || props.icon) && (
|
||||
<Icon
|
||||
icon={props.loading ? 'mingcute:loading-line' : props.icon}
|
||||
class={`${prefixCls}-icon-left`}
|
||||
spin={props.loading}
|
||||
width={iconSize.value}
|
||||
height={iconSize.value}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 插槽文本 */}
|
||||
<span>
|
||||
{slots.default?.()}
|
||||
</span>
|
||||
|
||||
{/* 右侧图标 */}
|
||||
{props.iconPosition === 'right' && props.icon && (
|
||||
<Icon
|
||||
icon={props.icon}
|
||||
class={`${prefixCls}-icon-right`}
|
||||
width={iconSize.value}
|
||||
height={iconSize.value}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -2,3 +2,4 @@ export { default as ConfigProvider } from './_config'
|
||||
export { default as Button } from './button'
|
||||
export { default as Icon } from './icon'
|
||||
export { default as Input } from './input'
|
||||
export { default as Spin } from './spin'
|
||||
@@ -0,0 +1,12 @@
|
||||
@use '../_styles/theme/index' as *;
|
||||
|
||||
.#{$prefix}-icon-spin {
|
||||
animation: spin 1s linear infinite;
|
||||
--rotate-angle: 360deg;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(var(--rotate-angle));
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,32 @@
|
||||
import type { PropType } from 'vue'
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { defineComponent } from 'vue'
|
||||
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||
import './index.scss'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'AIcon',
|
||||
name: 'Icon',
|
||||
props: {
|
||||
icon: { type: String as PropType<string>, required: true },
|
||||
width: { type: String, default: '24px' },
|
||||
height: { type: String, default: '24px' },
|
||||
color: { type: String, default: 'currentColor' }, // 默认颜色使用 currentColor,支持继承父元素的颜色
|
||||
width: { type: Number, default: 16 },
|
||||
height: { type: Number, default: 16 },
|
||||
color: { type: String, default: 'currentColor' },
|
||||
spin: { type: Boolean, default: false },
|
||||
rotate: { type: Number, default: 360 },
|
||||
},
|
||||
setup(props) {
|
||||
const prefixCls = getPrefixCls('icon')
|
||||
return () => (
|
||||
<Icon
|
||||
icon={props.icon}
|
||||
width={props.width}
|
||||
height={props.height}
|
||||
style={{ color: props.color, verticalAlign: 'middle' }}
|
||||
style={{
|
||||
'color': props.color,
|
||||
'verticalAlign': 'middle',
|
||||
'--rotate-angle': `${props.rotate}deg`,
|
||||
}}
|
||||
class={props.spin ? `${prefixCls}-spin` : ''}
|
||||
/>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
@import './button/index.scss';
|
||||
@use './button/index.scss' as *;
|
||||
@use './input/index.scss' as *;
|
||||
@@ -0,0 +1,7 @@
|
||||
@use '../_styles/theme/index' as *;
|
||||
|
||||
$input-prefix: #{$prefix}-input;
|
||||
|
||||
.#{$input-prefix} {
|
||||
border-color: #d9d9d9;
|
||||
}
|
||||
@@ -1,63 +1,23 @@
|
||||
import type { PropType } from 'vue'
|
||||
import { computed, defineComponent, ref, toRefs } from 'vue'
|
||||
import { computed, defineComponent, ref } from 'vue'
|
||||
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Input',
|
||||
props: {
|
||||
modelValue: { type: String, default: '' },
|
||||
placeholder: { type: String, default: '' },
|
||||
type: { type: String as PropType<'text' | 'password' | 'number'>, default: 'text' },
|
||||
disabled: { type: Boolean, default: false },
|
||||
clearable: { type: Boolean, default: false },
|
||||
},
|
||||
emits: ['update:modelValue', 'change', 'focus', 'blur'],
|
||||
setup(props, { emit }) {
|
||||
name: 'AInput',
|
||||
setup() {
|
||||
const inputRef = ref<HTMLInputElement | null>(null)
|
||||
|
||||
const handleInput = (e: Event) => {
|
||||
const value = (e.target as HTMLInputElement).value
|
||||
emit('update:modelValue', value)
|
||||
emit('change', value)
|
||||
}
|
||||
|
||||
const handleClear = () => {
|
||||
emit('update:modelValue', '')
|
||||
inputRef.value?.focus()
|
||||
emit('change', '')
|
||||
}
|
||||
|
||||
const showClear = computed(() => props.clearable && !!props.modelValue && !props.disabled)
|
||||
// 使用统一前缀
|
||||
const prefixCls = getPrefixCls('input')
|
||||
const cls = computed(() => [prefixCls])
|
||||
|
||||
return () => (
|
||||
<div class="a-input-wrapper" style={{ position: 'relative', display: 'inline-block' }}>
|
||||
<div class={`${prefixCls}-wrapper`} style={{ display: 'inline-block' }}>
|
||||
<input
|
||||
ref={inputRef}
|
||||
class="a-input"
|
||||
type={props.type}
|
||||
placeholder={props.placeholder}
|
||||
value={props.modelValue}
|
||||
disabled={props.disabled}
|
||||
onInput={handleInput}
|
||||
onFocus={e => emit('focus', e)}
|
||||
onBlur={e => emit('blur', e)}
|
||||
style={{ paddingRight: showClear.value ? '24px' : '8px' }}
|
||||
class={cls.value}
|
||||
type="text"
|
||||
placeholder="请输入"
|
||||
/>
|
||||
{showClear.value && (
|
||||
<span
|
||||
class="a-input-clear"
|
||||
onClick={handleClear}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: '4px',
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
cursor: 'pointer',
|
||||
fontSize: '12px',
|
||||
}}
|
||||
>
|
||||
×
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
@use '../_styles/theme/index' as *;
|
||||
|
||||
$spin-prefix: #{$prefix}-spin;
|
||||
|
||||
.#{$spin-prefix}-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.#{$spin-prefix} {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10;
|
||||
|
||||
&-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
&-tip {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
&.rounded {
|
||||
border-radius: inherit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { PropType } from 'vue'
|
||||
import { defineComponent } from 'vue'
|
||||
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||
import Icon from '../icon'
|
||||
import './index.scss'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Spin',
|
||||
props: {
|
||||
loading: { type: Boolean, default: false },
|
||||
opacity: { type: Number as PropType<number>, default: 0.6 },
|
||||
rounded: { type: Boolean, default: true },
|
||||
icon: { type: String as PropType<string>, default: 'mingcute:loading-line' },
|
||||
size: { type: Number as PropType<number>, default: 16 },
|
||||
rotate: { type: Number as PropType<number>, default: 360 },
|
||||
tip: { type: String as PropType<string>, default: '' },
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
const prefixCls = getPrefixCls('spin')
|
||||
|
||||
return () => {
|
||||
if (!props.loading && !slots.default)
|
||||
return null
|
||||
|
||||
return (
|
||||
<div class={`${prefixCls}-wrapper`}>
|
||||
{slots.default?.()}
|
||||
{props.loading && (
|
||||
<div
|
||||
class={`${prefixCls}`}
|
||||
style={{
|
||||
background: slots.default ? `rgba(255,255,255,${props.opacity})` : 'transparent',
|
||||
borderRadius: props.rounded ? '4px' : 0,
|
||||
}}
|
||||
>
|
||||
<div class={`${prefixCls}-content`}>
|
||||
<Icon
|
||||
icon={props.icon}
|
||||
width={props.size}
|
||||
height={props.size}
|
||||
spin
|
||||
rotate={props.rotate}
|
||||
/>
|
||||
{props.tip && <span class={`${prefixCls}-tip`}>{props.tip}</span>}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -2,9 +2,114 @@
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AConfigProvider>
|
||||
<AButton type="primary">
|
||||
按钮 A
|
||||
<!-- 状态按钮 (solid) -->
|
||||
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
|
||||
<AButton status="normal">
|
||||
Normal
|
||||
</AButton>
|
||||
</AConfigProvider>
|
||||
<AButton status="primary">
|
||||
主按钮
|
||||
</AButton>
|
||||
<AButton status="warning">
|
||||
警告
|
||||
</AButton>
|
||||
<AButton status="danger">
|
||||
危险
|
||||
</AButton>
|
||||
<AButton status="success">
|
||||
成功
|
||||
</AButton>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
|
||||
<AButton status="normal" type="outline">
|
||||
Normal
|
||||
</AButton>
|
||||
<AButton status="primary" type="outline">
|
||||
主按钮
|
||||
</AButton>
|
||||
<AButton status="warning" type="outline">
|
||||
警告
|
||||
</AButton>
|
||||
<AButton status="danger" type="outline">
|
||||
危险
|
||||
</AButton>
|
||||
<AButton status="success" type="outline">
|
||||
成功
|
||||
</AButton>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
|
||||
<AButton status="normal" type="dashed">
|
||||
Normal
|
||||
</AButton>
|
||||
<AButton status="primary" type="dashed">
|
||||
主按钮
|
||||
</AButton>
|
||||
<AButton status="warning" type="dashed">
|
||||
警告
|
||||
</AButton>
|
||||
<AButton status="danger" type="dashed">
|
||||
危险
|
||||
</AButton>
|
||||
<AButton status="success" type="dashed">
|
||||
成功
|
||||
</AButton>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
|
||||
<AButton status="normal" type="text">
|
||||
Normal
|
||||
</AButton>
|
||||
<AButton status="primary" type="text">
|
||||
主按钮
|
||||
</AButton>
|
||||
<AButton status="warning" type="text">
|
||||
警告
|
||||
</AButton>
|
||||
<AButton status="danger" type="text">
|
||||
危险
|
||||
</AButton>
|
||||
<AButton status="success" type="text">
|
||||
成功
|
||||
</AButton>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
|
||||
<AButton status="normal" disabled>
|
||||
禁用
|
||||
</AButton>
|
||||
<AButton status="primary" disabled>
|
||||
禁用
|
||||
</AButton>
|
||||
<AButton type="outline" disabled>
|
||||
禁用
|
||||
</AButton>
|
||||
<AButton type="dashed" disabled>
|
||||
禁用
|
||||
</AButton>
|
||||
<AButton type="text" disabled>
|
||||
禁用
|
||||
</AButton>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
|
||||
<AButton status="normal" loading>
|
||||
loading
|
||||
</AButton>
|
||||
<AButton status="primary" loading>
|
||||
loading
|
||||
</AButton>
|
||||
<AButton type="outline" loading>
|
||||
loading
|
||||
</AButton>
|
||||
<AButton type="dashed" loading>
|
||||
loading
|
||||
</AButton>
|
||||
<AButton type="text" loading>
|
||||
loading
|
||||
</AButton>
|
||||
</div>
|
||||
|
||||
<AInput />
|
||||
</template>
|
||||
@@ -12,5 +12,8 @@ declare module 'vue' {
|
||||
AConfigProvider: typeof import('@ao/ao-design')['ConfigProvider']
|
||||
AIcon: typeof import('@ao/ao-design')['Icon']
|
||||
AInput: typeof import('@ao/ao-design')['Input']
|
||||
ALoading: typeof import('@ao/ao-design')['Loading']
|
||||
ALoding: typeof import('@ao/ao-design')['Loding']
|
||||
ASpin: typeof import('@ao/ao-design')['Spin']
|
||||
}
|
||||
}
|
||||
@@ -1 +1,5 @@
|
||||
@import '@ao/ao-design/index.scss';
|
||||
@use '@ao/ao-design/index.scss' as *;
|
||||
|
||||
body {
|
||||
font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Arial, sans-serif;
|
||||
}
|
||||
@@ -1,79 +1,46 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>后台低交互按钮(纯 CSS 自动亮暗)</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>AntD 风格按钮点击反馈</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #2563eb;
|
||||
--secondary-color: #6b7280;
|
||||
--danger-color: #dc2626;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background: #f8fafc;
|
||||
padding: 40px;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 36px;
|
||||
}
|
||||
|
||||
/* 基础按钮样式 */
|
||||
.btn {
|
||||
padding: 6px 22px;
|
||||
border-radius: 0px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
background-color: #1677ff; /* 主色 */
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 10px 24px;
|
||||
font-size: 16px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
position: relative;
|
||||
outline: none;
|
||||
transition: background-color 0.1s ease;
|
||||
}
|
||||
|
||||
/* 主色按钮 */
|
||||
.btn-primary {
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background-color: color-mix(in srgb, var(--primary-color) 90%, white 10%);
|
||||
}
|
||||
.btn-primary:active {
|
||||
background-color: color-mix(in srgb, var(--primary-color) 90%, black 10%);
|
||||
/* hover 高亮 */
|
||||
.btn:hover:not(:disabled) {
|
||||
background-color: #4096ff; /* 调亮 */
|
||||
}
|
||||
|
||||
/* 次色按钮 */
|
||||
.btn-secondary {
|
||||
background-color: var(--secondary-color);
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background-color: color-mix(in srgb, var(--secondary-color) 90%, white 10%);
|
||||
}
|
||||
.btn-secondary:active {
|
||||
background-color: color-mix(in srgb, var(--secondary-color) 90%, black 10%);
|
||||
/* 按下 active 效果 */
|
||||
.btn:active:not(:disabled) {
|
||||
background-color: #0958d9; /* 调暗 */
|
||||
transform: translateY(1px); /* 轻微下移,模拟按下 */
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); /* 按下阴影 */
|
||||
}
|
||||
|
||||
/* 危险按钮 */
|
||||
.btn-danger {
|
||||
background-color: var(--danger-color);
|
||||
}
|
||||
.btn-danger:hover {
|
||||
background-color: color-mix(in srgb, var(--danger-color) 90%, white 10%);
|
||||
}
|
||||
.btn-danger:active {
|
||||
background-color: color-mix(in srgb, var(--danger-color) 90%, black 10%);
|
||||
/* disabled 状态 */
|
||||
.btn:disabled {
|
||||
background-color: #cfe0ff;
|
||||
color: #a0bfff;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>后台低交互按钮(纯 CSS 自动亮暗)</h1>
|
||||
|
||||
<div class="row">
|
||||
<button class="btn btn-primary">确认</button>
|
||||
<button class="btn btn-secondary">取消</button>
|
||||
<button class="btn btn-danger">删除</button>
|
||||
</div>
|
||||
<button class="btn">Primary Button</button>
|
||||
<button class="btn" disabled>Disabled</button>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user