This commit is contained in:
oneao committed 2025-09-13 17:28:55 +08:00
1 parent 985b42cafb
commit 5e3dccc88b
25 files changed
+931 -543

No files matched your search

@@ -0,0 +1,82 @@
@use '../_styles/_variables.scss' as *;
$radio-prefix: '#{$prefix}-radio';
.#{$radio-prefix} {
display: inline-flex;
align-items: center;
gap: 8px;
cursor: pointer;
font-size: 14px;
user-select: none;
&-wrapper {
position: relative;
width: 16px;
height: 16px;
input[type='radio'] {
position: absolute;
opacity: 0;
width: 100%;
height: 100%;
margin: 0;
cursor: pointer;
z-index: 2;
}
& .#{$radio-prefix}-circle {
position: absolute;
top: 0;
left: 0;
width: 16px;
height: 16px;
border: 1px solid #d9d9d9;
border-radius: 50%;
background-color: #fff;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}
// 勾选圆点
input[type='radio']:checked + .#{$radio-prefix}-circle::after {
content: '';
width: 8px;
height: 8px;
background-color: #1890ff;
border-radius: 50%;
display: block;
animation: scaleIn 0.2s ease forwards;
box-shadow: 0 0 6px #1890ff33; // #33 = 20% 透明度
}
}
&-content {
display: flex;
flex-direction: column;
}
&-disabled {
cursor: not-allowed;
opacity: 0.5;
}
&-clicked {
.#{$radio-prefix}-circle {
transform: scale(0.9);
transition: transform 0.15s ease;
}
}
}
@keyframes scaleIn {
from {
transform: scale(0);
}
to {
transform: scale(1);
}
}
@@ -0,0 +1,71 @@
import { computed, defineComponent, ref } from 'vue'
import { getPrefixCls } from '../_utils/getPrefixCls'
export default defineComponent({
name: 'AnimatedRadio',
props: {
modelValue: {
type: [String, Number, Boolean],
default: null,
},
value: {
type: [String, Number, Boolean],
required: true,
},
disabled: {
type: Boolean,
default: false,
},
class: {
type: [String, Array, Object],
default: '',
},
style: {
type: Object,
default: () => ({}),
},
},
emits: ['update:modelValue'],
setup(props, { slots, emit }) {
const prefixCls = getPrefixCls('radio')
const isClicked = ref(false)
const checked = computed(() => props.modelValue === props.value)
const handleChange = () => {
if (!props.disabled) {
emit('update:modelValue', props.value)
// 播放点击动画
isClicked.value = true
setTimeout(() => (isClicked.value = false), 300)
}
}
return () => (
<label
class={[
prefixCls,
props.class,
checked.value ? `${prefixCls}-checked` : '',
props.disabled ? `${prefixCls}-disabled` : '',
isClicked.value ? `${prefixCls}-clicked` : '',
]}
style={{ ...props.style }}
>
<div class={`${prefixCls}-wrapper`}>
<input
type="radio"
value={props.value}
checked={checked.value}
disabled={props.disabled}
onChange={handleChange}
/>
<span class={`${prefixCls}-circle`} />
</div>
<div class={`${prefixCls}-content`}>
{slots.default ? slots.default() : null}
</div>
</label>
)
},
})