v3-comf-dm 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../packages/components/ScaleContainer/index.vue","../packages/components/ImageCropper/index.vue","../packages/install.ts","../packages/utils/index.ts","../packages/index.ts"],"sourcesContent":["<template>\r\n <div ref=\"scaleContainer\" class=\"vc-scale-container\" :style=\"containerStyle\">\r\n <div class=\"vc-scale-wrapper\" :style=\"wrapperStyle\">\r\n <slot></slot>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted, onBeforeUnmount, nextTick } from 'vue'\r\nimport type { ScaleContainerProps } from './types'\r\n\r\nconst props = withDefaults(defineProps<ScaleContainerProps>(), {\r\n designWidth: 1920,\r\n designHeight: 1080,\r\n keepAspectRatio: true,\r\n scaleMode: 'fit',\r\n detectBrowserZoom: true,\r\n})\r\n\r\nconst scaleContainer = ref<HTMLElement | null>(null)\r\nconst scale = ref(1)\r\nconst scaleX = ref(1)\r\nconst scaleY = ref(1)\r\nconst containerWidth = ref(1920)\r\nconst containerHeight = ref(1080)\r\n\r\n// 容器样式\r\nconst containerStyle = computed(() => ({\r\n width: `${containerWidth.value}px`,\r\n height: `${containerHeight.value}px`,\r\n position: 'relative' as const,\r\n overflow: 'hidden' as const,\r\n}))\r\n\r\n// 包装器样式\r\nconst wrapperStyle = computed(() => {\r\n const commonStyle = {\r\n width: `${props.designWidth}px`,\r\n height: `${props.designHeight}px`,\r\n transformOrigin: 'top left' as const,\r\n }\r\n\r\n if (props.keepAspectRatio && (props.scaleMode === 'fit' || props.scaleMode === 'fill')) {\r\n const sw = props.designWidth * scale.value\r\n const sh = props.designHeight * scale.value\r\n return {\r\n ...commonStyle,\r\n transform: `scale(${scale.value})`,\r\n position: 'absolute' as const,\r\n top: '50%',\r\n left: '50%',\r\n marginTop: `-${sh / 2}px`,\r\n marginLeft: `-${sw / 2}px`,\r\n }\r\n }\r\n\r\n return {\r\n ...commonStyle,\r\n transform: `scale(${scaleX.value}, ${scaleY.value})`,\r\n }\r\n})\r\n\r\nconst updateScale = () => {\r\n const el = scaleContainer.value\r\n if (!el || !el.parentElement) return\r\n\r\n const parent = el.parentElement\r\n let pw = parent.clientWidth || window.innerWidth\r\n let ph = parent.clientHeight || window.innerHeight\r\n\r\n if (pw === 0) pw = window.innerWidth\r\n if (ph === 0) ph = window.innerHeight\r\n\r\n containerWidth.value = pw\r\n containerHeight.value = ph\r\n\r\n const sx = pw / props.designWidth\r\n const sy = ph / props.designHeight\r\n\r\n if (props.scaleMode === 'stretch') {\r\n scaleX.value = sx\r\n scaleY.value = sy\r\n } else if (props.keepAspectRatio) {\r\n scale.value = props.scaleMode === 'fit' ? Math.min(sx, sy) : Math.max(sx, sy)\r\n } else {\r\n scaleX.value = sx\r\n scaleY.value = sy\r\n }\r\n}\r\n\r\nlet resizeObserver: ResizeObserver | null = null\r\nconst handleResize = () => updateScale()\r\n\r\nonMounted(() => {\r\n nextTick(() => {\r\n updateScale()\r\n window.addEventListener('resize', handleResize)\r\n\r\n if (window.ResizeObserver && scaleContainer.value?.parentElement) {\r\n resizeObserver = new ResizeObserver(handleResize)\r\n resizeObserver.observe(scaleContainer.value.parentElement)\r\n }\r\n })\r\n})\r\n\r\nonBeforeUnmount(() => {\r\n window.removeEventListener('resize', handleResize)\r\n if (resizeObserver) {\r\n resizeObserver.disconnect()\r\n }\r\n})\r\n\r\ndefineOptions({\r\n name: 'VcScaleContainer'\r\n})\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.vc-scale-container {\r\n margin: 0;\r\n padding: 0;\r\n display: block;\r\n}\r\n.vc-scale-wrapper {\r\n box-sizing: border-box;\r\n display: block;\r\n}\r\n</style>\r\n","<template>\r\n <div ref=\"containerRef\" class=\"vc-image-cropper\" :style=\"containerStyle\" tabindex=\"0\">\r\n <div v-if=\"!imageSrc\" class=\"vc-image-cropper-placeholder\">\r\n <div class=\"placeholder-content\">\r\n <svg\r\n width=\"64\"\r\n height=\"64\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"></rect>\r\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"></circle>\r\n <polyline points=\"21 15 16 10 5 21\"></polyline>\r\n </svg>\r\n <p>请选择图片</p>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"vc-image-cropper-content\" ref=\"contentRef\">\r\n <div\r\n ref=\"imageWrapperRef\"\r\n class=\"vc-image-wrapper\"\r\n :style=\"imageWrapperStyle\"\r\n @mousedown=\"handleMouseDown\"\r\n @wheel.prevent=\"handleWheel\"\r\n >\r\n <img\r\n ref=\"imageRef\"\r\n :src=\"imageSrc\"\r\n :style=\"imageStyle\"\r\n @load=\"handleImageLoad\"\r\n draggable=\"false\"\r\n />\r\n\r\n <!-- 裁剪框 -->\r\n <div\r\n v-if=\"imageLoaded\"\r\n ref=\"cropBoxRef\"\r\n class=\"vc-crop-box\"\r\n :style=\"cropBoxStyle\"\r\n @mousedown.stop=\"handleCropBoxMouseDown\"\r\n >\r\n <!-- 网格线 -->\r\n <div v-if=\"showGrid\" class=\"vc-crop-grid\">\r\n <div class=\"grid-line grid-line-h1\"></div>\r\n <div class=\"grid-line grid-line-h2\"></div>\r\n <div class=\"grid-line grid-line-v1\"></div>\r\n <div class=\"grid-line grid-line-v2\"></div>\r\n </div>\r\n\r\n <!-- 控制点 -->\r\n <div\r\n v-for=\"(handle, index) in cropHandles\"\r\n :key=\"index\"\r\n class=\"vc-crop-handle\"\r\n :class=\"handle.class\"\r\n :style=\"handle.style\"\r\n @mousedown.stop=\"handleResizeStart($event, handle.type)\"\r\n ></div>\r\n </div>\r\n </div>\r\n\r\n <!-- 工具栏 -->\r\n <div v-if=\"imageLoaded\" class=\"vc-cropper-toolbar\">\r\n <div v-if=\"zoomable\" class=\"toolbar-group\">\r\n <label class=\"toolbar-label\">缩放:</label>\r\n <input\r\n v-model.number=\"zoom\"\r\n type=\"range\"\r\n :min=\"minZoom\"\r\n :max=\"maxZoom\"\r\n :step=\"0.1\"\r\n class=\"toolbar-slider\"\r\n @input=\"handleZoomChange\"\r\n />\r\n <span class=\"toolbar-value\">{{ Math.round(zoom * 100) }}%</span>\r\n </div>\r\n\r\n <div v-if=\"rotatable\" class=\"toolbar-group\">\r\n <button class=\"toolbar-btn\" @click=\"rotateImage(-90)\" title=\"逆时针旋转\">↺</button>\r\n <button class=\"toolbar-btn\" @click=\"rotateImage(90)\" title=\"顺时针旋转\">↻</button>\r\n </div>\r\n\r\n <div class=\"toolbar-group\">\r\n <button class=\"toolbar-btn toolbar-btn-primary\" @click=\"handleCrop\">确认裁剪</button>\r\n <button class=\"toolbar-btn\" @click=\"handleCancel\">取消</button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'\r\nimport type { ImageCropperProps, ImageCropperEmits, CropArea } from './types'\r\n\r\nconst props = withDefaults(defineProps<ImageCropperProps>(), {\r\n cropMode: 'free',\r\n minWidth: 50,\r\n minHeight: 50,\r\n showGrid: true,\r\n rotatable: true,\r\n zoomable: true,\r\n initialZoom: 1,\r\n containerWidth: '100%',\r\n containerHeight: '600px',\r\n})\r\n\r\nconst emit = defineEmits<ImageCropperEmits>()\r\n\r\n// Refs\r\nconst containerRef = ref<HTMLElement | null>(null)\r\nconst contentRef = ref<HTMLElement | null>(null)\r\nconst imageWrapperRef = ref<HTMLElement | null>(null)\r\nconst imageRef = ref<HTMLImageElement | null>(null)\r\nconst cropBoxRef = ref<HTMLElement | null>(null)\r\n\r\n// 状态\r\nconst imageLoaded = ref(false)\r\nconst imageNaturalWidth = ref(0)\r\nconst imageNaturalHeight = ref(0)\r\nconst imageDisplayWidth = ref(0)\r\nconst imageDisplayHeight = ref(0)\r\nconst rotation = ref(0)\r\nconst zoom = ref(props.initialZoom)\r\nconst minZoom = ref(0.1)\r\nconst maxZoom = ref(5)\r\n\r\n// 裁剪区域(相对于图片的坐标)\r\nconst cropArea = ref<CropArea>({\r\n x: 0,\r\n y: 0,\r\n width: 0,\r\n height: 0,\r\n})\r\n\r\n// 拖拽状态\r\nconst isDragging = ref(false)\r\nconst isResizing = ref(false)\r\nconst dragType = ref<string>('')\r\nconst dragStart = ref({ x: 0, y: 0 })\r\nconst cropStart = ref<CropArea>({ x: 0, y: 0, width: 0, height: 0 })\r\n\r\n// 容器样式\r\nconst containerStyle = computed(() => ({\r\n width:\r\n typeof props.containerWidth === 'number' ? `${props.containerWidth}px` : props.containerWidth,\r\n height:\r\n typeof props.containerHeight === 'number'\r\n ? `${props.containerHeight}px`\r\n : props.containerHeight,\r\n}))\r\n\r\n// 图片包装器样式\r\nconst imageWrapperStyle = computed(() => ({\r\n transform: `rotate(${rotation.value}deg) scale(${zoom.value})`,\r\n transformOrigin: 'center center',\r\n}))\r\n\r\n// 图片样式\r\nconst imageStyle = computed(() => ({\r\n width: `${imageDisplayWidth.value}px`,\r\n height: `${imageDisplayHeight.value}px`,\r\n display: 'block',\r\n}))\r\n\r\n// 裁剪框样式\r\nconst cropBoxStyle = computed(() => ({\r\n left: `${cropArea.value.x}px`,\r\n top: `${cropArea.value.y}px`,\r\n width: `${cropArea.value.width}px`,\r\n height: `${cropArea.value.height}px`,\r\n}))\r\n\r\n// 裁剪控制点\r\nconst cropHandles = computed(() => {\r\n return [\r\n { type: 'nw', class: 'handle-nw', style: { top: '-4px', left: '-4px', cursor: 'nwse-resize' } },\r\n {\r\n type: 'ne',\r\n class: 'handle-ne',\r\n style: { top: '-4px', right: '-4px', cursor: 'nesw-resize' },\r\n },\r\n {\r\n type: 'sw',\r\n class: 'handle-sw',\r\n style: { bottom: '-4px', left: '-4px', cursor: 'nesw-resize' },\r\n },\r\n {\r\n type: 'se',\r\n class: 'handle-se',\r\n style: { bottom: '-4px', right: '-4px', cursor: 'nwse-resize' },\r\n },\r\n {\r\n type: 'n',\r\n class: 'handle-n',\r\n style: { top: '-4px', left: '50%', transform: 'translateX(-50%)', cursor: 'ns-resize' },\r\n },\r\n {\r\n type: 's',\r\n class: 'handle-s',\r\n style: { bottom: '-4px', left: '50%', transform: 'translateX(-50%)', cursor: 'ns-resize' },\r\n },\r\n {\r\n type: 'w',\r\n class: 'handle-w',\r\n style: { top: '50%', left: '-4px', transform: 'translateY(-50%)', cursor: 'ew-resize' },\r\n },\r\n {\r\n type: 'e',\r\n class: 'handle-e',\r\n style: { top: '50%', right: '-4px', transform: 'translateY(-50%)', cursor: 'ew-resize' },\r\n },\r\n ]\r\n})\r\n\r\n// 图片加载完成\r\nconst handleImageLoad = () => {\r\n if (!imageRef.value) return\r\n\r\n imageNaturalWidth.value = imageRef.value.naturalWidth\r\n imageNaturalHeight.value = imageRef.value.naturalHeight\r\n\r\n nextTick(() => {\r\n updateImageDisplaySize()\r\n initCropArea()\r\n imageLoaded.value = true\r\n emit('ready')\r\n })\r\n}\r\n\r\n// 更新图片显示尺寸\r\nconst updateImageDisplaySize = () => {\r\n if (!contentRef.value || !imageRef.value) return\r\n\r\n // 使用内容区域的尺寸作为参考\r\n const containerWidth = contentRef.value.clientWidth\r\n const containerHeight = contentRef.value.clientHeight\r\n\r\n if (containerWidth === 0 || containerHeight === 0) return\r\n\r\n const naturalAspect = imageNaturalWidth.value / imageNaturalHeight.value\r\n const containerAspect = containerWidth / containerHeight\r\n\r\n if (naturalAspect > containerAspect) {\r\n // 图片较宽,以容器宽度为准\r\n imageDisplayWidth.value = containerWidth * 0.9\r\n imageDisplayHeight.value = (containerWidth * 0.9) / naturalAspect\r\n } else {\r\n // 图片较高,以容器高度为准\r\n imageDisplayHeight.value = containerHeight * 0.9\r\n imageDisplayWidth.value = containerHeight * 0.9 * naturalAspect\r\n }\r\n}\r\n\r\n// 初始化裁剪区域\r\nconst initCropArea = () => {\r\n const width = imageDisplayWidth.value\r\n const height = imageDisplayHeight.value\r\n const size = Math.min(width, height) * 0.8\r\n\r\n let cropWidth = size\r\n let cropHeight = size\r\n\r\n if (props.cropMode === 'fixed') {\r\n cropWidth = props.fixedWidth || size\r\n cropHeight = props.fixedHeight || size\r\n } else if (props.cropMode === 'ratio' && props.aspectRatio) {\r\n if (width / height > props.aspectRatio) {\r\n cropHeight = size\r\n cropWidth = size * props.aspectRatio\r\n } else {\r\n cropWidth = size\r\n cropHeight = size / props.aspectRatio\r\n }\r\n }\r\n\r\n cropArea.value = {\r\n x: (width - cropWidth) / 2,\r\n y: (height - cropHeight) / 2,\r\n width: cropWidth,\r\n height: cropHeight,\r\n }\r\n}\r\n\r\n// 鼠标按下(拖拽图片)\r\nconst handleMouseDown = (e: MouseEvent) => {\r\n if (e.target !== imageWrapperRef.value) return\r\n isDragging.value = true\r\n dragStart.value = { x: e.clientX, y: e.clientY }\r\n document.addEventListener('mousemove', handleMouseMove)\r\n document.addEventListener('mouseup', handleMouseUp)\r\n e.preventDefault()\r\n}\r\n\r\n// 裁剪框鼠标按下\r\nconst handleCropBoxMouseDown = (e: MouseEvent) => {\r\n if (e.target === cropBoxRef.value) {\r\n isDragging.value = true\r\n dragType.value = 'crop-box'\r\n dragStart.value = { x: e.clientX, y: e.clientY }\r\n cropStart.value = { ...cropArea.value }\r\n document.addEventListener('mousemove', handleMouseMove)\r\n document.addEventListener('mouseup', handleMouseUp)\r\n e.preventDefault()\r\n }\r\n}\r\n\r\n// 开始调整大小\r\nconst handleResizeStart = (e: MouseEvent, type: string) => {\r\n isResizing.value = true\r\n dragType.value = type\r\n dragStart.value = { x: e.clientX, y: e.clientY }\r\n cropStart.value = { ...cropArea.value }\r\n document.addEventListener('mousemove', handleMouseMove)\r\n document.addEventListener('mouseup', handleMouseUp)\r\n e.preventDefault()\r\n}\r\n\r\n// 鼠标移动\r\nconst handleMouseMove = (e: MouseEvent) => {\r\n if (!contentRef.value) return\r\n\r\n // 计算鼠标在屏幕上的移动距离,并除以缩放倍数\r\n const screenDeltaX = (e.clientX - dragStart.value.x) / zoom.value\r\n const screenDeltaY = (e.clientY - dragStart.value.y) / zoom.value\r\n\r\n // 【核心修复】将屏幕移动坐标转换回旋转后的本地坐标系\r\n // 公式:x' = x*cos(θ) + y*sin(θ), y' = -x*sin(θ) + y*cos(θ)\r\n // 这里 θ 取负值,因为我们要从屏幕坐标转回组件本地坐标\r\n const rad = (-rotation.value * Math.PI) / 180\r\n const cos = Math.cos(rad)\r\n const sin = Math.sin(rad)\r\n\r\n const deltaX = screenDeltaX * cos - screenDeltaY * sin\r\n const deltaY = screenDeltaX * sin + screenDeltaY * cos\r\n\r\n if (isDragging.value && dragType.value === 'crop-box') {\r\n // 拖拽裁剪框\r\n // 【核心修复】由于裁剪框在旋转容器内部,边界限制应始终使用图片的原始显示尺寸\r\n const width = imageDisplayWidth.value\r\n const height = imageDisplayHeight.value\r\n const newX = Math.max(0, Math.min(cropStart.value.x + deltaX, width - cropArea.value.width))\r\n const newY = Math.max(0, Math.min(cropStart.value.y + deltaY, height - cropArea.value.height))\r\n\r\n cropArea.value.x = newX\r\n cropArea.value.y = newY\r\n } else if (isResizing.value) {\r\n // 调整裁剪框大小\r\n resizeCropBox(deltaX, deltaY)\r\n }\r\n}\r\n\r\n// 调整裁剪框大小\r\nconst resizeCropBox = (deltaX: number, deltaY: number) => {\r\n const width = imageDisplayWidth.value\r\n const height = imageDisplayHeight.value\r\n const { x, y, width: w, height: h } = cropStart.value\r\n const type = dragType.value\r\n\r\n let newX = x\r\n let newY = y\r\n let newWidth = w\r\n let newHeight = h\r\n\r\n // 根据拖拽类型调整\r\n if (type.includes('e')) {\r\n newWidth = Math.max(props.minWidth, Math.min(w + deltaX, width - x, props.maxWidth || Infinity))\r\n }\r\n if (type.includes('w')) {\r\n const maxWidth = x + w\r\n newWidth = Math.max(props.minWidth, Math.min(w - deltaX, maxWidth, props.maxWidth || Infinity))\r\n newX = Math.max(0, x + w - newWidth)\r\n }\r\n if (type.includes('s')) {\r\n newHeight = Math.max(\r\n props.minHeight,\r\n Math.min(h + deltaY, height - y, props.maxHeight || Infinity)\r\n )\r\n }\r\n if (type.includes('n')) {\r\n const maxHeight = y + h\r\n newHeight = Math.max(\r\n props.minHeight,\r\n Math.min(h - deltaY, maxHeight, props.maxHeight || Infinity)\r\n )\r\n newY = Math.max(0, y + h - newHeight)\r\n }\r\n\r\n // 处理固定比例\r\n if (props.cropMode === 'ratio' && props.aspectRatio) {\r\n const currentAspect = newWidth / newHeight\r\n if (Math.abs(currentAspect - props.aspectRatio) > 0.01) {\r\n if (type.includes('e') || type.includes('w')) {\r\n newHeight = newWidth / props.aspectRatio\r\n if (type.includes('n')) {\r\n newY = y + h - newHeight\r\n }\r\n } else {\r\n newWidth = newHeight * props.aspectRatio\r\n if (type.includes('w')) {\r\n newX = x + w - newWidth\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 边界检查\r\n if (newX + newWidth > width) {\r\n newWidth = width - newX\r\n if (props.cropMode === 'ratio' && props.aspectRatio) {\r\n newHeight = newWidth / props.aspectRatio\r\n }\r\n }\r\n if (newY + newHeight > height) {\r\n newHeight = height - newY\r\n if (props.cropMode === 'ratio' && props.aspectRatio) {\r\n newWidth = newHeight * props.aspectRatio\r\n }\r\n }\r\n\r\n cropArea.value = { x: newX, y: newY, width: newWidth, height: newHeight }\r\n}\r\n\r\n// 鼠标释放\r\nconst handleMouseUp = () => {\r\n isDragging.value = false\r\n isResizing.value = false\r\n dragType.value = ''\r\n document.removeEventListener('mousemove', handleMouseMove)\r\n document.removeEventListener('mouseup', handleMouseUp)\r\n}\r\n\r\n// 缩放变化\r\nconst handleZoomChange = () => {\r\n // 缩放时保持裁剪区域相对位置\r\n // 这里可以添加更复杂的缩放逻辑\r\n}\r\n\r\n// 鼠标滚轮缩放(电脑端优化)\r\nconst handleWheel = (e: WheelEvent) => {\r\n if (!props.zoomable || !imageLoaded.value) return\r\n\r\n e.preventDefault()\r\n const delta = e.deltaY > 0 ? -0.1 : 0.1\r\n const newZoom = Math.max(minZoom.value, Math.min(maxZoom.value, zoom.value + delta))\r\n zoom.value = Math.round(newZoom * 10) / 10\r\n}\r\n\r\n// 旋转图片\r\nconst rotateImage = (angle: number) => {\r\n rotation.value = (rotation.value + angle) % 360\r\n nextTick(() => {\r\n updateImageDisplaySize()\r\n initCropArea()\r\n })\r\n}\r\n\r\n// 执行裁剪\r\nconst handleCrop = () => {\r\n if (!imageRef.value || !props.imageSrc) return\r\n\r\n const canvas = document.createElement('canvas')\r\n const ctx = canvas.getContext('2d')\r\n if (!ctx) return\r\n\r\n // 1. 获取缩放比例(显示尺寸 vs 原始尺寸)\r\n const scaleX = imageNaturalWidth.value / imageDisplayWidth.value\r\n const scaleY = imageNaturalHeight.value / imageDisplayHeight.value\r\n\r\n // 2. 计算裁剪框在原始图片坐标系下的尺寸(不计旋转)\r\n const { x, y, width, height } = cropArea.value\r\n const cropW = width * scaleX\r\n const cropH = height * scaleY\r\n\r\n // 3. 设置目标 Canvas 尺寸\r\n // 注意:如果旋转了 90/270 度,裁剪结果的视觉尺寸应该互换\r\n const is90Deg = Math.abs(rotation.value % 180) === 90\r\n canvas.width = is90Deg ? cropH : cropW\r\n canvas.height = is90Deg ? cropW : cropH\r\n\r\n ctx.save()\r\n\r\n // 4. 将画布原点移至中心并旋转\r\n ctx.translate(canvas.width / 2, canvas.height / 2)\r\n ctx.rotate((rotation.value * Math.PI) / 180)\r\n\r\n // 5. 关键步骤:计算图片在旋转后的画布上应该绘制的位置\r\n // 我们需要将图片的“裁剪框中心点”对齐到画布的“中心点”\r\n const imgCenterX = imageNaturalWidth.value / 2\r\n const imgCenterY = imageNaturalHeight.value / 2\r\n const cropCenterX = (x + width / 2) * scaleX\r\n const cropCenterY = (y + height / 2) * scaleY\r\n\r\n // 绘制偏移量 = 图片中心 - 裁剪框中心\r\n const drawOffsetX = imgCenterX - cropCenterX\r\n const drawOffsetY = imgCenterY - cropCenterY\r\n\r\n // 6. 绘制图片\r\n ctx.drawImage(\r\n imageRef.value,\r\n -imageNaturalWidth.value / 2 + drawOffsetX,\r\n -imageNaturalHeight.value / 2 + drawOffsetY,\r\n imageNaturalWidth.value,\r\n imageNaturalHeight.value\r\n )\r\n\r\n ctx.restore()\r\n\r\n // 7. 输出结果\r\n canvas.toBlob(blob => {\r\n if (blob) {\r\n const dataUrl = canvas.toDataURL('image/png')\r\n emit('crop', {\r\n blob,\r\n dataUrl,\r\n cropArea: {\r\n x: x * scaleX,\r\n y: y * scaleY,\r\n width: cropW,\r\n height: cropH,\r\n },\r\n })\r\n }\r\n }, 'image/png')\r\n}\r\n\r\n// 取消\r\nconst handleCancel = () => {\r\n emit('cancel')\r\n}\r\n\r\n// 监听图片源变化\r\nwatch(\r\n () => props.imageSrc,\r\n (newSrc: string | undefined) => {\r\n if (newSrc) {\r\n imageLoaded.value = false\r\n rotation.value = 0\r\n zoom.value = props.initialZoom\r\n }\r\n }\r\n)\r\n\r\n// 监听容器大小变化\r\nconst resizeObserver = ref<ResizeObserver | null>(null)\r\n\r\n// 键盘快捷键处理(电脑端优化)\r\nconst handleKeyDown = (e: KeyboardEvent) => {\r\n // 只在组件可见且有图片时响应\r\n if (!imageLoaded.value || !props.imageSrc) return\r\n // 如果用户在输入框中,不响应快捷键\r\n const target = e.target as HTMLElement\r\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable)\r\n return\r\n\r\n // Ctrl/Cmd + 滚轮缩放,或方向键旋转\r\n if (e.ctrlKey || e.metaKey) {\r\n if (e.key === '=' || e.key === '+') {\r\n e.preventDefault()\r\n const newZoom = Math.min(maxZoom.value, zoom.value + 0.1)\r\n zoom.value = Math.round(newZoom * 10) / 10\r\n } else if (e.key === '-' || e.key === '_') {\r\n e.preventDefault()\r\n const newZoom = Math.max(minZoom.value, zoom.value - 0.1)\r\n zoom.value = Math.round(newZoom * 10) / 10\r\n }\r\n }\r\n\r\n // R 键旋转(需要组件获得焦点)\r\n if (props.rotatable && (e.key === 'r' || e.key === 'R')) {\r\n e.preventDefault()\r\n rotateImage(90)\r\n }\r\n\r\n // Enter 确认裁剪\r\n if (e.key === 'Enter' && !e.shiftKey) {\r\n e.preventDefault()\r\n handleCrop()\r\n }\r\n\r\n // Esc 取消\r\n if (e.key === 'Escape') {\r\n e.preventDefault()\r\n handleCancel()\r\n }\r\n}\r\n\r\nonMounted(() => {\r\n if (containerRef.value && window.ResizeObserver) {\r\n resizeObserver.value = new ResizeObserver(() => {\r\n updateImageDisplaySize()\r\n })\r\n resizeObserver.value.observe(containerRef.value)\r\n }\r\n\r\n // 添加键盘事件监听(电脑端优化)\r\n document.addEventListener('keydown', handleKeyDown)\r\n})\r\n\r\nonBeforeUnmount(() => {\r\n handleMouseUp()\r\n if (resizeObserver.value) {\r\n resizeObserver.value.disconnect()\r\n }\r\n // 移除键盘事件监听\r\n document.removeEventListener('keydown', handleKeyDown)\r\n})\r\n</script>\r\n\r\n<script lang=\"ts\">\r\nexport default {\r\n name: 'VcImageCropper',\r\n}\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.vc-image-cropper {\r\n position: relative;\r\n background: #1a1a1a;\r\n border-radius: 8px;\r\n overflow: hidden;\r\n user-select: none;\r\n outline: none;\r\n\r\n &:focus {\r\n box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.5);\r\n }\r\n}\r\n\r\n.vc-image-cropper-placeholder {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 100%;\r\n color: #666;\r\n}\r\n\r\n.placeholder-content {\r\n text-align: center;\r\n\r\n svg {\r\n margin-bottom: 16px;\r\n opacity: 0.5;\r\n }\r\n\r\n p {\r\n margin: 0;\r\n font-size: 14px;\r\n }\r\n}\r\n\r\n.vc-image-cropper-content {\r\n position: relative;\r\n width: 100%;\r\n height: calc(100% - 60px);\r\n overflow: hidden;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.vc-image-wrapper {\r\n position: relative;\r\n transition: transform 0.1s ease-out;\r\n}\r\n\r\n.vc-image-wrapper img {\r\n max-width: none;\r\n max-height: none;\r\n}\r\n\r\n.vc-crop-box {\r\n position: absolute;\r\n border: 2px solid #fff;\r\n box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5);\r\n cursor: move;\r\n}\r\n\r\n.vc-crop-grid {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n width: 100%;\r\n height: 100%;\r\n pointer-events: none;\r\n}\r\n\r\n.grid-line {\r\n position: absolute;\r\n background: rgba(255, 255, 255, 0.3);\r\n\r\n &.grid-line-h1 {\r\n top: 33.33%;\r\n left: 0;\r\n width: 100%;\r\n height: 1px;\r\n }\r\n\r\n &.grid-line-h2 {\r\n top: 66.66%;\r\n left: 0;\r\n width: 100%;\r\n height: 1px;\r\n }\r\n\r\n &.grid-line-v1 {\r\n left: 33.33%;\r\n top: 0;\r\n width: 1px;\r\n height: 100%;\r\n }\r\n\r\n &.grid-line-v2 {\r\n left: 66.66%;\r\n top: 0;\r\n width: 1px;\r\n height: 100%;\r\n }\r\n}\r\n\r\n.vc-crop-handle {\r\n position: absolute;\r\n width: 8px;\r\n height: 8px;\r\n background: #fff;\r\n border: 1px solid #333;\r\n box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);\r\n z-index: 10;\r\n\r\n &:hover {\r\n background: #667eea;\r\n border-color: #667eea;\r\n }\r\n}\r\n\r\n.vc-cropper-toolbar {\r\n position: absolute;\r\n bottom: 0;\r\n left: 0;\r\n right: 0;\r\n height: 60px;\r\n background: rgba(0, 0, 0, 0.8);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 24px;\r\n padding: 0 24px;\r\n backdrop-filter: blur(10px);\r\n}\r\n\r\n.toolbar-group {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n}\r\n\r\n.toolbar-label {\r\n color: #fff;\r\n font-size: 14px;\r\n white-space: nowrap;\r\n}\r\n\r\n.toolbar-slider {\r\n width: 150px;\r\n height: 4px;\r\n border-radius: 2px;\r\n background: #333;\r\n outline: none;\r\n -webkit-appearance: none;\r\n appearance: none;\r\n\r\n &::-webkit-slider-thumb {\r\n -webkit-appearance: none;\r\n appearance: none;\r\n width: 16px;\r\n height: 16px;\r\n border-radius: 50%;\r\n background: #667eea;\r\n cursor: pointer;\r\n }\r\n\r\n &::-moz-range-thumb {\r\n width: 16px;\r\n height: 16px;\r\n border-radius: 50%;\r\n background: #667eea;\r\n cursor: pointer;\r\n border: none;\r\n }\r\n}\r\n\r\n.toolbar-value {\r\n color: #fff;\r\n font-size: 14px;\r\n min-width: 40px;\r\n text-align: right;\r\n}\r\n\r\n.toolbar-btn {\r\n padding: 8px 16px;\r\n border: 1px solid #444;\r\n background: #333;\r\n color: #fff;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font-size: 14px;\r\n transition: all 0.2s;\r\n\r\n &:hover {\r\n background: #444;\r\n border-color: #667eea;\r\n }\r\n\r\n &.toolbar-btn-primary {\r\n background: #667eea;\r\n border-color: #667eea;\r\n\r\n &:hover {\r\n background: #5568d3;\r\n }\r\n }\r\n}\r\n</style>\r\n","import type { App, Component } from 'vue'\r\nimport ScaleContainer from './components/ScaleContainer/index.vue'\r\nimport ImageCropper from './components/ImageCropper/index.vue'\r\n\r\nconst components: Component[] = [\r\n ScaleContainer,\r\n ImageCropper\r\n]\r\n\r\nexport const install = (app: App) => {\r\n components.forEach(component => {\r\n const name = (component as any).name || (component as any).__name\r\n if (name) {\r\n app.component(name, component)\r\n }\r\n })\r\n}\r\n\r\nexport default {\r\n install\r\n}\r\n","// 工具函数\r\nexport const isString = (val: unknown): val is string => typeof val === 'string'\r\n\r\nexport const isNumber = (val: unknown): val is number => typeof val === 'number'\r\n\r\nexport const isBoolean = (val: unknown): val is boolean => typeof val === 'boolean'\r\n\r\nexport const isObject = (val: unknown): val is Record<string, any> =>\r\n val !== null && typeof val === 'object'\r\n\r\nexport const isArray = (val: unknown): val is Array<any> => Array.isArray(val)\r\n\r\nexport const isFunction = (val: unknown): val is Function => typeof val === 'function'\r\n\r\n// 防抖函数\r\nexport function debounce<T extends (...args: any[]) => any>(\r\n func: T,\r\n wait: number\r\n): (...args: Parameters<T>) => void {\r\n let timeout: ReturnType<typeof setTimeout> | null = null\r\n return function (this: any, ...args: Parameters<T>) {\r\n const context = this\r\n if (timeout) clearTimeout(timeout)\r\n timeout = setTimeout(() => {\r\n func.apply(context, args)\r\n }, wait)\r\n }\r\n}\r\n\r\n// 节流函数\r\nexport function throttle<T extends (...args: any[]) => any>(\r\n func: T,\r\n wait: number\r\n): (...args: Parameters<T>) => void {\r\n let timeout: ReturnType<typeof setTimeout> | null = null\r\n let previous = 0\r\n return function (this: any, ...args: Parameters<T>) {\r\n const now = Date.now()\r\n const remaining = wait - (now - previous)\r\n if (remaining <= 0 || remaining > wait) {\r\n if (timeout) {\r\n clearTimeout(timeout)\r\n timeout = null\r\n }\r\n previous = now\r\n func.apply(this, args)\r\n } else if (!timeout) {\r\n timeout = setTimeout(() => {\r\n previous = Date.now()\r\n timeout = null\r\n func.apply(this, args)\r\n }, remaining)\r\n }\r\n }\r\n}\r\n\r\n","// 主入口文件\r\nimport type { App } from 'vue'\r\nimport { install as installComponents } from './install'\r\n\r\n// 导出所有组件\r\nexport * from './components'\r\n\r\n// 导出类型\r\nexport * from './types'\r\n\r\n// 导出工具函数\r\nexport * from './utils'\r\n\r\n// 安装函数(用于 Vue.use())\r\nexport const install = (app: App) => {\r\n installComponents(app)\r\n}\r\n\r\n// 默认导出\r\nexport default {\r\n install\r\n}\r\n\r\n// 版本号\r\nexport const version = '1.0.0'\r\n\r\n"],"names":["_createElementBlock","_createElementVNode","_renderSlot","_openBlock","_Fragment","_renderList","index","_normalizeClass","_normalizeStyle","_toDisplayString","install","installComponents"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { App } from 'vue';
2
+
3
+ export declare const install: (app: App) => void;
4
+ declare const _default: {
5
+ install: (app: App) => void;
6
+ };
7
+ export default _default;
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .vc-scale-container[data-v-7f878606]{margin:0;padding:0;display:block}.vc-scale-wrapper[data-v-7f878606]{box-sizing:border-box;display:block}.vc-image-cropper[data-v-a3fe50be]{position:relative;background:#1a1a1a;border-radius:8px;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;user-select:none;outline:none}.vc-image-cropper[data-v-a3fe50be]:focus{box-shadow:0 0 0 2px #667eea80}.vc-image-cropper-placeholder[data-v-a3fe50be]{display:flex;align-items:center;justify-content:center;height:100%;color:#666}.placeholder-content[data-v-a3fe50be]{text-align:center}.placeholder-content svg[data-v-a3fe50be]{margin-bottom:16px;opacity:.5}.placeholder-content p[data-v-a3fe50be]{margin:0;font-size:14px}.vc-image-cropper-content[data-v-a3fe50be]{position:relative;width:100%;height:calc(100% - 60px);overflow:hidden;display:flex;align-items:center;justify-content:center}.vc-image-wrapper[data-v-a3fe50be]{position:relative;transition:transform .1s ease-out}.vc-image-wrapper img[data-v-a3fe50be]{max-width:none;max-height:none}.vc-crop-box[data-v-a3fe50be]{position:absolute;border:2px solid #fff;box-shadow:0 0 0 9999px #00000080;cursor:move}.vc-crop-grid[data-v-a3fe50be]{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.grid-line[data-v-a3fe50be]{position:absolute;background:#ffffff4d}.grid-line.grid-line-h1[data-v-a3fe50be]{top:33.33%;left:0;width:100%;height:1px}.grid-line.grid-line-h2[data-v-a3fe50be]{top:66.66%;left:0;width:100%;height:1px}.grid-line.grid-line-v1[data-v-a3fe50be]{left:33.33%;top:0;width:1px;height:100%}.grid-line.grid-line-v2[data-v-a3fe50be]{left:66.66%;top:0;width:1px;height:100%}.vc-crop-handle[data-v-a3fe50be]{position:absolute;width:8px;height:8px;background:#fff;border:1px solid #333;box-shadow:0 0 2px #00000080;z-index:10}.vc-crop-handle[data-v-a3fe50be]:hover{background:#667eea;border-color:#667eea}.vc-cropper-toolbar[data-v-a3fe50be]{position:absolute;bottom:0;left:0;right:0;height:60px;background:#000c;display:flex;align-items:center;justify-content:center;gap:24px;padding:0 24px;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.toolbar-group[data-v-a3fe50be]{display:flex;align-items:center;gap:12px}.toolbar-label[data-v-a3fe50be]{color:#fff;font-size:14px;white-space:nowrap}.toolbar-slider[data-v-a3fe50be]{width:150px;height:4px;border-radius:2px;background:#333;outline:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.toolbar-slider[data-v-a3fe50be]::-webkit-slider-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:16px;height:16px;border-radius:50%;background:#667eea;cursor:pointer}.toolbar-slider[data-v-a3fe50be]::-moz-range-thumb{width:16px;height:16px;border-radius:50%;background:#667eea;cursor:pointer;border:none}.toolbar-value[data-v-a3fe50be]{color:#fff;font-size:14px;min-width:40px;text-align:right}.toolbar-btn[data-v-a3fe50be]{padding:8px 16px;border:1px solid #444;background:#333;color:#fff;border-radius:4px;cursor:pointer;font-size:14px;transition:all .2s}.toolbar-btn[data-v-a3fe50be]:hover{background:#444;border-color:#667eea}.toolbar-btn.toolbar-btn-primary[data-v-a3fe50be]{background:#667eea;border-color:#667eea}.toolbar-btn.toolbar-btn-primary[data-v-a3fe50be]:hover{background:#5568d3}
@@ -0,0 +1 @@
1
+ export * from '../components/ScaleContainer/types';
@@ -0,0 +1,8 @@
1
+ export declare const isString: (val: unknown) => val is string;
2
+ export declare const isNumber: (val: unknown) => val is number;
3
+ export declare const isBoolean: (val: unknown) => val is boolean;
4
+ export declare const isObject: (val: unknown) => val is Record<string, any>;
5
+ export declare const isArray: (val: unknown) => val is Array<any>;
6
+ export declare const isFunction: (val: unknown) => val is Function;
7
+ export declare function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void;
8
+ export declare function throttle<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void;
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "v3-comf-dm",
3
+ "version": "1.0.0",
4
+ "description": "A Vue3 component library",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.esm.js",
8
+ "types": "./dist/index.d.ts",
9
+ "private": false,
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.esm.js",
13
+ "require": "./dist/index.cjs",
14
+ "types": "./dist/index.d.ts"
15
+ },
16
+ "./style": "./dist/style.css"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "packages"
21
+ ],
22
+ "scripts": {
23
+ "dev": "vite",
24
+ "build": "vite build",
25
+ "build:watch": "vite build --watch",
26
+ "test": "vitest",
27
+ "test:ui": "vitest --ui",
28
+ "test:coverage": "vitest --coverage",
29
+ "lint": "eslint . --ext .vue,.js,.ts",
30
+ "format": "prettier --write \"**/*.{js,ts,json,vue,scss,css}\"",
31
+ "prepublishOnly": "npm run build",
32
+ "publish:npm": "npm publish --registry=https://registry.npmjs.org/ --access public"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public",
36
+ "registry": "https://registry.npmjs.org/"
37
+ },
38
+ "keywords": [
39
+ "vue",
40
+ "vue3",
41
+ "component",
42
+ "library",
43
+ "ui"
44
+ ],
45
+ "author": "adqw",
46
+ "license": "MIT",
47
+ "devDependencies": {
48
+ "@vitejs/plugin-vue": "^5.0.0",
49
+ "@vitest/ui": "^1.0.0",
50
+ "@vue/test-utils": "^2.4.0",
51
+ "autoprefixer": "^10.4.16",
52
+ "eslint": "^8.54.0",
53
+ "eslint-plugin-vue": "^9.18.1",
54
+ "jsdom": "^23.0.1",
55
+ "postcss": "^8.4.32",
56
+ "prettier": "^3.1.0",
57
+ "sass-embedded": "^1.69.5",
58
+ "terser": "^5.44.1",
59
+ "typescript": "^5.3.2",
60
+ "vite": "^5.0.5",
61
+ "vite-plugin-dts": "^3.6.4",
62
+ "vitest": "^1.0.0",
63
+ "vue": "^3.3.11"
64
+ },
65
+ "peerDependencies": {
66
+ "vue": "^3.0.0"
67
+ }
68
+ }