Files
AIProd/pages/Home/components/ToolItem.vue

190 lines
4.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="tool-card" :class="{ 'checkedBg': item.active, 'hovered': isHover && !item.active }"
@click="handleClick"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave">
<div class="content">
<div class="icon-container">
<img :src="iconBase64 || item.icon || ''" alt="" class="icon-base" />
<img :src="iconSelectedBase64 || item.iconSelected || ''" alt="" class="icon-selected" />
</div>
<span class="text">{{ item.name || '' }}</span>
</div>
</div>
</template>
<script>
export default {
props: {
item: {
type: Object,
required: true
}
},
data() {
return {
iconBase64: '',
iconSelectedBase64: '',
isHover: false
}
},
created() {
// 组件创建时预加载图标
this.preloadIcons();
},
methods: {
// 处理点击事件
handleClick() {
if (this.item.active) {
this.$set(this.item, 'active', false);
} else {
// 先重置所有项,再激活当前项
// 这里我们需要通知父组件来完成全局重置
this.$emit('tool-selected', this.item);
}
},
// 处理鼠标进入事件
handleMouseEnter() {
// 当项已激活时不触发hover效果
if (this.item.active) {
return;
}
this.isHover = true;
},
// 处理鼠标离开事件
handleMouseLeave() {
// 当项已激活时不触发hover效果
if (this.item.active) {
return;
}
this.isHover = false;
},
// 预加载图标并转换为base64
async preloadIcons() {
// 预加载普通图标
if (this.item.icon && this.item.icon !== '') {
try {
this.iconBase64 = await this.convertToBase64(this.item.icon);
} catch (error) {
// console.warn('Failed to load icon:', this.item.icon, error);
}
}
// 预加载选中图标
if (this.item.iconSelected && this.item.iconSelected !== '') {
try {
this.iconSelectedBase64 = await this.convertToBase64(this.item.iconSelected);
} catch (error) {
// console.warn('Failed to load iconSelected:', this.item.iconSelected, error);
}
}
},
// 将图片URL转换为base64
convertToBase64(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'Anonymous'; // 处理跨域问题
img.onload = () => {
try {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const dataURL = canvas.toDataURL('image/png');
resolve(dataURL);
} catch (error) {
reject(error);
}
};
img.onerror = (error) => {
reject(error);
};
img.src = url;
});
}
}
}
</script>
<style lang="scss" scoped>
.tool-card {
background: #FFFFFF;
box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.05);
border-radius: 12px;
padding: 10px 16px;
font-weight: 600;
font-family: 'Poppins-SemiBold';
cursor: pointer;
width: fit-content;
.content {
@include display-flex;
white-space: nowrap;
max-width: 220px;
.icon-container {
position: relative;
width: 24px;
height: 24px;
margin-right: 5px;
}
.icon-base,
.icon-selected {
position: absolute;
top: 0;
left: 0;
width: 24px;
height: 24px;
transition: opacity 0.2s ease;
}
// 基础状态:显示普通图标,隐藏选中图标
.icon-base {
opacity: 1;
}
.icon-selected {
opacity: 0;
}
.text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
// 激活状态样式
.checkedBg {
color: $white;
background: linear-gradient(90deg, $linear-gradient-start 22%, $linear-gradient-end 73%);
.icon-container {
.icon-base {
opacity: 0 !important;
}
.icon-selected {
opacity: 1 !important;
}
}
}
// 悬停状态样式(非激活时)
.hovered {
color: $white;
background: linear-gradient(90deg, $linear-gradient-start 22%, $linear-gradient-end 73%);
// 悬停状态(非激活时):显示选中图标,隐藏普通图标
.icon-container {
.icon-base {
opacity: 0 !important;
}
.icon-selected {
opacity: 1 !important;
}
}
}
</style>