@kirkw/vue2-image-hotzone

A Vue 2 component for creating image hotzones with drag, resize and move support
610
Install
npm install @kirkw/vue2-image-hotzone
Latest Version:1.0.3
Vue:2
License:MIT
Last Updated:Sep 8, 2026
Links: GitHub  ·  npm
Maintainer: manongguai

markdown

ImageHotzone - Vue2 图片热区组件

一个功能强大的 Vue 2 图片热区编辑组件,支持拖拽绘制、移动、缩放热区,提供丰富的配置选项和事件系统。

特性

  • 🖱️ 拖拽绘制 - 在图片上按住鼠标拖拽即可创建热区
  • 📐 自由缩放 - 8个手柄支持全方位调整热区大小
  • 🔄 拖拽移动 - 点击热区内部可拖拽移动位置
  • 📱 响应式适配 - 基于百分比坐标,适配所有分辨率
  • 🎨 主题定制 - 完整的配色系统,支持预设主题和自定义
  • ⚙️ 灵活配置 - 丰富的配置选项,满足各种需求
  • 🎯 独立热区控制 - 支持禁用、隐藏、锁定单个热区
  • 📦 数据导入导出 - 支持 JSON 格式的热区数据导入导出
  • ⌨️ 键盘快捷键 - 支持 Delete/Backspace 删除,Escape 取消选择
  • ⚡ 高性能 - 使用 requestAnimationFrame 优化拖拽性能
  • 🔌 完善的事件系统 - 覆盖所有交互事件

安装

直接引入

<script src="./components/ImageHotzone.vue"></script>
模块化引入
javascript
import ImageHotzone from './components/ImageHotzone.vue'

export default {
  components: {
    ImageHotzone
  }
}
全局注册
javascript
// main.js
import Vue from 'vue'
import ImageHotzone from './components/ImageHotzone.vue'

Vue.component('image-hotzone', ImageHotzone)
快速开始
vue
<template>
  <image-hotzone
    ref="hotzone"
    :src="imageUrl"
    :zones.sync="zones"
    :theme="theme"
    :config="config"
    @zone-created="onZoneCreated"
    @zone-updated="onZoneUpdated"
    @zone-deleted="onZoneDeleted"
  />
</template>

<script>
import ImageHotzone from './components/ImageHotzone.vue'

export default {
  components: { ImageHotzone },
  data() {
    return {
      imageUrl: 'https://example.com/image.jpg',
      zones: [],
      theme: {},
      config: {}
    }
  },
  methods: {
    onZoneCreated(zone) {
      console.log('热区创建:', zone)
    },
    onZoneUpdated(zone) {
      console.log('热区更新:', zone)
    },
    onZoneDeleted(zone) {
      console.log('热区删除:', zone)
    }
  }
}
</script>
Props
src
类型: String

必填: true

说明: 图片地址

zones
类型: Array

默认值: []

支持修饰符: .sync

说明: 热区数据数组,支持双向绑定

热区数据结构:

javascript
{
  id: 'unique_id',           // 唯一标识(可选,自动生成)
  x: 20,                     // X坐标(百分比 0-100)
  y: 15,                     // Y坐标(百分比 0-100)
  width: 25,                 // 宽度(百分比 0-100)
  height: 30,                // 高度(百分比 0-100)
  label: '热区名称',          // 标签文本
  title: '热区标题',          // 标题(备用)
  data: {},                  // 自定义数据
  disabled: false,           // 是否禁用
  visible: true,             // 是否可见
  draggable: true,           // 是否可拖拽
  resizable: true,           // 是否可调整大小
  style: {}                  // 自定义样式
}
theme
类型: Object

默认值: {}

说明: 主题配色配置

javascript
{
  // 绘制中虚线框
  drawingLineColor: '#4f6ef7',
  drawingLineWidth: 2,
  drawingFillColor: 'rgba(79, 110, 247, 0.15)',
  
  // 热区默认状态
  zoneBorderColor: '#4f6ef7',
  zoneBorderWidth: 2,
  zoneFillColor: 'rgba(79, 110, 247, 0.2)',
  zoneBorderStyle: 'solid',
  zoneOpacity: 1,
  
  // 热区激活状态
  zoneActiveBorderColor: '#e53e3e',
  zoneActiveFillColor: 'rgba(229, 62, 62, 0.15)',
  zoneActiveBorderStyle: 'solid',
  zoneActiveShadow: '0 0 0 2px rgba(229, 62, 62, 0.3)',
  
  // 热区悬停状态
  zoneHoverBorderColor: '#718096',
  zoneHoverFillColor: 'rgba(113, 128, 150, 0.2)',
  
  // 手柄样式
  handleSize: 10,
  handleColor: '#ffffff',
  handleBorderColor: '#4f6ef7',
  handleBorderWidth: 2,
  handleActiveBorderColor: '#e53e3e',
  handleHoverColor: '#4f6ef7',
  handleActiveHoverColor: '#e53e3e',
  handleBorderRadius: '3px',
  handleShadow: '0 1px 4px rgba(0,0,0,0.15)',
  
  // 标签样式
  labelColor: '#333333',
  labelFontSize: '12px',
  labelFontWeight: '600',
  labelBackgroundColor: 'transparent',
  labelPadding: '2px 4px',
  labelBorderRadius: '0px',
  labelMaxWidth: '90%',
  labelTextShadow: 'none',
  
  // 过渡动画
  transitionDuration: '0s',
  transitionTiming: 'ease'
}
config
类型: Object

默认值: {}

说明: 功能配置

javascript
{
  minSize: 2,              // 最小尺寸(百分比)
  maxZones: 20,            // 最大热区数量
  showLabel: true,         // 是否显示标签
  enableResize: true,      // 是否允许调整大小
  enableMove: true,        // 是否允许移动
  enableDraw: true,        // 是否允许绘制新热区
  enableDelete: true,      // 是否允许删除热区
  showHandles: true,       // 是否显示手柄
  allowOverlap: true,      // 是否允许热区重叠
  snapToGrid: false,       // 是否吸附到网格
  gridSize: 5,             // 网格大小(百分比)
  useAnimationFrame: true, // 使用RAF优化性能
  debounceUpdate: true     // 防抖更新
}
事件
事件名	参数	说明
zone-created	zone	热区创建时触发
zone-updated	zone	热区更新时触发
zone-deleted	zone	热区删除时触发
zone-click	zone	点击热区时触发
zone-focus	zone	热区获得焦点时触发
zone-hover	zone	鼠标进入热区时触发
zone-leave	zone	鼠标离开热区时触发
draw-start	{x, y}	开始绘制时触发
drawing	{x, y, width, height}	绘制过程中触发
draw-end	{x, y, width, height, valid}	绘制结束时触发
drag-start	{zone, handle, type}	开始拖拽时触发
moving	{zone, originalZone}	移动过程中触发
resizing	{zone, handle, originalZone}	调整大小过程中触发
drag-end	{zone, type}	拖拽结束时触发
max-reached	max	达到最大数量时触发
selection-cleared	-	清除选择时触发
all-cleared	-	清除所有热区时触发
zones-imported	count	导入热区完成时触发
resize	{width, height}	容器尺寸变化时触发
change	zones	热区数据变化时触发
方法
通过 ref 调用组件方法:

javascript
const hotzone = this.$refs.hotzone
添加热区
javascript
// 添加单个热区
hotzone.addZone({
  x: 20,
  y: 20,
  width: 30,
  height: 30,
  label: '新热区',
  data: { type: 'custom' }
})

// 批量添加热区
hotzone.addZones([
  { x: 10, y: 10, width: 20, height: 20, label: '热区1' },
  { x: 40, y: 40, width: 25, height: 25, label: '热区2' }
])
更新热区
javascript
// 更新热区属性
hotzone.updateZone('zone_id', {
  label: '新名称',
  x: 30,
  y: 30,
  data: { updated: true },
  style: {
    borderColor: '#48bb78',
    fillColor: 'rgba(72, 187, 120, 0.2)'
  }
})
删除热区
javascript
// 删除指定热区
hotzone.removeZone('zone_id')

// 清除所有热区
hotzone.clearAll()
获取热区
javascript
// 获取激活的热区
const activeZone = hotzone.getActiveZone()

// 获取指定热区
const zone = hotzone.getZone('zone_id')

// 获取所有热区
const allZones = hotzone.getAllZones()
设置激活热区
javascript
// 激活指定热区
hotzone.setActiveZone('zone_id')

// 取消激活
hotzone.setActiveZone(null)
控制热区状态
javascript
// 禁用/启用
hotzone.disableZone('zone_id')
hotzone.enableZone('zone_id')

// 隐藏/显示
hotzone.hideZone('zone_id')
hotzone.showZone('zone_id')
数据导入导出
javascript
// 导出热区数据
const data = hotzone.exportZones()
console.log(JSON.stringify(data, null, 2))

// 导入热区数据
hotzone.importZones(data)
获取容器尺寸
javascript
const size = hotzone.getSize()
console.log(size.width, size.height)
预设主题
组件内置了几种预设主题供参考:

javascript
// 默认蓝色主题
const defaultTheme = {
  drawingLineColor: '#4f6ef7',
  zoneBorderColor: '#4f6ef7',
  zoneFillColor: 'rgba(79, 110, 247, 0.2)',
  zoneActiveBorderColor: '#e53e3e',
  zoneActiveFillColor: 'rgba(229, 62, 62, 0.15)',
}

// 暗色主题
const darkTheme = {
  drawingLineColor: '#a0aec0',
  zoneBorderColor: '#718096',
  zoneFillColor: 'rgba(113, 128, 150, 0.2)',
  zoneActiveBorderColor: '#fbd38d',
  zoneActiveFillColor: 'rgba(251, 211, 141, 0.15)',
  labelColor: '#e2e8f0'
}

// 绿色主题
const greenTheme = {
  drawingLineColor: '#48bb78',
  zoneBorderColor: '#38a169',
  zoneFillColor: 'rgba(56, 161, 105, 0.2)',
  zoneActiveBorderColor: '#f56565',
  zoneActiveFillColor: 'rgba(245, 101, 101, 0.15)',
}

// 海洋主题
const oceanTheme = {
  drawingLineColor: '#00b4d8',
  zoneBorderColor: '#0077b6',
  zoneFillColor: 'rgba(0, 119, 182, 0.2)',
  zoneActiveBorderColor: '#ff6b6b',
  zoneActiveFillColor: 'rgba(255, 107, 107, 0.15)',
  handleBorderRadius: '50%',
  handleSize: 12
}

// 日落主题
const sunsetTheme = {
  drawingLineColor: '#f6ad55',
  zoneBorderColor: '#ed8936',
  zoneFillColor: 'rgba(237, 137, 54, 0.2)',
  zoneActiveBorderColor: '#9f7aea',
  zoneActiveFillColor: 'rgba(159, 122, 234, 0.15)',
  zoneBorderWidth: 3,
  labelColor: '#744210',
  labelFontWeight: 'bold'
}

// 霓虹主题
const neonTheme = {
  drawingLineColor: '#00ff00',
  zoneBorderColor: '#00ff00',
  zoneFillColor: 'rgba(0, 255, 0, 0.1)',
  zoneActiveBorderColor: '#ff00ff',
  zoneActiveFillColor: 'rgba(255, 0, 255, 0.15)',
  zoneActiveShadow: '0 0 10px rgba(255, 0, 255, 0.5)',
  handleBorderRadius: '50%',
  labelColor: '#00ff00'
}
键盘快捷键
快捷键	说明
Delete / Backspace	删除当前激活的热区
Escape	取消当前选择/取消绘制
性能优化
组件内置了多项性能优化措施:

requestAnimationFrame - 拖拽和绘制使用 RAF 优化,避免过度渲染

防抖更新 - 数据更新使用防抖,减少不必要的事件触发

关闭过渡动画 - 拖拽时关闭 CSS 过渡动画,提升响应速度

Resize 防抖 - 窗口大小变化时防抖更新容器尺寸

可在 config 中调整:

javascript
{
  useAnimationFrame: true,  // 是否使用 RAF(推荐开启)
  debounceUpdate: true      // 是否防抖更新(推荐开启)
}
浏览器兼容性
Chrome 60+

Firefox 60+

Safari 12+

Edge 79+

移动端 Safari

移动端 Chrome

License
MIT

更新日志
v1.0.0
✨ 初始版本发布

🎨 支持完整的主题定制

⚡ 使用 RAF 优化拖拽性能

📦 支持热区数据导入导出

⌨️ 支持键盘快捷键

🎯 完善的事件系统

📱 响应式百分比坐标系统

Related Packages

@kirkw/vue3-image-hotzone

A Vue 3 component for creating image hotzones with drag, resize and move support

597 0
vuejs-countdown-timer

Vue 2 countdown and timer component

53,691 48
ner-text-annotation

A vue2component for NER text annotation

458

Version History

Version Released Vue License
1.0.3 ^2.6.0 MIT
1.0.2 ^2.6.0 MIT
1.0.1 ^2.6.0 MIT
1.0.0 ^2.6.0 MIT