🚧 development of image display interfaces
This commit is contained in:
187
src/components/MyUI/CheckCard/CheckCard.vue
Normal file
187
src/components/MyUI/CheckCard/CheckCard.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<div class="check-card" :class="{ 'selected': isSelected }" @click="handleClick" :style="cardStyle">
|
||||
<div class="hover-circle" @click.stop="toggleSelection"
|
||||
v-if="showHoverCircle"
|
||||
:style="{ width: iconSize + 'px', height: iconSize + 'px' }">
|
||||
<img :src="greyComplete" alt="Hover" class="hover-icon"
|
||||
:style="{ width: iconSize + 'px', height: iconSize + 'px' }"/>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div class="card-selected-icon" v-if="isSelected" :class="iconPositionClass"
|
||||
:style="{ width: iconSize + 'px', height: iconSize + 'px' }">
|
||||
<img :src="icon" alt="Selected" class="selected-icon"
|
||||
@click.stop="toggleSelection"
|
||||
:style="{ width: iconSize + 'px', height: iconSize + 'px' }"/>
|
||||
<img :src="cancel" alt="Delete" class="delete-icon" @click.stop="toggleSelection"
|
||||
:style="{ width: iconSize + 'px', height: iconSize + 'px' }"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import complete from '@/assets/svgs/complete.svg';
|
||||
import cancel from '@/assets/svgs/cancle.svg';
|
||||
import greyComplete from '@/assets/svgs/grey-complete.svg';
|
||||
|
||||
interface Props {
|
||||
value: string | number;
|
||||
modelValue?: (string | number)[];
|
||||
icon?: string;
|
||||
iconPosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
||||
margin?: string;
|
||||
borderRadius?: string;
|
||||
backgroundColor?: string;
|
||||
showHoverCircle?: boolean; // 控制是否显示悬停圆环
|
||||
iconSize?: number; // 控制图标大小
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
icon: complete,
|
||||
iconPosition: 'top-left',
|
||||
margin: '16px',
|
||||
borderRadius: '8px',
|
||||
backgroundColor: '#e5eeff',
|
||||
showHoverCircle: true, // 默认显示悬停圆环
|
||||
iconSize: 24, // 默认图标大小
|
||||
});
|
||||
|
||||
const emits = defineEmits(['update:modelValue']);
|
||||
|
||||
const isSelected = computed(() => {
|
||||
return props.modelValue?.includes(props.value);
|
||||
});
|
||||
|
||||
const iconPositionClass = computed(() => {
|
||||
return `icon-${props.iconPosition}`;
|
||||
});
|
||||
|
||||
const cardStyle = computed(() => {
|
||||
return {
|
||||
margin: props.margin,
|
||||
borderRadius: props.borderRadius,
|
||||
backgroundColor: props.backgroundColor,
|
||||
};
|
||||
});
|
||||
|
||||
function handleClick() {
|
||||
if (!props.showHoverCircle) {
|
||||
toggleSelection();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSelection() {
|
||||
if (isSelected.value) {
|
||||
emits('update:modelValue', props.modelValue?.filter((val) => val !== props.value));
|
||||
} else {
|
||||
emits('update:modelValue', [...(props.modelValue || []), props.value]);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.check-card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.3s, background-color 0.3s;
|
||||
overflow: visible; /* Ensure the icon is not cut off */
|
||||
}
|
||||
.check-card.selected {
|
||||
border: 1px solid rgba(125, 167, 255, 0.68);
|
||||
box-shadow: 0 0 2px rgba(77, 167, 255, 0.89);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.card-selected-icon {
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
border-radius: 50%; /* Optional: Make it circular */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #ccc; /* Optional: Add a border */
|
||||
}
|
||||
|
||||
.icon-top-left {
|
||||
top: 3px;
|
||||
left: 3px;
|
||||
}
|
||||
|
||||
.icon-top-right {
|
||||
top: 3px;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
.icon-bottom-left {
|
||||
bottom: 3px;
|
||||
left: 3px;
|
||||
}
|
||||
|
||||
.icon-bottom-right {
|
||||
bottom: 3px;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
.card-selected-icon img {
|
||||
z-index: 3; /* Ensure the icon is on top */
|
||||
}
|
||||
|
||||
.selected-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.delete-icon {
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card-selected-icon:hover .selected-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card-selected-icon:hover .delete-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hover-circle {
|
||||
position: absolute;
|
||||
top: 3px; /* 与 .card-selected-icon 的 top 值相同 */
|
||||
left: 3px; /* 与 .card-selected-icon 的 left 值相同 */
|
||||
border: 2px solid white; /* 与 .card-selected-icon 的 border 值相同 */
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
z-index: 1; /* Ensure the hover circle is on top */
|
||||
opacity: 0;
|
||||
transform: scale(0); /* 初始状态为0 */
|
||||
transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out; /* 添加动画效果 */
|
||||
}
|
||||
|
||||
.hover-circle .hover-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.check-card:hover .hover-circle {
|
||||
opacity: 1; /* 鼠标悬停时变为可见 */
|
||||
transform: scale(1); /* 鼠标悬停时放大到1倍 */
|
||||
}
|
||||
|
||||
.check-card:hover .hover-circle .hover-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.check-card.selected:hover .hover-circle {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
@@ -156,7 +156,7 @@ function onChecked() {
|
||||
|
||||
&:not(.checkbox-disabled):hover {
|
||||
.checkbox-box {
|
||||
border-color: @themeColor;
|
||||
border-color: #40a9ff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,8 +195,8 @@ function onChecked() {
|
||||
}
|
||||
|
||||
.checkbox-checked {
|
||||
background-color: @themeColor;
|
||||
border-color: @themeColor;
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
|
||||
&::after {
|
||||
opacity: 1;
|
||||
@@ -211,7 +211,7 @@ function onChecked() {
|
||||
left: 50%;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: @themeColor;
|
||||
background-color: #40a9ff;
|
||||
border: 0;
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
opacity: 1;
|
||||
|
@@ -70,7 +70,7 @@ const showAfter = computed(() => {
|
||||
return slotsExist.addonAfter || props.addonAfter;
|
||||
});
|
||||
const lazyInput = computed(() => {
|
||||
return 'lazy' in props.valueModifiers;
|
||||
return 'lazy.ts' in props.valueModifiers;
|
||||
});
|
||||
|
||||
function onInput(e: InputEvent) {
|
||||
|
@@ -70,7 +70,7 @@ const showBefore = computed(() => {
|
||||
return slotsExist.addonBefore || props.addonBefore;
|
||||
});
|
||||
const lazyInput = computed(() => {
|
||||
return 'lazy' in props.valueModifiers;
|
||||
return 'lazy.ts' in props.valueModifiers;
|
||||
});
|
||||
|
||||
function onInput(e: InputEvent) {
|
||||
|
@@ -67,7 +67,7 @@ const showCountNum = computed(() => {
|
||||
return props.value.length;
|
||||
});
|
||||
const lazyTextarea = computed(() => {
|
||||
return 'lazy' in props.valueModifiers;
|
||||
return 'lazy.ts' in props.valueModifiers;
|
||||
});
|
||||
watch(
|
||||
() => props.value,
|
||||
|
Reference in New Issue
Block a user