开发预览 更新于 2026-05-10

HotspotImage 图像热区

图像 + 预定义可点击区域(矩形 / 圆形)。SVG overlay 渲染、归一化坐标、悬停高亮 + label tooltip。

基础用法

hotspots 数组定义可点击区域;shape: 'rect'rect: { x, y, w, h }shape: 'circle'circle: { cx, cy, r },全部归一化到图像 0–1 坐标。设 show-outlines 强制描边可见,否则仅 hover 时显示。

背景 视口
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfHotspotImage, type HotspotItem } from '@chufix-design/vue';

const svg =
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 360">' +
  '<rect width="100%" height="100%" fill="#26272a"/>' +
  '<rect x="80" y="80" width="180" height="180" fill="#404048" stroke="#656571" stroke-width="2" rx="8"/>' +
  '<rect x="300" y="150" width="220" height="50" fill="#404048" stroke="#656571" stroke-width="2" rx="4"/>' +
  '<circle cx="450" cy="80" r="48" fill="#404048" stroke="#656571" stroke-width="2"/>' +
  '</svg>';
const imgSrc = `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;

const hotspots: HotspotItem[] = [
  {
    id: 'cpu',
    shape: 'rect',
    rect: { x: 0.13, y: 0.22, w: 0.3, h: 0.5 },
    label: 'CPU 区',
    tone: 'success',
  },
  {
    id: 'pcie',
    shape: 'rect',
    rect: { x: 0.5, y: 0.42, w: 0.36, h: 0.14 },
    label: 'PCIe 插槽',
    tone: 'info',
  },
  {
    id: 'fan',
    shape: 'circle',
    circle: { cx: 0.75, cy: 0.22, r: 0.08 },
    label: '机箱风扇',
    tone: 'warning',
  },
];

const last = ref('点击区域查看坐标');

function onClick(h: HotspotItem) {
  last.value = `clicked: ${h.id} (${h.label ?? '-'})`;
}
</script>
<template>
  <div class="hs-demo">
    <CfHotspotImage
      :src="imgSrc"
      alt="hardware"
      :hotspots="hotspots"
      show-outlines
      @hotspot-click="onClick"
    />
    <code class="hs-demo__meta">{{ last }}</code>
  </div>
</template>
<style scoped>
.hs-demo {
  display: grid;
  gap: 8px;
}
.hs-demo__meta {
  padding: 4px 8px;
  background: var(--bg-inset);
  border-radius: var(--r-2);
  font-size: var(--t-12);
  color: var(--fg-2);
}
</style>
<script setup>
import { ref } from 'vue';
import { CfHotspotImage } from '@chufix-design/vue';

const svg =
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 360">' +
  '<rect width="100%" height="100%" fill="#26272a"/>' +
  '<rect x="80" y="80" width="180" height="180" fill="#404048" stroke="#656571" stroke-width="2" rx="8"/>' +
  '<rect x="300" y="150" width="220" height="50" fill="#404048" stroke="#656571" stroke-width="2" rx="4"/>' +
  '<circle cx="450" cy="80" r="48" fill="#404048" stroke="#656571" stroke-width="2"/>' +
  '</svg>';
const imgSrc = `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;

const hotspots= [
  {
    id: 'cpu',
    shape: 'rect',
    rect: { x: 0.13, y: 0.22, w: 0.3, h: 0.5 },
    label: 'CPU 区',
    tone: 'success',
  },
  {
    id: 'pcie',
    shape: 'rect',
    rect: { x: 0.5, y: 0.42, w: 0.36, h: 0.14 },
    label: 'PCIe 插槽',
    tone: 'info',
  },
  {
    id: 'fan',
    shape: 'circle',
    circle: { cx: 0.75, cy: 0.22, r: 0.08 },
    label: '机箱风扇',
    tone: 'warning',
  },
];

const last = ref('点击区域查看坐标');

function onClick(h) {
  last.value = `clicked: ${h.id} (${h.label ?? '-'})`;
}
</script>
<template>
  <div class="hs-demo">
    <CfHotspotImage
      :src="imgSrc"
      alt="hardware"
      :hotspots="hotspots"
      show-outlines
      @hotspot-click="onClick"
    />
    <code class="hs-demo__meta">{{ last }}</code>
  </div>
</template>
<style scoped>
.hs-demo {
  display: grid;
  gap: 8px;
}
.hs-demo__meta {
  padding: 4px 8px;
  background: var(--bg-inset);
  border-radius: var(--r-2);
  font-size: var(--t-12);
  color: var(--fg-2);
}
</style>
import { useState } from 'react';
import { CfHotspotImage } from '@chufix-design/react';

export default function Demo() {
  const svg =
    '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 360">' +
    '<rect width="100%" height="100%" fill="#26272a"/>' +
    '<rect x="80" y="80" width="180" height="180" fill="#404048" stroke="#656571" stroke-width="2" rx="8"/>' +
    '<rect x="300" y="150" width="220" height="50" fill="#404048" stroke="#656571" stroke-width="2" rx="4"/>' +
    '<circle cx="450" cy="80" r="48" fill="#404048" stroke="#656571" stroke-width="2"/>' +
    '</svg>';
  const imgSrc = `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;

  const hotspots: HotspotItem[] = [
    {
      id: 'cpu',
      shape: 'rect',
      rect: { x: 0.13, y: 0.22, w: 0.3, h: 0.5 },
      label: 'CPU 区',
      tone: 'success',
    },
    {
      id: 'pcie',
      shape: 'rect',
      rect: { x: 0.5, y: 0.42, w: 0.36, h: 0.14 },
      label: 'PCIe 插槽',
      tone: 'info',
    },
    {
      id: 'fan',
      shape: 'circle',
      circle: { cx: 0.75, cy: 0.22, r: 0.08 },
      label: '机箱风扇',
      tone: 'warning',
    },
  ];

  const [last, setLast] = useState('点击区域查看坐标');

  function onClick(h: HotspotItem) {
    setLast(`clicked: ${h.id} (${h.label ?? '-'})`);
  }
  return (
    <>
      <div className="hs-demo">
          <CfHotspotImage src={imgSrc} alt="hardware" hotspots={hotspots} showOutlines onHotspotClick={onClick} />
          <code className="hs-demo__meta">{last}</code>
        </div>
    </>
  );
}
import { useState } from 'react';
import { CfHotspotImage } from '@chufix-design/react';

export default function Demo() {
  const svg =
    '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 360">' +
    '<rect width="100%" height="100%" fill="#26272a"/>' +
    '<rect x="80" y="80" width="180" height="180" fill="#404048" stroke="#656571" stroke-width="2" rx="8"/>' +
    '<rect x="300" y="150" width="220" height="50" fill="#404048" stroke="#656571" stroke-width="2" rx="4"/>' +
    '<circle cx="450" cy="80" r="48" fill="#404048" stroke="#656571" stroke-width="2"/>' +
    '</svg>';
  const imgSrc = `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;

  const hotspots= [
    {
      id: 'cpu',
      shape: 'rect',
      rect: { x: 0.13, y: 0.22, w: 0.3, h: 0.5 },
      label: 'CPU 区',
      tone: 'success',
    },
    {
      id: 'pcie',
      shape: 'rect',
      rect: { x: 0.5, y: 0.42, w: 0.36, h: 0.14 },
      label: 'PCIe 插槽',
      tone: 'info',
    },
    {
      id: 'fan',
      shape: 'circle',
      circle: { cx: 0.75, cy: 0.22, r: 0.08 },
      label: '机箱风扇',
      tone: 'warning',
    },
  ];

  const [last, setLast] = useState('点击区域查看坐标');

  function onClick(h) {
    setLast(`clicked: ${h.id} (${h.label ?? '-'})`);
  }
  return (
    <>
      <div className="hs-demo">
          <CfHotspotImage src={imgSrc} alt="hardware" hotspots={hotspots} showOutlines onHotspotClick={onClick} />
          <code className="hs-demo__meta">{last}</code>
        </div>
    </>
  );
}

API

Props

属性类型默认说明
srcstring图片 URL
altstring''alt
hotspotsHotspotItem[]区域定义
showOutlinesbooleanfalse静态显示描边

Events

事件载荷说明
hotspot-click(hotspot, ev)点击区域
hotspot-hoverhotspot | null悬停

反馈与讨论

HotspotImage 图像热区 的讨论

0
0 / 600
正在加载评论...