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.
package/README.md ADDED
@@ -0,0 +1,175 @@
1
+ # Vue Component Library
2
+
3
+ 一个支持 Vue2 和 Vue3 的组件库项目。
4
+
5
+ ## 特性
6
+
7
+ - ✅ 使用 Vue3 语法开发
8
+ - ✅ 支持打包为 Vue2 和 Vue3 两个版本
9
+ - ✅ 支持 npm 发布(可配置公有/私有源)
10
+ - ✅ 支持代码复制使用(低耦合设计)
11
+ - ✅ 集成 Vitest 测试框架
12
+ - ✅ 自动样式兼容(Autoprefixer)
13
+ - ✅ TypeScript 支持
14
+ - ✅ 完整的类型定义
15
+
16
+ ## 安装
17
+
18
+ ### npm 安装
19
+
20
+ ```bash
21
+ npm install @your-org/vue-component-library
22
+ ```
23
+
24
+ ### 使用
25
+
26
+ #### Vue3 项目
27
+
28
+ ```typescript
29
+ import { createApp } from 'vue'
30
+ import App from './App.vue'
31
+ import VueComponentLibrary from '@your-org/vue-component-library'
32
+ import '@your-org/vue-component-library/style'
33
+
34
+ const app = createApp(App)
35
+ app.use(VueComponentLibrary)
36
+ app.mount('#app')
37
+ ```
38
+
39
+ #### Vue2 项目
40
+
41
+ ```typescript
42
+ import Vue from 'vue'
43
+ import VueComponentLibrary from '@your-org/vue-component-library/vue2'
44
+ import '@your-org/vue-component-library/vue2/style'
45
+
46
+ Vue.use(VueComponentLibrary)
47
+ ```
48
+
49
+ #### 按需引入
50
+
51
+ ```typescript
52
+ import { Button, Card } from '@your-org/vue-component-library'
53
+
54
+ // 在组件中使用
55
+ export default {
56
+ components: {
57
+ Button,
58
+ Card
59
+ }
60
+ }
61
+ ```
62
+
63
+ ## 开发
64
+
65
+ ### 安装依赖
66
+
67
+ ```bash
68
+ npm install
69
+ ```
70
+
71
+ ### 开发模式
72
+
73
+ ```bash
74
+ npm run dev
75
+ ```
76
+
77
+ ### 构建
78
+
79
+ ```bash
80
+ # 构建 Vue3 和 Vue2 版本
81
+ npm run build
82
+
83
+ # 只构建 Vue3 版本
84
+ npm run build:vue3
85
+
86
+ # 只构建 Vue2 版本
87
+ npm run build:vue2
88
+ ```
89
+
90
+ ### 测试
91
+
92
+ ```bash
93
+ # 运行测试
94
+ npm run test
95
+
96
+ # 测试 UI
97
+ npm run test:ui
98
+
99
+ # 测试覆盖率
100
+ npm run test:coverage
101
+ ```
102
+
103
+ ## 发布
104
+
105
+ ### 发布到 npm 官方源
106
+
107
+ ```bash
108
+ npm run publish:npm
109
+ ```
110
+
111
+ ### 发布到私有源
112
+
113
+ 1. 修改 `.npmrc` 文件,配置私有源地址
114
+ 2. 运行:
115
+
116
+ ```bash
117
+ npm run publish:private
118
+ ```
119
+
120
+ ## 组件开发规范
121
+
122
+ ### 1. 组件结构
123
+
124
+ ```
125
+ packages/components/Button/
126
+ ├── index.vue # 组件文件
127
+ ├── types.ts # 类型定义
128
+ └── README.md # 组件文档(可选)
129
+ ```
130
+
131
+ ### 2. 组件要求
132
+
133
+ - 使用 Vue3 Composition API
134
+ - 提供完整的 TypeScript 类型定义
135
+ - 样式使用 scoped,避免污染
136
+ - 组件名称使用 `vc-` 前缀(避免冲突)
137
+ - 保持低耦合,可独立使用
138
+
139
+ ### 3. 添加新组件
140
+
141
+ 1. 在 `packages/components/` 下创建组件目录
142
+ 2. 在 `packages/components/index.ts` 中导出
143
+ 3. 在 `packages/install.ts` 中注册
144
+ 4. 编写测试用例
145
+
146
+ ## 代码复制使用
147
+
148
+ 所有组件都设计为低耦合,可以直接复制代码使用:
149
+
150
+ 1. 复制组件文件(`.vue`)
151
+ 2. 复制相关类型定义(`types.ts`)
152
+ 3. 复制样式代码
153
+ 4. 在项目中引入使用
154
+
155
+ ## 项目结构
156
+
157
+ ```
158
+ vue-component-library/
159
+ ├── packages/ # 组件源码
160
+ │ ├── components/ # 组件目录
161
+ │ ├── utils/ # 工具函数
162
+ │ ├── types/ # 类型定义
163
+ │ ├── styles/ # 样式文件
164
+ │ └── index.ts # 入口文件
165
+ ├── examples/ # 示例项目
166
+ ├── tests/ # 测试文件
167
+ ├── dist/ # 构建输出(Vue3)
168
+ ├── dist-vue2/ # 构建输出(Vue2)
169
+ └── vite.config.ts # Vite 配置
170
+ ```
171
+
172
+ ## 许可证
173
+
174
+ MIT
175
+
@@ -0,0 +1,67 @@
1
+ import { ImageCropperProps, CropArea } from './types';
2
+
3
+ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<ImageCropperProps>, {
4
+ cropMode: string;
5
+ minWidth: number;
6
+ minHeight: number;
7
+ showGrid: boolean;
8
+ rotatable: boolean;
9
+ zoomable: boolean;
10
+ initialZoom: number;
11
+ containerWidth: string;
12
+ containerHeight: string;
13
+ }>>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
14
+ crop: (data: {
15
+ blob: Blob;
16
+ dataUrl: string;
17
+ cropArea: CropArea;
18
+ }) => void;
19
+ cancel: () => void;
20
+ ready: () => void;
21
+ }, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<ImageCropperProps>, {
22
+ cropMode: string;
23
+ minWidth: number;
24
+ minHeight: number;
25
+ showGrid: boolean;
26
+ rotatable: boolean;
27
+ zoomable: boolean;
28
+ initialZoom: number;
29
+ containerWidth: string;
30
+ containerHeight: string;
31
+ }>>> & Readonly<{
32
+ onCrop?: ((data: {
33
+ blob: Blob;
34
+ dataUrl: string;
35
+ cropArea: CropArea;
36
+ }) => any) | undefined;
37
+ onCancel?: (() => any) | undefined;
38
+ onReady?: (() => any) | undefined;
39
+ }>, {
40
+ cropMode: import('./types').CropMode;
41
+ minWidth: number;
42
+ minHeight: number;
43
+ showGrid: boolean;
44
+ rotatable: boolean;
45
+ zoomable: boolean;
46
+ initialZoom: number;
47
+ containerWidth: number | string;
48
+ containerHeight: number | string;
49
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
50
+ export default _default;
51
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
52
+ type __VLS_TypePropsToRuntimeProps<T> = {
53
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
54
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
55
+ } : {
56
+ type: import('vue').PropType<T[K]>;
57
+ required: true;
58
+ };
59
+ };
60
+ type __VLS_WithDefaults<P, D> = {
61
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
62
+ default: D[K];
63
+ }> : P[K];
64
+ };
65
+ type __VLS_Prettify<T> = {
66
+ [K in keyof T]: T[K];
67
+ } & {};
@@ -0,0 +1,33 @@
1
+ export type CropMode = 'free' | 'fixed' | 'ratio';
2
+ export interface ImageCropperProps {
3
+ imageSrc?: string;
4
+ cropMode?: CropMode;
5
+ fixedWidth?: number;
6
+ fixedHeight?: number;
7
+ aspectRatio?: number;
8
+ minWidth?: number;
9
+ minHeight?: number;
10
+ maxWidth?: number;
11
+ maxHeight?: number;
12
+ showGrid?: boolean;
13
+ rotatable?: boolean;
14
+ zoomable?: boolean;
15
+ initialZoom?: number;
16
+ containerWidth?: number | string;
17
+ containerHeight?: number | string;
18
+ }
19
+ export interface CropArea {
20
+ x: number;
21
+ y: number;
22
+ width: number;
23
+ height: number;
24
+ }
25
+ export interface ImageCropperEmits {
26
+ (e: 'crop', data: {
27
+ blob: Blob;
28
+ dataUrl: string;
29
+ cropArea: CropArea;
30
+ }): void;
31
+ (e: 'cancel'): void;
32
+ (e: 'ready'): void;
33
+ }
@@ -0,0 +1,48 @@
1
+ import { ScaleContainerProps } from './types';
2
+
3
+ declare function __VLS_template(): {
4
+ default?(_: {}): any;
5
+ };
6
+ declare const __VLS_component: import('vue').DefineComponent<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<ScaleContainerProps>, {
7
+ designWidth: number;
8
+ designHeight: number;
9
+ keepAspectRatio: boolean;
10
+ scaleMode: string;
11
+ detectBrowserZoom: boolean;
12
+ }>>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<ScaleContainerProps>, {
13
+ designWidth: number;
14
+ designHeight: number;
15
+ keepAspectRatio: boolean;
16
+ scaleMode: string;
17
+ detectBrowserZoom: boolean;
18
+ }>>> & Readonly<{}>, {
19
+ designWidth: number;
20
+ designHeight: number;
21
+ keepAspectRatio: boolean;
22
+ scaleMode: import('./types').ScaleMode;
23
+ detectBrowserZoom: boolean;
24
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
25
+ declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, ReturnType<typeof __VLS_template>>;
26
+ export default _default;
27
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
28
+ type __VLS_TypePropsToRuntimeProps<T> = {
29
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
30
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
31
+ } : {
32
+ type: import('vue').PropType<T[K]>;
33
+ required: true;
34
+ };
35
+ };
36
+ type __VLS_WithDefaults<P, D> = {
37
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
38
+ default: D[K];
39
+ }> : P[K];
40
+ };
41
+ type __VLS_Prettify<T> = {
42
+ [K in keyof T]: T[K];
43
+ } & {};
44
+ type __VLS_WithTemplateSlots<T, S> = T & {
45
+ new (): {
46
+ $slots: S;
47
+ };
48
+ };
@@ -0,0 +1,8 @@
1
+ export type ScaleMode = 'fit' | 'fill' | 'stretch';
2
+ export interface ScaleContainerProps {
3
+ designWidth?: number;
4
+ designHeight?: number;
5
+ keepAspectRatio?: boolean;
6
+ scaleMode?: ScaleMode;
7
+ detectBrowserZoom?: boolean;
8
+ }
@@ -0,0 +1,4 @@
1
+ export { default as ScaleContainer } from './ScaleContainer/index.vue';
2
+ export { default as ImageCropper } from './ImageCropper/index.vue';
3
+ export type { ScaleContainerProps, ScaleMode } from './ScaleContainer/types';
4
+ export type { ImageCropperProps, CropMode, CropArea, ImageCropperEmits } from './ImageCropper/types';
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),t=(e,t)=>{const a=e.__vccOpts||e;for(const[l,n]of t)a[l]=n;return a},a=t(e.defineComponent({name:"VcScaleContainer",__name:"index",props:{designWidth:{default:1920},designHeight:{default:1080},keepAspectRatio:{type:Boolean,default:!0},scaleMode:{default:"fit"},detectBrowserZoom:{type:Boolean,default:!0}},setup(t){const a=t,l=e.ref(null),n=e.ref(1),o=e.ref(1),r=e.ref(1),i=e.ref(1920),s=e.ref(1080),c=e.computed(()=>({width:`${i.value}px`,height:`${s.value}px`,position:"relative",overflow:"hidden"})),u=e.computed(()=>{const e={width:`${a.designWidth}px`,height:`${a.designHeight}px`,transformOrigin:"top left"};if(a.keepAspectRatio&&("fit"===a.scaleMode||"fill"===a.scaleMode)){const t=a.designWidth*n.value,l=a.designHeight*n.value;return{...e,transform:`scale(${n.value})`,position:"absolute",top:"50%",left:"50%",marginTop:`-${l/2}px`,marginLeft:`-${t/2}px`}}return{...e,transform:`scale(${o.value}, ${r.value})`}}),d=()=>{const e=l.value;if(!e||!e.parentElement)return;const t=e.parentElement;let c=t.clientWidth||window.innerWidth,u=t.clientHeight||window.innerHeight;0===c&&(c=window.innerWidth),0===u&&(u=window.innerHeight),i.value=c,s.value=u;const d=c/a.designWidth,v=u/a.designHeight;"stretch"===a.scaleMode?(o.value=d,r.value=v):a.keepAspectRatio?n.value="fit"===a.scaleMode?Math.min(d,v):Math.max(d,v):(o.value=d,r.value=v)};let v=null;const p=()=>d();return e.onMounted(()=>{e.nextTick(()=>{var e;d(),window.addEventListener("resize",p),window.ResizeObserver&&(null==(e=l.value)?void 0:e.parentElement)&&(v=new ResizeObserver(p),v.observe(l.value.parentElement))})}),e.onBeforeUnmount(()=>{window.removeEventListener("resize",p),v&&v.disconnect()}),(t,a)=>(e.openBlock(),e.createElementBlock("div",{ref_key:"scaleContainer",ref:l,class:"vc-scale-container",style:e.normalizeStyle(c.value)},[e.createElementVNode("div",{class:"vc-scale-wrapper",style:e.normalizeStyle(u.value)},[e.renderSlot(t.$slots,"default",{},void 0,!0)],4)],4))}}),[["__scopeId","data-v-7f878606"]]),l={key:0,class:"vc-image-cropper-placeholder"},n=["src"],o={key:0,class:"vc-crop-grid"},r=["onMousedown"],i={key:0,class:"vc-cropper-toolbar"},s={key:0,class:"toolbar-group"},c=["min","max"],u={class:"toolbar-value"},d={key:1,class:"toolbar-group"},v=t(e.defineComponent({name:"VcImageCropper",props:{imageSrc:{},cropMode:{default:"free"},fixedWidth:{},fixedHeight:{},aspectRatio:{},minWidth:{default:50},minHeight:{default:50},maxWidth:{},maxHeight:{},showGrid:{type:Boolean,default:!0},rotatable:{type:Boolean,default:!0},zoomable:{type:Boolean,default:!0},initialZoom:{default:1},containerWidth:{default:"100%"},containerHeight:{default:"600px"}},emits:["crop","cancel","ready"],setup(t,{emit:a}){const v=t,p=a,m=e.ref(null),h=e.ref(null),f=e.ref(null),g=e.ref(null),y=e.ref(null),x=e.ref(!1),w=e.ref(0),b=e.ref(0),k=e.ref(0),M=e.ref(0),E=e.ref(0),B=e.ref(v.initialZoom),R=e.ref(.1),z=e.ref(5),N=e.ref({x:0,y:0,width:0,height:0}),V=e.ref(!1),W=e.ref(!1),H=e.ref(""),S=e.ref({x:0,y:0}),C=e.ref({x:0,y:0,width:0,height:0}),$=e.computed(()=>({width:"number"==typeof v.containerWidth?`${v.containerWidth}px`:v.containerWidth,height:"number"==typeof v.containerHeight?`${v.containerHeight}px`:v.containerHeight})),_=e.computed(()=>({transform:`rotate(${E.value}deg) scale(${B.value})`,transformOrigin:"center center"})),L=e.computed(()=>({width:`${k.value}px`,height:`${M.value}px`,display:"block"})),D=e.computed(()=>({left:`${N.value.x}px`,top:`${N.value.y}px`,width:`${N.value.width}px`,height:`${N.value.height}px`})),T=e.computed(()=>[{type:"nw",class:"handle-nw",style:{top:"-4px",left:"-4px",cursor:"nwse-resize"}},{type:"ne",class:"handle-ne",style:{top:"-4px",right:"-4px",cursor:"nesw-resize"}},{type:"sw",class:"handle-sw",style:{bottom:"-4px",left:"-4px",cursor:"nesw-resize"}},{type:"se",class:"handle-se",style:{bottom:"-4px",right:"-4px",cursor:"nwse-resize"}},{type:"n",class:"handle-n",style:{top:"-4px",left:"50%",transform:"translateX(-50%)",cursor:"ns-resize"}},{type:"s",class:"handle-s",style:{bottom:"-4px",left:"50%",transform:"translateX(-50%)",cursor:"ns-resize"}},{type:"w",class:"handle-w",style:{top:"50%",left:"-4px",transform:"translateY(-50%)",cursor:"ew-resize"}},{type:"e",class:"handle-e",style:{top:"50%",right:"-4px",transform:"translateY(-50%)",cursor:"ew-resize"}}]),A=()=>{g.value&&(w.value=g.value.naturalWidth,b.value=g.value.naturalHeight,e.nextTick(()=>{I(),O(),x.value=!0,p("ready")}))},I=()=>{if(!h.value||!g.value)return;const e=h.value.clientWidth,t=h.value.clientHeight;if(0===e||0===t)return;const a=w.value/b.value;a>e/t?(k.value=.9*e,M.value=.9*e/a):(M.value=.9*t,k.value=.9*t*a)},O=()=>{const e=k.value,t=M.value,a=.8*Math.min(e,t);let l=a,n=a;"fixed"===v.cropMode?(l=v.fixedWidth||a,n=v.fixedHeight||a):"ratio"===v.cropMode&&v.aspectRatio&&(e/t>v.aspectRatio?(n=a,l=a*v.aspectRatio):(l=a,n=a/v.aspectRatio)),N.value={x:(e-l)/2,y:(t-n)/2,width:l,height:n}},X=e=>{e.target===f.value&&(V.value=!0,S.value={x:e.clientX,y:e.clientY},document.addEventListener("mousemove",U),document.addEventListener("mouseup",Z),e.preventDefault())},Y=e=>{e.target===y.value&&(V.value=!0,H.value="crop-box",S.value={x:e.clientX,y:e.clientY},C.value={...N.value},document.addEventListener("mousemove",U),document.addEventListener("mouseup",Z),e.preventDefault())},U=e=>{if(!h.value)return;const t=(e.clientX-S.value.x)/B.value,a=(e.clientY-S.value.y)/B.value,l=-E.value*Math.PI/180,n=Math.cos(l),o=Math.sin(l),r=t*n-a*o,i=t*o+a*n;if(V.value&&"crop-box"===H.value){const e=k.value,t=M.value,a=Math.max(0,Math.min(C.value.x+r,e-N.value.width)),l=Math.max(0,Math.min(C.value.y+i,t-N.value.height));N.value.x=a,N.value.y=l}else W.value&&P(r,i)},P=(e,t)=>{const a=k.value,l=M.value,{x:n,y:o,width:r,height:i}=C.value,s=H.value;let c=n,u=o,d=r,p=i;if(s.includes("e")&&(d=Math.max(v.minWidth,Math.min(r+e,a-n,v.maxWidth||1/0))),s.includes("w")){const t=n+r;d=Math.max(v.minWidth,Math.min(r-e,t,v.maxWidth||1/0)),c=Math.max(0,n+r-d)}if(s.includes("s")&&(p=Math.max(v.minHeight,Math.min(i+t,l-o,v.maxHeight||1/0))),s.includes("n")){const e=o+i;p=Math.max(v.minHeight,Math.min(i-t,e,v.maxHeight||1/0)),u=Math.max(0,o+i-p)}if("ratio"===v.cropMode&&v.aspectRatio){const e=d/p;Math.abs(e-v.aspectRatio)>.01&&(s.includes("e")||s.includes("w")?(p=d/v.aspectRatio,s.includes("n")&&(u=o+i-p)):(d=p*v.aspectRatio,s.includes("w")&&(c=n+r-d)))}c+d>a&&(d=a-c,"ratio"===v.cropMode&&v.aspectRatio&&(p=d/v.aspectRatio)),u+p>l&&(p=l-u,"ratio"===v.cropMode&&v.aspectRatio&&(d=p*v.aspectRatio)),N.value={x:c,y:u,width:d,height:p}},Z=()=>{V.value=!1,W.value=!1,H.value="",document.removeEventListener("mousemove",U),document.removeEventListener("mouseup",Z)},j=()=>{},K=e=>{if(!v.zoomable||!x.value)return;e.preventDefault();const t=e.deltaY>0?-.1:.1,a=Math.max(R.value,Math.min(z.value,B.value+t));B.value=Math.round(10*a)/10},F=t=>{E.value=(E.value+t)%360,e.nextTick(()=>{I(),O()})},G=()=>{if(!g.value||!v.imageSrc)return;const e=document.createElement("canvas"),t=e.getContext("2d");if(!t)return;const a=w.value/k.value,l=b.value/M.value,{x:n,y:o,width:r,height:i}=N.value,s=r*a,c=i*l,u=90===Math.abs(E.value%180);e.width=u?c:s,e.height=u?s:c,t.save(),t.translate(e.width/2,e.height/2),t.rotate(E.value*Math.PI/180);const d=w.value/2,m=b.value/2,h=d-(n+r/2)*a,f=m-(o+i/2)*l;t.drawImage(g.value,-w.value/2+h,-b.value/2+f,w.value,b.value),t.restore(),e.toBlob(t=>{if(t){const r=e.toDataURL("image/png");p("crop",{blob:t,dataUrl:r,cropArea:{x:n*a,y:o*l,width:s,height:c}})}},"image/png")},q=()=>{p("cancel")};e.watch(()=>v.imageSrc,e=>{e&&(x.value=!1,E.value=0,B.value=v.initialZoom)});const J=e.ref(null),Q=e=>{if(!x.value||!v.imageSrc)return;const t=e.target;if("INPUT"!==t.tagName&&"TEXTAREA"!==t.tagName&&!t.isContentEditable){if(e.ctrlKey||e.metaKey)if("="===e.key||"+"===e.key){e.preventDefault();const t=Math.min(z.value,B.value+.1);B.value=Math.round(10*t)/10}else if("-"===e.key||"_"===e.key){e.preventDefault();const t=Math.max(R.value,B.value-.1);B.value=Math.round(10*t)/10}!v.rotatable||"r"!==e.key&&"R"!==e.key||(e.preventDefault(),F(90)),"Enter"!==e.key||e.shiftKey||(e.preventDefault(),G()),"Escape"===e.key&&(e.preventDefault(),q())}};return e.onMounted(()=>{m.value&&window.ResizeObserver&&(J.value=new ResizeObserver(()=>{I()}),J.value.observe(m.value)),document.addEventListener("keydown",Q)}),e.onBeforeUnmount(()=>{Z(),J.value&&J.value.disconnect(),document.removeEventListener("keydown",Q)}),(a,v)=>(e.openBlock(),e.createElementBlock("div",{ref_key:"containerRef",ref:m,class:"vc-image-cropper",style:e.normalizeStyle($.value),tabindex:"0"},[t.imageSrc?(e.openBlock(),e.createElementBlock("div",{key:1,class:"vc-image-cropper-content",ref_key:"contentRef",ref:h},[e.createElementVNode("div",{ref_key:"imageWrapperRef",ref:f,class:"vc-image-wrapper",style:e.normalizeStyle(_.value),onMousedown:X,onWheel:e.withModifiers(K,["prevent"])},[e.createElementVNode("img",{ref_key:"imageRef",ref:g,src:t.imageSrc,style:e.normalizeStyle(L.value),onLoad:A,draggable:"false"},null,44,n),x.value?(e.openBlock(),e.createElementBlock("div",{key:0,ref_key:"cropBoxRef",ref:y,class:"vc-crop-box",style:e.normalizeStyle(D.value),onMousedown:e.withModifiers(Y,["stop"])},[t.showGrid?(e.openBlock(),e.createElementBlock("div",o,[...v[4]||(v[4]=[e.createElementVNode("div",{class:"grid-line grid-line-h1"},null,-1),e.createElementVNode("div",{class:"grid-line grid-line-h2"},null,-1),e.createElementVNode("div",{class:"grid-line grid-line-v1"},null,-1),e.createElementVNode("div",{class:"grid-line grid-line-v2"},null,-1)])])):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(T.value,(t,a)=>(e.openBlock(),e.createElementBlock("div",{key:a,class:e.normalizeClass(["vc-crop-handle",t.class]),style:e.normalizeStyle(t.style),onMousedown:e.withModifiers(e=>{return a=e,l=t.type,W.value=!0,H.value=l,S.value={x:a.clientX,y:a.clientY},C.value={...N.value},document.addEventListener("mousemove",U),document.addEventListener("mouseup",Z),void a.preventDefault();var a,l},["stop"])},null,46,r))),128))],36)):e.createCommentVNode("",!0)],36),x.value?(e.openBlock(),e.createElementBlock("div",i,[t.zoomable?(e.openBlock(),e.createElementBlock("div",s,[v[5]||(v[5]=e.createElementVNode("label",{class:"toolbar-label"},"缩放:",-1)),e.withDirectives(e.createElementVNode("input",{"onUpdate:modelValue":v[0]||(v[0]=e=>B.value=e),type:"range",min:R.value,max:z.value,step:.1,class:"toolbar-slider",onInput:j},null,40,c),[[e.vModelText,B.value,void 0,{number:!0}]]),e.createElementVNode("span",u,e.toDisplayString(Math.round(100*B.value))+"%",1)])):e.createCommentVNode("",!0),t.rotatable?(e.openBlock(),e.createElementBlock("div",d,[e.createElementVNode("button",{class:"toolbar-btn",onClick:v[1]||(v[1]=e=>F(-90)),title:"逆时针旋转"},"↺"),e.createElementVNode("button",{class:"toolbar-btn",onClick:v[2]||(v[2]=e=>F(90)),title:"顺时针旋转"},"↻")])):e.createCommentVNode("",!0),e.createElementVNode("div",{class:"toolbar-group"},[e.createElementVNode("button",{class:"toolbar-btn toolbar-btn-primary",onClick:G},"确认裁剪"),e.createElementVNode("button",{class:"toolbar-btn",onClick:q},"取消")])])):e.createCommentVNode("",!0)],512)):(e.openBlock(),e.createElementBlock("div",l,[...v[3]||(v[3]=[e.createStaticVNode('<div class="placeholder-content" data-v-a3fe50be><svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" data-v-a3fe50be><rect x="3" y="3" width="18" height="18" rx="2" ry="2" data-v-a3fe50be></rect><circle cx="8.5" cy="8.5" r="1.5" data-v-a3fe50be></circle><polyline points="21 15 16 10 5 21" data-v-a3fe50be></polyline></svg><p data-v-a3fe50be>请选择图片</p></div>',1)])]))],4))}}),[["__scopeId","data-v-a3fe50be"]]),p=[a,v];const m=e=>{(e=>{p.forEach(t=>{const a=t.name||t.__name;a&&e.component(a,t)})})(e)},h={install:m};exports.ImageCropper=v,exports.ScaleContainer=a,exports.debounce=function(e,t){let a=null;return function(...l){const n=this;a&&clearTimeout(a),a=setTimeout(()=>{e.apply(n,l)},t)}},exports.default=h,exports.install=m,exports.isArray=e=>Array.isArray(e),exports.isBoolean=e=>"boolean"==typeof e,exports.isFunction=e=>"function"==typeof e,exports.isNumber=e=>"number"==typeof e,exports.isObject=e=>null!==e&&"object"==typeof e,exports.isString=e=>"string"==typeof e,exports.throttle=function(e,t){let a=null,l=0;return function(...n){const o=Date.now(),r=t-(o-l);r<=0||r>t?(a&&(clearTimeout(a),a=null),l=o,e.apply(this,n)):a||(a=setTimeout(()=>{l=Date.now(),a=null,e.apply(this,n)},r))}},exports.version="1.0.0";
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../packages/components/ScaleContainer/index.vue","../packages/components/ImageCropper/index.vue","../packages/install.ts","../packages/index.ts","../packages/utils/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\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","// 工具函数\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"],"names":["props","__props","scaleContainer","ref","scale","scaleX","scaleY","containerWidth","containerHeight","containerStyle","computed","width","value","height","position","overflow","wrapperStyle","commonStyle","designWidth","designHeight","transformOrigin","keepAspectRatio","scaleMode","sw","sh","transform","top","left","marginTop","marginLeft","updateScale","el","parentElement","parent","pw","clientWidth","window","innerWidth","ph","clientHeight","innerHeight","sx","sy","Math","min","max","resizeObserver","handleResize","onMounted","nextTick","addEventListener","ResizeObserver","_a","observe","onBeforeUnmount","removeEventListener","disconnect","_createElementBlock","class","style","_createElementVNode","_renderSlot","_ctx","$slots","name","emit","__emit","containerRef","contentRef","imageWrapperRef","imageRef","cropBoxRef","imageLoaded","imageNaturalWidth","imageNaturalHeight","imageDisplayWidth","imageDisplayHeight","rotation","zoom","initialZoom","minZoom","maxZoom","cropArea","x","y","isDragging","isResizing","dragType","dragStart","cropStart","imageWrapperStyle","imageStyle","display","cropBoxStyle","cropHandles","type","cursor","right","bottom","handleImageLoad","naturalWidth","naturalHeight","updateImageDisplaySize","initCropArea","naturalAspect","size","cropWidth","cropHeight","cropMode","fixedWidth","fixedHeight","aspectRatio","handleMouseDown","e","target","clientX","clientY","document","handleMouseMove","handleMouseUp","preventDefault","handleCropBoxMouseDown","screenDeltaX","screenDeltaY","rad","PI","cos","sin","deltaX","deltaY","newX","newY","resizeCropBox","w","h","newWidth","newHeight","includes","minWidth","maxWidth","Infinity","minHeight","maxHeight","currentAspect","abs","handleZoomChange","handleWheel","zoomable","delta","newZoom","round","rotateImage","angle","handleCrop","imageSrc","canvas","createElement","ctx","getContext","cropW","cropH","is90Deg","save","translate","rotate","imgCenterX","imgCenterY","drawOffsetX","drawOffsetY","drawImage","restore","toBlob","blob","dataUrl","toDataURL","handleCancel","watch","newSrc","handleKeyDown","tagName","isContentEditable","ctrlKey","metaKey","key","rotatable","shiftKey","tabindex","onMousedown","onWheel","src","onLoad","draggable","showGrid","_openBlock","_hoisted_3","_cache","_Fragment","_renderList","handle","index","_normalizeClass","_normalizeStyle","handleResizeStart","$event","_hoisted_5","_hoisted_6","step","onInput","number","_hoisted_8","_toDisplayString","_hoisted_9","onClick","title","_hoisted_1","components","ScaleContainer","ImageCropper","install","app","forEach","component","__name","installComponents","func","wait","timeout","args","context","this","setTimeout","apply","val","Array","isArray","previous","now","Date","remaining","clearTimeout"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { App } from 'vue';
2
+
3
+ export * from './components';
4
+ export * from './types';
5
+ export * from './utils';
6
+ export declare const install: (app: App) => void;
7
+ declare const _default: {
8
+ install: (app: App) => void;
9
+ };
10
+ export default _default;
11
+ export declare const version = "1.0.0";