2 changed files with 772 additions and 0 deletions
@ -0,0 +1,728 @@ |
|||
<template> |
|||
<div class="context-menu" v-if="visible" :style="positionStyle"> |
|||
<div class="menu-section"> |
|||
<div class="menu-item" @click="handleDelete"> |
|||
<span class="menu-icon">🗑️</span> |
|||
<span>删除</span> |
|||
<span>删除</span> |
|||
<!-- 111 --> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 线段特有选项 --> |
|||
<div class="menu-section" v-if="entityData.type === 'line'"> |
|||
<div class="menu-title">线段属性</div> |
|||
<div class="menu-item" @click="toggleColorPicker('color')"> |
|||
<span class="menu-icon">🎨</span> |
|||
<span>颜色</span> |
|||
<span class="menu-preview" :style="{backgroundColor: entityData.color}"></span> |
|||
</div> |
|||
<!-- 颜色选择器 --> |
|||
<div class="color-picker-container" v-if="showColorPickerFor === 'color'"> |
|||
<div class="color-grid"> |
|||
<div |
|||
v-for="color in presetColors" |
|||
:key="color" |
|||
class="color-item" |
|||
:style="{backgroundColor: color}" |
|||
@click="selectColor('color', color)" |
|||
:class="{ active: entityData.color === color }" |
|||
></div> |
|||
</div> |
|||
</div> |
|||
<div class="menu-item" @click="toggleWidthPicker"> |
|||
<span class="menu-icon">📏</span> |
|||
<span>线宽</span> |
|||
<span class="menu-value">{{ entityData.width }}px</span> |
|||
</div> |
|||
<!-- 线宽选择器 --> |
|||
<div class="width-picker-container" v-if="showWidthPicker"> |
|||
<div class="width-grid"> |
|||
<div |
|||
v-for="width in presetWidths" |
|||
:key="width" |
|||
class="width-item" |
|||
@click="selectWidth(width)" |
|||
:class="{ active: entityData.width === width }" |
|||
> |
|||
{{ width }}px |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="menu-item" @click="toggleBearingTypeMenu"> |
|||
<span class="menu-icon">🧭</span> |
|||
<span>方位角类型</span> |
|||
<span class="menu-value">{{ entityData.bearingType === 'magnetic' ? '磁方位' : '真方位' }}</span> |
|||
</div> |
|||
<!-- 方位角类型选择菜单 --> |
|||
<div class="sub-menu" v-if="showBearingTypeMenu"> |
|||
<div class="sub-menu-item" @click="selectBearingType('true')" :class="{ active: entityData.bearingType === 'true' }"> |
|||
<span>真方位</span> |
|||
</div> |
|||
<div class="sub-menu-item" @click="selectBearingType('magnetic')" :class="{ active: entityData.bearingType === 'magnetic' }"> |
|||
<span>磁方位</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 点特有选项 --> |
|||
<div class="menu-section" v-if="entityData.type === 'point'"> |
|||
<div class="menu-title">点属性</div> |
|||
<div class="menu-item" @click="toggleColorPicker('color')"> |
|||
<span class="menu-icon">🎨</span> |
|||
<span>颜色</span> |
|||
<span class="menu-preview" :style="{backgroundColor: entityData.color}"></span> |
|||
</div> |
|||
<!-- 颜色选择器 --> |
|||
<div class="color-picker-container" v-if="showColorPickerFor === 'color'"> |
|||
<div class="color-grid"> |
|||
<div |
|||
v-for="color in presetColors" |
|||
:key="color" |
|||
class="color-item" |
|||
:style="{backgroundColor: color}" |
|||
@click="selectColor('color', color)" |
|||
:class="{ active: entityData.color === color }" |
|||
></div> |
|||
</div> |
|||
</div> |
|||
<div class="menu-item" @click="toggleSizePicker"> |
|||
<span class="menu-icon">🔵</span> |
|||
<span>大小</span> |
|||
<span class="menu-value">{{ entityData.size }}px</span> |
|||
</div> |
|||
<!-- 大小选择器 --> |
|||
<div class="size-picker-container" v-if="showSizePicker"> |
|||
<div class="size-grid"> |
|||
<div |
|||
v-for="size in presetSizes" |
|||
:key="size" |
|||
class="size-item" |
|||
@click="selectSize(size)" |
|||
:class="{ active: entityData.size === size }" |
|||
> |
|||
{{ size }}px |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 多边形特有选项 --> |
|||
<div class="menu-section" v-if="entityData.type === 'polygon' || entityData.type === 'rectangle' || entityData.type === 'circle' || entityData.type === 'sector'"> |
|||
<div class="menu-title">填充属性</div> |
|||
<div class="menu-item" @click="toggleColorPicker('color')"> |
|||
<span class="menu-icon">🎨</span> |
|||
<span>填充色</span> |
|||
<span class="menu-preview" :style="{backgroundColor: entityData.color}"></span> |
|||
</div> |
|||
<!-- 颜色选择器 --> |
|||
<div class="color-picker-container" v-if="showColorPickerFor === 'color'"> |
|||
<div class="color-grid"> |
|||
<div |
|||
v-for="color in presetColors" |
|||
:key="color" |
|||
class="color-item" |
|||
:style="{backgroundColor: color}" |
|||
@click="selectColor('color', color)" |
|||
:class="{ active: entityData.color === color }" |
|||
></div> |
|||
</div> |
|||
</div> |
|||
<div class="menu-item" @click="toggleOpacityPicker"> |
|||
<span class="menu-icon">🌫️</span> |
|||
<span>透明度</span> |
|||
<span class="menu-value">{{ Math.round(entityData.opacity * 100) }}%</span> |
|||
</div> |
|||
<!-- 透明度选择器 --> |
|||
<div class="opacity-picker-container" v-if="showOpacityPicker"> |
|||
<div class="opacity-grid"> |
|||
<div |
|||
v-for="opacity in presetOpacities" |
|||
:key="opacity" |
|||
class="opacity-item" |
|||
@click="selectOpacity(opacity)" |
|||
:class="{ active: Math.round(entityData.opacity * 100) === Math.round(opacity * 100) }" |
|||
> |
|||
{{ Math.round(opacity * 100) }}% |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="menu-item" @click="toggleColorPicker('borderColor')"> |
|||
<span class="menu-icon">🖌️</span> |
|||
<span>边框色</span> |
|||
<span class="menu-preview" :style="{backgroundColor: entityData.color}"></span> |
|||
</div> |
|||
<!-- 边框颜色选择器 --> |
|||
<div class="color-picker-container" v-if="showColorPickerFor === 'borderColor'"> |
|||
<div class="color-grid"> |
|||
<div |
|||
v-for="color in presetColors" |
|||
:key="color" |
|||
class="color-item" |
|||
:style="{backgroundColor: color}" |
|||
@click="selectColor('borderColor', color)" |
|||
:class="{ active: (entityData.borderColor || entityData.color) === color }" |
|||
></div> |
|||
</div> |
|||
</div> |
|||
<div class="menu-item" @click="toggleWidthPicker"> |
|||
<span class="menu-icon">📏</span> |
|||
<span>边框宽</span> |
|||
<span class="menu-value">{{ entityData.width }}px</span> |
|||
</div> |
|||
<!-- 边框宽度选择器 --> |
|||
<div class="width-picker-container" v-if="showWidthPicker"> |
|||
<div class="width-grid"> |
|||
<div |
|||
v-for="width in presetWidths" |
|||
:key="width" |
|||
class="width-item" |
|||
@click="selectWidth(width)" |
|||
:class="{ active: entityData.width === width }" |
|||
> |
|||
{{ width }}px |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 箭头特有选项 --> |
|||
<div class="menu-section" v-if="entityData.type === 'arrow'"> |
|||
<div class="menu-title">箭头属性</div> |
|||
<div class="menu-item" @click="toggleColorPicker('color')"> |
|||
<span class="menu-icon">🎨</span> |
|||
<span>颜色</span> |
|||
<span class="menu-preview" :style="{backgroundColor: entityData.color}"></span> |
|||
</div> |
|||
<!-- 颜色选择器 --> |
|||
<div class="color-picker-container" v-if="showColorPickerFor === 'color'"> |
|||
<div class="color-grid"> |
|||
<div |
|||
v-for="color in presetColors" |
|||
:key="color" |
|||
class="color-item" |
|||
:style="{backgroundColor: color}" |
|||
@click="selectColor('color', color)" |
|||
:class="{ active: entityData.color === color }" |
|||
></div> |
|||
</div> |
|||
</div> |
|||
<div class="menu-item" @click="toggleWidthPicker"> |
|||
<span class="menu-icon">📏</span> |
|||
<span>线宽</span> |
|||
<span class="menu-value">{{ entityData.width }}px</span> |
|||
</div> |
|||
<!-- 线宽选择器 --> |
|||
<div class="width-picker-container" v-if="showWidthPicker"> |
|||
<div class="width-grid"> |
|||
<div |
|||
v-for="width in presetWidths" |
|||
:key="width" |
|||
class="width-item" |
|||
@click="selectWidth(width)" |
|||
:class="{ active: entityData.width === width }" |
|||
> |
|||
{{ width }}px |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 文本特有选项 --> |
|||
<div class="menu-section" v-if="entityData.type === 'text'"> |
|||
<div class="menu-title">文本属性</div> |
|||
<div class="menu-item" @click="toggleColorPicker('color')"> |
|||
<span class="menu-icon">🎨</span> |
|||
<span>文字颜色</span> |
|||
<span class="menu-preview" :style="{backgroundColor: entityData.color}"></span> |
|||
</div> |
|||
<!-- 颜色选择器 --> |
|||
<div class="color-picker-container" v-if="showColorPickerFor === 'color'"> |
|||
<div class="color-grid"> |
|||
<div |
|||
v-for="color in presetColors" |
|||
:key="color" |
|||
class="color-item" |
|||
:style="{backgroundColor: color}" |
|||
@click="selectColor('color', color)" |
|||
:class="{ active: entityData.color === color }" |
|||
></div> |
|||
</div> |
|||
</div> |
|||
<div class="menu-item" @click="showFontPicker"> |
|||
<span class="menu-icon">📝</span> |
|||
<span>字体</span> |
|||
<span class="menu-value">{{ getFontName(entityData.font) }}</span> |
|||
</div> |
|||
<div class="menu-item" @click="toggleFontSizePicker"> |
|||
<span class="menu-icon">🔤</span> |
|||
<span>字号</span> |
|||
<span class="menu-value">{{ getFontSize(entityData.font) }}px</span> |
|||
</div> |
|||
<!-- 字号选择器 --> |
|||
<div class="font-size-picker-container" v-if="showFontSizePicker"> |
|||
<div class="font-size-grid"> |
|||
<div |
|||
v-for="size in presetFontSizes" |
|||
:key="size" |
|||
class="font-size-item" |
|||
@click="selectFontSize(size)" |
|||
:class="{ active: getFontSize(entityData.font) === size.toString() }" |
|||
> |
|||
{{ size }}px |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'ContextMenu', |
|||
props: { |
|||
visible: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
position: { |
|||
type: Object, |
|||
default: () => ({ x: 0, y: 0 }) |
|||
}, |
|||
entityData: { |
|||
type: Object, |
|||
default: null |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
showColorPickerFor: null, |
|||
showWidthPicker: false, |
|||
showSizePicker: false, |
|||
showOpacityPicker: false, |
|||
showFontSizePicker: false, |
|||
showBearingTypeMenu: false, |
|||
presetColors: [ |
|||
'#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#FF00FF', '#00FFFF', |
|||
'#FF6600', '#663399', '#999999', '#000000', '#FFFFFF', '#FF99CC', |
|||
'#CC99FF', '#99CCFF', '#99FF99', '#FFFF99', '#FFCC99', '#FF9999' |
|||
], |
|||
presetWidths: [1, 2, 3, 4, 5, 6, 8, 10, 12], |
|||
presetSizes: [6, 8, 10, 12, 14, 16, 18, 20, 24], |
|||
presetOpacities: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0], |
|||
presetFontSizes: [8, 10, 12, 14, 16, 18, 20, 24, 28, 32] |
|||
} |
|||
}, |
|||
computed: { |
|||
positionStyle() { |
|||
return { |
|||
left: this.position.x + 'px', |
|||
top: this.position.y + 'px' |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
handleDelete() { |
|||
this.$emit('delete') |
|||
}, |
|||
|
|||
toggleColorPicker(property) { |
|||
if (this.showColorPickerFor === property) { |
|||
this.showColorPickerFor = null |
|||
} else { |
|||
// 隐藏其他选择器 |
|||
this.showWidthPicker = false |
|||
this.showSizePicker = false |
|||
this.showOpacityPicker = false |
|||
this.showFontSizePicker = false |
|||
this.showColorPickerFor = property |
|||
} |
|||
}, |
|||
|
|||
selectColor(property, color) { |
|||
this.$emit('update-property', property, color) |
|||
this.showColorPickerFor = null |
|||
}, |
|||
|
|||
toggleWidthPicker() { |
|||
if (this.showWidthPicker) { |
|||
this.showWidthPicker = false |
|||
} else { |
|||
// 隐藏其他选择器 |
|||
this.showColorPickerFor = null |
|||
this.showSizePicker = false |
|||
this.showOpacityPicker = false |
|||
this.showFontSizePicker = false |
|||
this.showWidthPicker = true |
|||
} |
|||
}, |
|||
|
|||
selectWidth(width) { |
|||
this.$emit('update-property', 'width', width) |
|||
this.showWidthPicker = false |
|||
}, |
|||
|
|||
toggleSizePicker() { |
|||
if (this.showSizePicker) { |
|||
this.showSizePicker = false |
|||
} else { |
|||
// 隐藏其他选择器 |
|||
this.showColorPickerFor = null |
|||
this.showWidthPicker = false |
|||
this.showOpacityPicker = false |
|||
this.showFontSizePicker = false |
|||
this.showSizePicker = true |
|||
} |
|||
}, |
|||
|
|||
selectSize(size) { |
|||
this.$emit('update-property', 'size', size) |
|||
this.showSizePicker = false |
|||
}, |
|||
|
|||
toggleOpacityPicker() { |
|||
if (this.showOpacityPicker) { |
|||
this.showOpacityPicker = false |
|||
} else { |
|||
// 隐藏其他选择器 |
|||
this.showColorPickerFor = null |
|||
this.showWidthPicker = false |
|||
this.showSizePicker = false |
|||
this.showFontSizePicker = false |
|||
this.showOpacityPicker = true |
|||
} |
|||
}, |
|||
|
|||
selectOpacity(opacity) { |
|||
this.$emit('update-property', 'opacity', opacity) |
|||
this.showOpacityPicker = false |
|||
}, |
|||
|
|||
toggleFontSizePicker() { |
|||
if (this.showFontSizePicker) { |
|||
this.showFontSizePicker = false |
|||
} else { |
|||
// 隐藏其他选择器 |
|||
this.showColorPickerFor = null |
|||
this.showWidthPicker = false |
|||
this.showSizePicker = false |
|||
this.showOpacityPicker = false |
|||
this.showFontSizePicker = true |
|||
} |
|||
}, |
|||
|
|||
selectFontSize(size) { |
|||
const fontName = this.getFontName(this.entityData.font) |
|||
this.$emit('update-property', 'font', `${size}px ${fontName}`) |
|||
this.showFontSizePicker = false |
|||
}, |
|||
|
|||
showFontPicker() { |
|||
const fonts = ['Arial', 'Microsoft YaHei', 'SimSun', 'SimHei', 'KaiTi'] |
|||
const fontName = prompt(`请选择字体:\n${fonts.map((f, i) => `${i+1}. ${f}`).join('\n')}\n\n输入序号:`) |
|||
if (fontName && !isNaN(fontName) && fonts[parseInt(fontName)-1]) { |
|||
const selectedFont = fonts[parseInt(fontName)-1] |
|||
const fontSize = this.getFontSize(this.entityData.font) |
|||
this.$emit('update-property', 'font', `${fontSize}px ${selectedFont}`) |
|||
} |
|||
}, |
|||
|
|||
getFontName(font) { |
|||
const match = font.match(/\d+px\s+(.+)/) |
|||
return match ? match[1] : 'Arial' |
|||
}, |
|||
|
|||
getFontSize(font) { |
|||
const match = font.match(/(\d+)px/) |
|||
return match ? match[1] : '14' |
|||
}, |
|||
|
|||
toggleBearingTypeMenu() { |
|||
// 切换方位角类型选择菜单的显示/隐藏 |
|||
this.showBearingTypeMenu = !this.showBearingTypeMenu |
|||
// 隐藏其他选择器 |
|||
if (this.showBearingTypeMenu) { |
|||
this.showColorPickerFor = null |
|||
this.showWidthPicker = false |
|||
this.showSizePicker = false |
|||
this.showOpacityPicker = false |
|||
this.showFontSizePicker = false |
|||
} |
|||
}, |
|||
|
|||
selectBearingType(bearingType) { |
|||
// 选择方位角类型 |
|||
this.$emit('update-property', 'bearingType', bearingType) |
|||
this.showBearingTypeMenu = false |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.context-menu { |
|||
position: fixed; |
|||
z-index: 9999; |
|||
background: white; |
|||
border-radius: 8px; |
|||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15); |
|||
padding: 8px 0; |
|||
min-width: 180px; |
|||
max-width: 220px; |
|||
} |
|||
|
|||
.menu-section { |
|||
margin-bottom: 8px; |
|||
} |
|||
|
|||
.menu-section:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.menu-title { |
|||
padding: 4px 16px; |
|||
font-size: 12px; |
|||
color: #666; |
|||
font-weight: 600; |
|||
text-transform: uppercase; |
|||
letter-spacing: 0.5px; |
|||
} |
|||
|
|||
.menu-item { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 8px 16px; |
|||
cursor: pointer; |
|||
transition: background-color 0.2s; |
|||
} |
|||
|
|||
.menu-item:hover { |
|||
background-color: #f5f5f5; |
|||
} |
|||
|
|||
.menu-icon { |
|||
margin-right: 8px; |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.menu-preview { |
|||
margin-left: auto; |
|||
width: 16px; |
|||
height: 16px; |
|||
border-radius: 2px; |
|||
border: 1px solid #ddd; |
|||
} |
|||
|
|||
.menu-value { |
|||
margin-left: auto; |
|||
font-size: 12px; |
|||
color: #666; |
|||
min-width: 40px; |
|||
text-align: right; |
|||
} |
|||
|
|||
.menu-item span { |
|||
flex: 1; |
|||
} |
|||
|
|||
/* 颜色选择器样式 */ |
|||
.color-picker-container { |
|||
padding: 8px 16px; |
|||
background-color: #f9f9f9; |
|||
border-top: 1px solid #eee; |
|||
border-bottom: 1px solid #eee; |
|||
} |
|||
|
|||
.color-grid { |
|||
display: grid; |
|||
grid-template-columns: repeat(6, 1fr); |
|||
gap: 6px; |
|||
} |
|||
|
|||
.color-item { |
|||
width: 24px; |
|||
height: 24px; |
|||
border-radius: 4px; |
|||
cursor: pointer; |
|||
transition: transform 0.2s, box-shadow 0.2s; |
|||
border: 1px solid #ddd; |
|||
} |
|||
|
|||
.color-item:hover { |
|||
transform: scale(1.1); |
|||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); |
|||
} |
|||
|
|||
.color-item.active { |
|||
transform: scale(1.2); |
|||
box-shadow: 0 0 0 2px white, 0 0 0 3px #007bff; |
|||
} |
|||
|
|||
/* 线宽选择器样式 */ |
|||
.width-picker-container { |
|||
padding: 8px 16px; |
|||
background-color: #f9f9f9; |
|||
border-top: 1px solid #eee; |
|||
border-bottom: 1px solid #eee; |
|||
} |
|||
|
|||
.width-grid { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 1fr); |
|||
gap: 6px; |
|||
} |
|||
|
|||
.width-item { |
|||
padding: 6px 8px; |
|||
background-color: white; |
|||
border: 1px solid #ddd; |
|||
border-radius: 4px; |
|||
text-align: center; |
|||
cursor: pointer; |
|||
transition: all 0.2s; |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.width-item:hover { |
|||
background-color: #e3f2fd; |
|||
border-color: #2196f3; |
|||
} |
|||
|
|||
.width-item.active { |
|||
background-color: #2196f3; |
|||
color: white; |
|||
border-color: #1976d2; |
|||
} |
|||
|
|||
/* 大小选择器样式 */ |
|||
.size-picker-container { |
|||
padding: 8px 16px; |
|||
background-color: #f9f9f9; |
|||
border-top: 1px solid #eee; |
|||
border-bottom: 1px solid #eee; |
|||
} |
|||
|
|||
.size-grid { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 1fr); |
|||
gap: 6px; |
|||
} |
|||
|
|||
.size-item { |
|||
padding: 6px 8px; |
|||
background-color: white; |
|||
border: 1px solid #ddd; |
|||
border-radius: 4px; |
|||
text-align: center; |
|||
cursor: pointer; |
|||
transition: all 0.2s; |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.size-item:hover { |
|||
background-color: #e3f2fd; |
|||
border-color: #2196f3; |
|||
} |
|||
|
|||
.size-item.active { |
|||
background-color: #2196f3; |
|||
color: white; |
|||
border-color: #1976d2; |
|||
} |
|||
|
|||
/* 透明度选择器样式 */ |
|||
.opacity-picker-container { |
|||
padding: 8px 16px; |
|||
background-color: #f9f9f9; |
|||
border-top: 1px solid #eee; |
|||
border-bottom: 1px solid #eee; |
|||
} |
|||
|
|||
.opacity-grid { |
|||
display: grid; |
|||
grid-template-columns: repeat(5, 1fr); |
|||
gap: 4px; |
|||
} |
|||
|
|||
.opacity-item { |
|||
padding: 4px 6px; |
|||
background-color: white; |
|||
border: 1px solid #ddd; |
|||
border-radius: 4px; |
|||
text-align: center; |
|||
cursor: pointer; |
|||
transition: all 0.2s; |
|||
font-size: 10px; |
|||
} |
|||
|
|||
.opacity-item:hover { |
|||
background-color: #e3f2fd; |
|||
border-color: #2196f3; |
|||
} |
|||
|
|||
.opacity-item.active { |
|||
background-color: #2196f3; |
|||
color: white; |
|||
border-color: #1976d2; |
|||
} |
|||
|
|||
/* 字号选择器样式 */ |
|||
.font-size-picker-container { |
|||
padding: 8px 16px; |
|||
background-color: #f9f9f9; |
|||
border-top: 1px solid #eee; |
|||
border-bottom: 1px solid #eee; |
|||
} |
|||
|
|||
.font-size-grid { |
|||
display: grid; |
|||
grid-template-columns: repeat(5, 1fr); |
|||
gap: 4px; |
|||
} |
|||
|
|||
.font-size-item { |
|||
padding: 4px 6px; |
|||
background-color: white; |
|||
border: 1px solid #ddd; |
|||
border-radius: 4px; |
|||
text-align: center; |
|||
cursor: pointer; |
|||
transition: all 0.2s; |
|||
font-size: 10px; |
|||
} |
|||
|
|||
.font-size-item:hover { |
|||
background-color: #e3f2fd; |
|||
border-color: #2196f3; |
|||
} |
|||
|
|||
.font-size-item.active { |
|||
background-color: #2196f3; |
|||
color: white; |
|||
border-color: #1976d2; |
|||
} |
|||
|
|||
/* 子菜单样式 */ |
|||
.sub-menu { |
|||
background-color: #f9f9f9; |
|||
border-top: 1px solid #eee; |
|||
border-bottom: 1px solid #eee; |
|||
padding: 4px 0; |
|||
} |
|||
|
|||
.sub-menu-item { |
|||
padding: 6px 16px 6px 32px; |
|||
cursor: pointer; |
|||
transition: background-color 0.2s; |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.sub-menu-item:hover { |
|||
background-color: #e3f2fd; |
|||
} |
|||
|
|||
.sub-menu-item.active { |
|||
background-color: #2196f3; |
|||
color: white; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,44 @@ |
|||
<template> |
|||
<div class="hover-tooltip" v-if="visible"> |
|||
<div class="tooltip-content"> |
|||
{{ content }} |
|||
</div> |
|||
<span>删除</span> |
|||
</div> |
|||
</template> |
|||
<!-- 111 --> |
|||
<script> |
|||
export default { |
|||
name: 'HoverTooltip', |
|||
props: { |
|||
visible: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
content: { |
|||
type: String, |
|||
default: '' |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.hover-tooltip { |
|||
position: absolute; |
|||
z-index: 9999; |
|||
background: rgba(0, 0, 0, 0.8); |
|||
color: white; |
|||
padding: 8px 12px; |
|||
border-radius: 4px; |
|||
font-size: 14px; |
|||
pointer-events: none; |
|||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
.tooltip-content { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue