yanzhi-ui 0.1.3 → 0.1.5
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/dist/button/Button.vue.d.ts +18 -8
- package/dist/image-preview/ImagePreview.d.ts +37 -0
- package/dist/index.d.ts +3 -1
- package/dist/select/Select.vue.d.ts +15 -0
- package/dist/yanzhi-ui.css +1 -1
- package/dist/yanzhi-ui.js +30 -1
- package/dist/yanzhi-ui.mjs +213 -51
- package/dist/yanzhi-ui.umd.js +30 -1
- package/package.json +1 -1
- package/src/packages/button/Button.vue +118 -60
- package/src/packages/global.d.ts +10 -0
- package/src/packages/image-preview/ImagePreview.ts +200 -0
- package/src/packages/index.ts +13 -3
- package/src/packages/select/Select.vue +45 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
export type ButtonType = 'default' | 'primary' | 'danger';
|
|
2
|
+
export type Size = 'small' | 'medium' | 'large';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
label: string;
|
|
5
|
+
type?: ButtonType;
|
|
6
|
+
size?: Size;
|
|
7
7
|
loading?: boolean;
|
|
8
|
-
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
};
|
|
9
10
|
declare function __VLS_template(): {
|
|
10
11
|
attrs: Partial<{}>;
|
|
11
12
|
slots: {
|
|
@@ -15,7 +16,16 @@ declare function __VLS_template(): {
|
|
|
15
16
|
rootEl: HTMLButtonElement;
|
|
16
17
|
};
|
|
17
18
|
type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
|
|
18
|
-
declare const __VLS_component: import('vue').DefineComponent<
|
|
19
|
+
declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
20
|
+
click: (event: MouseEvent) => any;
|
|
21
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
22
|
+
onClick?: ((event: MouseEvent) => any) | undefined;
|
|
23
|
+
}>, {
|
|
24
|
+
type: ButtonType;
|
|
25
|
+
size: Size;
|
|
26
|
+
loading: boolean;
|
|
27
|
+
disabled: boolean;
|
|
28
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLButtonElement>;
|
|
19
29
|
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
|
|
20
30
|
export default _default;
|
|
21
31
|
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export declare class ImagePreview {
|
|
2
|
+
private container;
|
|
3
|
+
private img;
|
|
4
|
+
private prevBtn;
|
|
5
|
+
private nextBtn;
|
|
6
|
+
private closeBtn;
|
|
7
|
+
private zoomInBtn;
|
|
8
|
+
private zoomOutBtn;
|
|
9
|
+
private resetBtn;
|
|
10
|
+
private zoomLabel;
|
|
11
|
+
private indexLabel;
|
|
12
|
+
private images;
|
|
13
|
+
private currentIndex;
|
|
14
|
+
private scale;
|
|
15
|
+
private position;
|
|
16
|
+
private isDragging;
|
|
17
|
+
private dragStart;
|
|
18
|
+
private startPos;
|
|
19
|
+
private zoomTimeout;
|
|
20
|
+
constructor(images: string[], initialIndex?: number);
|
|
21
|
+
private createBtn;
|
|
22
|
+
private updateImage;
|
|
23
|
+
private updateIndex;
|
|
24
|
+
private showZoomLabel;
|
|
25
|
+
private startDrag;
|
|
26
|
+
private onDrag;
|
|
27
|
+
private endDrag;
|
|
28
|
+
private handleWheel;
|
|
29
|
+
private zoomIn;
|
|
30
|
+
private zoomOut;
|
|
31
|
+
private reset;
|
|
32
|
+
private prev;
|
|
33
|
+
private next;
|
|
34
|
+
close(): void;
|
|
35
|
+
private handleKeydown;
|
|
36
|
+
open(index?: number): void;
|
|
37
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { App } from 'vue';
|
|
2
2
|
import { default as IButton } from './button/Button.vue';
|
|
3
|
-
|
|
3
|
+
import { default as ISelect } from './select/Select.vue';
|
|
4
|
+
import { ImagePreview } from './image-preview/ImagePreview';
|
|
5
|
+
export { IButton, ISelect, ImagePreview };
|
|
4
6
|
declare const _default: {
|
|
5
7
|
install: (app: App) => void;
|
|
6
8
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface OptionItem {
|
|
2
|
+
label: string;
|
|
3
|
+
value: string | number;
|
|
4
|
+
}
|
|
5
|
+
type __VLS_Props = {
|
|
6
|
+
modelValue?: string | number;
|
|
7
|
+
options: OptionItem[];
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
};
|
|
10
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
11
|
+
"update:modelValue": (value: string | number) => any;
|
|
12
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
13
|
+
"onUpdate:modelValue"?: ((value: string | number) => any) | undefined;
|
|
14
|
+
}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLSelectElement>;
|
|
15
|
+
export default _default;
|
package/dist/yanzhi-ui.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.i-button
|
|
1
|
+
.i-button{display:inline-flex;align-items:center;gap:6px;cursor:pointer;-webkit-user-select:none;user-select:none;border:none;border-radius:.25rem}.i-button--default{background:#f5f5f5}.i-button--default:hover{background:#d1d1d1}.i-button--primary{background:#409eff;color:#fff}.i-button--primary:hover{background:#398adb;color:#fff}.i-button--danger{background:#f56c6c;color:#fff}.i-button--danger:hover{background:#e05a5a;color:#fff}.i-button--small{height:1.4rem;padding:0 .5rem;font-size:12px}.i-button--medium{height:24px;padding:0 .75rem;font-size:14px}.i-button--large{height:32px;padding:0 1rem;font-size:15px}.i-button.is-disabled{cursor:not-allowed;opacity:.6}
|
package/dist/yanzhi-ui.js
CHANGED
|
@@ -1 +1,30 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var m=Object.defineProperty;var u=(n,t,e)=>t in n?m(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var s=(n,t,e)=>u(n,typeof t!="symbol"?t+"":t,e);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const i=require("vue"),p=["disabled"],g={class:"i-button__label"},h=i.defineComponent({name:"IButton",__name:"Button",props:{label:{},type:{default:"default"},size:{default:"medium"},loading:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1}},emits:["click"],setup(n,{emit:t}){const e=n,a=t,o=i.computed(()=>e.disabled||e.loading);function l(r){o.value||a("click",r)}const d=i.computed(()=>["i-button",`i-button--${e.type}`,`i-button--${e.size}`,o.value&&"is-disabled",e.loading&&"is-loading"]);return(r,z)=>(i.openBlock(),i.createElementBlock("button",i.mergeProps({type:"button",disabled:o.value,class:d.value,onClick:l},r.$attrs),[i.createElementVNode("span",g,[i.renderSlot(r.$slots,"default")])],16,p))}}),b=["value","disabled"],x=["value"],f=i.defineComponent({__name:"Select",props:{modelValue:{},options:{},disabled:{type:Boolean}},emits:["update:modelValue"],setup(n,{emit:t}){const e=n,a=t;function o(l){const d=l.target;a("update:modelValue",d.value)}return(l,d)=>(i.openBlock(),i.createElementBlock("select",{value:n.modelValue,onChange:o,disabled:e.disabled},[(i.openBlock(!0),i.createElementBlock(i.Fragment,null,i.renderList(n.options,r=>(i.openBlock(),i.createElementBlock("option",{key:r.value,value:r.value},i.toDisplayString(r.label),9,x))),128))],40,b))}}),y=(n,t)=>{const e=n.__vccOpts||n;for(const[a,o]of t)e[a]=o;return e},c=y(f,[["__scopeId","data-v-1c19bb1f"]]);class v{constructor(t,e=0){s(this,"container");s(this,"img");s(this,"prevBtn");s(this,"nextBtn");s(this,"closeBtn");s(this,"zoomInBtn");s(this,"zoomOutBtn");s(this,"resetBtn");s(this,"zoomLabel");s(this,"indexLabel");s(this,"images");s(this,"currentIndex",0);s(this,"scale",1);s(this,"position",{x:0,y:0});s(this,"isDragging",!1);s(this,"dragStart",{x:0,y:0});s(this,"startPos",{x:0,y:0});s(this,"zoomTimeout",null);this.images=t,this.currentIndex=e,this.container=document.createElement("div"),this.container.className="ip-overlay",this.container.style.cssText=`
|
|
2
|
+
position: fixed;
|
|
3
|
+
inset: 0;
|
|
4
|
+
background: rgba(0,0,0,0.8);
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
z-index: 9999;
|
|
9
|
+
`,this.container.addEventListener("click",a=>{a.target===this.container&&this.close()}),this.img=document.createElement("img"),this.img.className="ip-image",this.img.draggable=!1,this.img.style.maxWidth="100%",this.img.style.maxHeight="100%",this.img.style.userSelect="none",this.img.style.pointerEvents="none",this.updateImage(),this.img.addEventListener("mousedown",this.startDrag.bind(this)),document.addEventListener("mousemove",this.onDrag.bind(this)),document.addEventListener("mouseup",this.endDrag.bind(this)),this.img.addEventListener("wheel",this.handleWheel.bind(this)),this.prevBtn=this.createBtn("‹",{left:"16px",top:"50%",transform:"translateY(-50%)"},()=>this.prev()),this.nextBtn=this.createBtn("›",{right:"16px",top:"50%",transform:"translateY(-50%)"},()=>this.next()),this.closeBtn=this.createBtn("×",{right:"16px",top:"16px"},()=>this.close()),this.zoomInBtn=this.createBtn("+",{bottom:"20px",left:"50%",marginLeft:"40px"},()=>this.zoomIn()),this.zoomOutBtn=this.createBtn("-",{bottom:"20px",left:"50%",marginRight:"40px"},()=>this.zoomOut()),this.resetBtn=this.createBtn("0",{bottom:"20px",left:"50%"},()=>this.reset()),this.zoomLabel=document.createElement("div"),this.zoomLabel.style.cssText=`
|
|
10
|
+
position: absolute;
|
|
11
|
+
top: 16px;
|
|
12
|
+
left: 50%;
|
|
13
|
+
transform: translateX(-50%);
|
|
14
|
+
color: #fff;
|
|
15
|
+
background: rgba(0,0,0,0.6);
|
|
16
|
+
padding: 4px 8px;
|
|
17
|
+
border-radius: 4px;
|
|
18
|
+
font-size: 14px;
|
|
19
|
+
display: none;
|
|
20
|
+
`,this.indexLabel=document.createElement("div"),this.indexLabel.style.cssText=`
|
|
21
|
+
position: absolute;
|
|
22
|
+
bottom: 8px;
|
|
23
|
+
left: 50%;
|
|
24
|
+
transform: translateX(-50%);
|
|
25
|
+
color: #fff;
|
|
26
|
+
background: rgba(0,0,0,0.6);
|
|
27
|
+
padding: 2px 6px;
|
|
28
|
+
border-radius: 4px;
|
|
29
|
+
font-size: 14px;
|
|
30
|
+
`,this.container.appendChild(this.img),this.container.appendChild(this.prevBtn),this.container.appendChild(this.nextBtn),this.container.appendChild(this.closeBtn),this.container.appendChild(this.zoomInBtn),this.container.appendChild(this.zoomOutBtn),this.container.appendChild(this.resetBtn),this.container.appendChild(this.zoomLabel),this.container.appendChild(this.indexLabel),document.body.appendChild(this.container),document.addEventListener("keydown",this.handleKeydown.bind(this)),this.updateIndex()}createBtn(t,e,a){const o=document.createElement("button");return o.textContent=t,Object.assign(o.style,{position:"absolute",width:"36px",height:"36px",border:"none",borderRadius:"50%",background:"rgba(0,0,0,0.6)",color:"#fff",cursor:"pointer",fontSize:"18px",...e}),o.addEventListener("click",a),o.addEventListener("mouseover",()=>o.style.background="rgba(0,0,0,0.8)"),o.addEventListener("mouseout",()=>o.style.background="rgba(0,0,0,0.6)"),o}updateImage(){this.img.src=this.images[this.currentIndex],this.img.style.transform=`scale(${this.scale}) translate(${this.position.x}px, ${this.position.y}px)`}updateIndex(){this.indexLabel.textContent=`${this.currentIndex+1} / ${this.images.length}`}showZoomLabel(){this.zoomLabel.textContent=`${Math.round(this.scale*100)}%`,this.zoomLabel.style.display="block",this.zoomTimeout&&clearTimeout(this.zoomTimeout),this.zoomTimeout=window.setTimeout(()=>{this.zoomLabel.style.display="none"},800)}startDrag(t){this.isDragging=!0,this.dragStart={x:t.clientX,y:t.clientY},this.startPos={...this.position}}onDrag(t){if(!this.isDragging)return;const e=(t.clientX-this.dragStart.x)/this.scale,a=(t.clientY-this.dragStart.y)/this.scale;this.position.x=this.startPos.x+e,this.position.y=this.startPos.y+a,this.updateImage()}endDrag(){this.isDragging=!1}handleWheel(t){t.deltaY<0?this.zoomIn():this.zoomOut()}zoomIn(){this.scale=Math.min(this.scale+.1,3),this.updateImage(),this.showZoomLabel()}zoomOut(){this.scale=Math.max(this.scale-.1,.2),this.updateImage(),this.showZoomLabel()}reset(){this.scale=1,this.position={x:0,y:0},this.updateImage(),this.showZoomLabel()}prev(){this.currentIndex>0&&(this.currentIndex--,this.reset(),this.updateImage(),this.updateIndex())}next(){this.currentIndex<this.images.length-1&&(this.currentIndex++,this.reset(),this.updateImage(),this.updateIndex())}close(){this.container.style.display="none",document.removeEventListener("keydown",this.handleKeydown.bind(this))}handleKeydown(t){switch(t.key){case"Escape":this.close();break;case"ArrowLeft":this.prev();break;case"ArrowRight":this.next();break;case"+":case"=":this.zoomIn();break;case"-":this.zoomOut();break;case"0":this.reset();break}}open(t=0){this.currentIndex=t,this.reset(),this.updateImage(),this.updateIndex(),this.container.style.display="flex"}}const B=[h,c],I=n=>{B.forEach(t=>{n.component(t.name,t)})},k={install:I};exports.IButton=h;exports.ISelect=c;exports.ImagePreview=v;exports.default=k;
|
package/dist/yanzhi-ui.mjs
CHANGED
|
@@ -1,58 +1,220 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { defineComponent as
|
|
5
|
-
const
|
|
1
|
+
var u = Object.defineProperty;
|
|
2
|
+
var p = (i, t, e) => t in i ? u(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
|
|
3
|
+
var s = (i, t, e) => p(i, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import { defineComponent as m, computed as c, createElementBlock as d, openBlock as h, mergeProps as g, createElementVNode as b, renderSlot as x, Fragment as f, renderList as y, toDisplayString as v } from "vue";
|
|
5
|
+
const I = ["disabled"], B = { class: "i-button__label" }, z = /* @__PURE__ */ m({
|
|
6
|
+
name: "IButton",
|
|
6
7
|
__name: "Button",
|
|
7
8
|
props: {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
disabled: { type: Boolean }
|
|
13
|
-
loading: { type: Boolean }
|
|
9
|
+
label: {},
|
|
10
|
+
type: { default: "default" },
|
|
11
|
+
size: { default: "medium" },
|
|
12
|
+
loading: { type: Boolean, default: !1 },
|
|
13
|
+
disabled: { type: Boolean, default: !1 }
|
|
14
14
|
},
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
l(this, "disabled");
|
|
23
|
-
l(this, "loading");
|
|
24
|
-
this.type = t.type || "default", this.size = t.size || "medium", this.color = t.color, this.textColor = t.textColor, this.disabled = t.disabled ?? !1, this.loading = t.loading ?? !1;
|
|
25
|
-
}
|
|
26
|
-
get classes() {
|
|
27
|
-
const t = ["i-button", this.type, this.size];
|
|
28
|
-
return this.disabled && t.push("disabled"), this.loading && t.push("loading"), t.join(" ");
|
|
29
|
-
}
|
|
30
|
-
get styles() {
|
|
31
|
-
return {
|
|
32
|
-
backgroundColor: this.color || "",
|
|
33
|
-
color: this.textColor || ""
|
|
34
|
-
};
|
|
35
|
-
}
|
|
15
|
+
emits: ["click"],
|
|
16
|
+
setup(i, { emit: t }) {
|
|
17
|
+
const e = i, a = t, n = c(
|
|
18
|
+
() => e.disabled || e.loading
|
|
19
|
+
);
|
|
20
|
+
function r(o) {
|
|
21
|
+
n.value || a("click", o);
|
|
36
22
|
}
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
23
|
+
const l = c(() => [
|
|
24
|
+
"i-button",
|
|
25
|
+
`i-button--${e.type}`,
|
|
26
|
+
`i-button--${e.size}`,
|
|
27
|
+
n.value && "is-disabled",
|
|
28
|
+
e.loading && "is-loading"
|
|
29
|
+
]);
|
|
30
|
+
return (o, D) => (h(), d("button", g({
|
|
31
|
+
type: "button",
|
|
32
|
+
disabled: n.value,
|
|
33
|
+
class: l.value,
|
|
34
|
+
onClick: r
|
|
35
|
+
}, o.$attrs), [
|
|
36
|
+
b("span", B, [
|
|
37
|
+
x(o.$slots, "default")
|
|
38
|
+
])
|
|
39
|
+
], 16, I));
|
|
40
|
+
}
|
|
41
|
+
}), L = ["value", "disabled"], k = ["value"], _ = /* @__PURE__ */ m({
|
|
42
|
+
__name: "Select",
|
|
43
|
+
props: {
|
|
44
|
+
modelValue: {},
|
|
45
|
+
options: {},
|
|
46
|
+
disabled: { type: Boolean }
|
|
47
|
+
},
|
|
48
|
+
emits: ["update:modelValue"],
|
|
49
|
+
setup(i, { emit: t }) {
|
|
50
|
+
const e = i, a = t;
|
|
51
|
+
function n(r) {
|
|
52
|
+
const l = r.target;
|
|
53
|
+
a("update:modelValue", l.value);
|
|
54
|
+
}
|
|
55
|
+
return (r, l) => (h(), d("select", {
|
|
56
|
+
value: i.modelValue,
|
|
57
|
+
onChange: n,
|
|
58
|
+
disabled: e.disabled
|
|
43
59
|
}, [
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}),
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
60
|
+
(h(!0), d(f, null, y(i.options, (o) => (h(), d("option", {
|
|
61
|
+
key: o.value,
|
|
62
|
+
value: o.value
|
|
63
|
+
}, v(o.label), 9, k))), 128))
|
|
64
|
+
], 40, L));
|
|
65
|
+
}
|
|
66
|
+
}), E = (i, t) => {
|
|
67
|
+
const e = i.__vccOpts || i;
|
|
68
|
+
for (const [a, n] of t)
|
|
69
|
+
e[a] = n;
|
|
70
|
+
return e;
|
|
71
|
+
}, w = /* @__PURE__ */ E(_, [["__scopeId", "data-v-1c19bb1f"]]);
|
|
72
|
+
class T {
|
|
73
|
+
constructor(t, e = 0) {
|
|
74
|
+
s(this, "container");
|
|
75
|
+
s(this, "img");
|
|
76
|
+
s(this, "prevBtn");
|
|
77
|
+
s(this, "nextBtn");
|
|
78
|
+
s(this, "closeBtn");
|
|
79
|
+
s(this, "zoomInBtn");
|
|
80
|
+
s(this, "zoomOutBtn");
|
|
81
|
+
s(this, "resetBtn");
|
|
82
|
+
s(this, "zoomLabel");
|
|
83
|
+
s(this, "indexLabel");
|
|
84
|
+
s(this, "images");
|
|
85
|
+
s(this, "currentIndex", 0);
|
|
86
|
+
s(this, "scale", 1);
|
|
87
|
+
s(this, "position", { x: 0, y: 0 });
|
|
88
|
+
s(this, "isDragging", !1);
|
|
89
|
+
s(this, "dragStart", { x: 0, y: 0 });
|
|
90
|
+
s(this, "startPos", { x: 0, y: 0 });
|
|
91
|
+
s(this, "zoomTimeout", null);
|
|
92
|
+
this.images = t, this.currentIndex = e, this.container = document.createElement("div"), this.container.className = "ip-overlay", this.container.style.cssText = `
|
|
93
|
+
position: fixed;
|
|
94
|
+
inset: 0;
|
|
95
|
+
background: rgba(0,0,0,0.8);
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
z-index: 9999;
|
|
100
|
+
`, this.container.addEventListener("click", (a) => {
|
|
101
|
+
a.target === this.container && this.close();
|
|
102
|
+
}), this.img = document.createElement("img"), this.img.className = "ip-image", this.img.draggable = !1, this.img.style.maxWidth = "100%", this.img.style.maxHeight = "100%", this.img.style.userSelect = "none", this.img.style.pointerEvents = "none", this.updateImage(), this.img.addEventListener("mousedown", this.startDrag.bind(this)), document.addEventListener("mousemove", this.onDrag.bind(this)), document.addEventListener("mouseup", this.endDrag.bind(this)), this.img.addEventListener("wheel", this.handleWheel.bind(this)), this.prevBtn = this.createBtn("‹", { left: "16px", top: "50%", transform: "translateY(-50%)" }, () => this.prev()), this.nextBtn = this.createBtn("›", { right: "16px", top: "50%", transform: "translateY(-50%)" }, () => this.next()), this.closeBtn = this.createBtn("×", { right: "16px", top: "16px" }, () => this.close()), this.zoomInBtn = this.createBtn("+", { bottom: "20px", left: "50%", marginLeft: "40px" }, () => this.zoomIn()), this.zoomOutBtn = this.createBtn("-", { bottom: "20px", left: "50%", marginRight: "40px" }, () => this.zoomOut()), this.resetBtn = this.createBtn("0", { bottom: "20px", left: "50%" }, () => this.reset()), this.zoomLabel = document.createElement("div"), this.zoomLabel.style.cssText = `
|
|
103
|
+
position: absolute;
|
|
104
|
+
top: 16px;
|
|
105
|
+
left: 50%;
|
|
106
|
+
transform: translateX(-50%);
|
|
107
|
+
color: #fff;
|
|
108
|
+
background: rgba(0,0,0,0.6);
|
|
109
|
+
padding: 4px 8px;
|
|
110
|
+
border-radius: 4px;
|
|
111
|
+
font-size: 14px;
|
|
112
|
+
display: none;
|
|
113
|
+
`, this.indexLabel = document.createElement("div"), this.indexLabel.style.cssText = `
|
|
114
|
+
position: absolute;
|
|
115
|
+
bottom: 8px;
|
|
116
|
+
left: 50%;
|
|
117
|
+
transform: translateX(-50%);
|
|
118
|
+
color: #fff;
|
|
119
|
+
background: rgba(0,0,0,0.6);
|
|
120
|
+
padding: 2px 6px;
|
|
121
|
+
border-radius: 4px;
|
|
122
|
+
font-size: 14px;
|
|
123
|
+
`, this.container.appendChild(this.img), this.container.appendChild(this.prevBtn), this.container.appendChild(this.nextBtn), this.container.appendChild(this.closeBtn), this.container.appendChild(this.zoomInBtn), this.container.appendChild(this.zoomOutBtn), this.container.appendChild(this.resetBtn), this.container.appendChild(this.zoomLabel), this.container.appendChild(this.indexLabel), document.body.appendChild(this.container), document.addEventListener("keydown", this.handleKeydown.bind(this)), this.updateIndex();
|
|
124
|
+
}
|
|
125
|
+
createBtn(t, e, a) {
|
|
126
|
+
const n = document.createElement("button");
|
|
127
|
+
return n.textContent = t, Object.assign(n.style, {
|
|
128
|
+
position: "absolute",
|
|
129
|
+
width: "36px",
|
|
130
|
+
height: "36px",
|
|
131
|
+
border: "none",
|
|
132
|
+
borderRadius: "50%",
|
|
133
|
+
background: "rgba(0,0,0,0.6)",
|
|
134
|
+
color: "#fff",
|
|
135
|
+
cursor: "pointer",
|
|
136
|
+
fontSize: "18px",
|
|
137
|
+
...e
|
|
138
|
+
}), n.addEventListener("click", a), n.addEventListener("mouseover", () => n.style.background = "rgba(0,0,0,0.8)"), n.addEventListener("mouseout", () => n.style.background = "rgba(0,0,0,0.6)"), n;
|
|
139
|
+
}
|
|
140
|
+
updateImage() {
|
|
141
|
+
this.img.src = this.images[this.currentIndex], this.img.style.transform = `scale(${this.scale}) translate(${this.position.x}px, ${this.position.y}px)`;
|
|
142
|
+
}
|
|
143
|
+
updateIndex() {
|
|
144
|
+
this.indexLabel.textContent = `${this.currentIndex + 1} / ${this.images.length}`;
|
|
145
|
+
}
|
|
146
|
+
showZoomLabel() {
|
|
147
|
+
this.zoomLabel.textContent = `${Math.round(this.scale * 100)}%`, this.zoomLabel.style.display = "block", this.zoomTimeout && clearTimeout(this.zoomTimeout), this.zoomTimeout = window.setTimeout(() => {
|
|
148
|
+
this.zoomLabel.style.display = "none";
|
|
149
|
+
}, 800);
|
|
150
|
+
}
|
|
151
|
+
startDrag(t) {
|
|
152
|
+
this.isDragging = !0, this.dragStart = { x: t.clientX, y: t.clientY }, this.startPos = { ...this.position };
|
|
153
|
+
}
|
|
154
|
+
onDrag(t) {
|
|
155
|
+
if (!this.isDragging) return;
|
|
156
|
+
const e = (t.clientX - this.dragStart.x) / this.scale, a = (t.clientY - this.dragStart.y) / this.scale;
|
|
157
|
+
this.position.x = this.startPos.x + e, this.position.y = this.startPos.y + a, this.updateImage();
|
|
158
|
+
}
|
|
159
|
+
endDrag() {
|
|
160
|
+
this.isDragging = !1;
|
|
161
|
+
}
|
|
162
|
+
handleWheel(t) {
|
|
163
|
+
t.deltaY < 0 ? this.zoomIn() : this.zoomOut();
|
|
164
|
+
}
|
|
165
|
+
zoomIn() {
|
|
166
|
+
this.scale = Math.min(this.scale + 0.1, 3), this.updateImage(), this.showZoomLabel();
|
|
167
|
+
}
|
|
168
|
+
zoomOut() {
|
|
169
|
+
this.scale = Math.max(this.scale - 0.1, 0.2), this.updateImage(), this.showZoomLabel();
|
|
170
|
+
}
|
|
171
|
+
reset() {
|
|
172
|
+
this.scale = 1, this.position = { x: 0, y: 0 }, this.updateImage(), this.showZoomLabel();
|
|
173
|
+
}
|
|
174
|
+
prev() {
|
|
175
|
+
this.currentIndex > 0 && (this.currentIndex--, this.reset(), this.updateImage(), this.updateIndex());
|
|
176
|
+
}
|
|
177
|
+
next() {
|
|
178
|
+
this.currentIndex < this.images.length - 1 && (this.currentIndex++, this.reset(), this.updateImage(), this.updateIndex());
|
|
179
|
+
}
|
|
180
|
+
close() {
|
|
181
|
+
this.container.style.display = "none", document.removeEventListener("keydown", this.handleKeydown.bind(this));
|
|
182
|
+
}
|
|
183
|
+
handleKeydown(t) {
|
|
184
|
+
switch (t.key) {
|
|
185
|
+
case "Escape":
|
|
186
|
+
this.close();
|
|
187
|
+
break;
|
|
188
|
+
case "ArrowLeft":
|
|
189
|
+
this.prev();
|
|
190
|
+
break;
|
|
191
|
+
case "ArrowRight":
|
|
192
|
+
this.next();
|
|
193
|
+
break;
|
|
194
|
+
case "+":
|
|
195
|
+
case "=":
|
|
196
|
+
this.zoomIn();
|
|
197
|
+
break;
|
|
198
|
+
case "-":
|
|
199
|
+
this.zoomOut();
|
|
200
|
+
break;
|
|
201
|
+
case "0":
|
|
202
|
+
this.reset();
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
open(t = 0) {
|
|
207
|
+
this.currentIndex = t, this.reset(), this.updateImage(), this.updateIndex(), this.container.style.display = "flex";
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const C = [z, w], $ = (i) => {
|
|
211
|
+
C.forEach((t) => {
|
|
212
|
+
i.component(t.name, t);
|
|
213
|
+
});
|
|
214
|
+
}, P = { install: $ };
|
|
55
215
|
export {
|
|
56
|
-
|
|
57
|
-
|
|
216
|
+
z as IButton,
|
|
217
|
+
w as ISelect,
|
|
218
|
+
T as ImagePreview,
|
|
219
|
+
P as default
|
|
58
220
|
};
|
package/dist/yanzhi-ui.umd.js
CHANGED
|
@@ -1 +1,30 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(i,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],t):(i=typeof globalThis<"u"?globalThis:i||self,t(i.YanzhiUI={},i.Vue))})(this,(function(i,t){"use strict";var B=Object.defineProperty;var I=(i,t,d)=>t in i?B(i,t,{enumerable:!0,configurable:!0,writable:!0,value:d}):i[t]=d;var s=(i,t,d)=>I(i,typeof t!="symbol"?t+"":t,d);const d=["disabled"],u={class:"i-button__label"},m=t.defineComponent({name:"IButton",__name:"Button",props:{label:{},type:{default:"default"},size:{default:"medium"},loading:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1}},emits:["click"],setup(a,{emit:e}){const n=a,r=e,o=t.computed(()=>n.disabled||n.loading);function h(l){o.value||r("click",l)}const c=t.computed(()=>["i-button",`i-button--${n.type}`,`i-button--${n.size}`,o.value&&"is-disabled",n.loading&&"is-loading"]);return(l,_)=>(t.openBlock(),t.createElementBlock("button",t.mergeProps({type:"button",disabled:o.value,class:c.value,onClick:h},l.$attrs),[t.createElementVNode("span",u,[t.renderSlot(l.$slots,"default")])],16,d))}}),g=["value","disabled"],b=["value"],p=((a,e)=>{const n=a.__vccOpts||a;for(const[r,o]of e)n[r]=o;return n})(t.defineComponent({__name:"Select",props:{modelValue:{},options:{},disabled:{type:Boolean}},emits:["update:modelValue"],setup(a,{emit:e}){const n=a,r=e;function o(h){const c=h.target;r("update:modelValue",c.value)}return(h,c)=>(t.openBlock(),t.createElementBlock("select",{value:a.modelValue,onChange:o,disabled:n.disabled},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(a.options,l=>(t.openBlock(),t.createElementBlock("option",{key:l.value,value:l.value},t.toDisplayString(l.label),9,b))),128))],40,g))}}),[["__scopeId","data-v-1c19bb1f"]]);class x{constructor(e,n=0){s(this,"container");s(this,"img");s(this,"prevBtn");s(this,"nextBtn");s(this,"closeBtn");s(this,"zoomInBtn");s(this,"zoomOutBtn");s(this,"resetBtn");s(this,"zoomLabel");s(this,"indexLabel");s(this,"images");s(this,"currentIndex",0);s(this,"scale",1);s(this,"position",{x:0,y:0});s(this,"isDragging",!1);s(this,"dragStart",{x:0,y:0});s(this,"startPos",{x:0,y:0});s(this,"zoomTimeout",null);this.images=e,this.currentIndex=n,this.container=document.createElement("div"),this.container.className="ip-overlay",this.container.style.cssText=`
|
|
2
|
+
position: fixed;
|
|
3
|
+
inset: 0;
|
|
4
|
+
background: rgba(0,0,0,0.8);
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
z-index: 9999;
|
|
9
|
+
`,this.container.addEventListener("click",r=>{r.target===this.container&&this.close()}),this.img=document.createElement("img"),this.img.className="ip-image",this.img.draggable=!1,this.img.style.maxWidth="100%",this.img.style.maxHeight="100%",this.img.style.userSelect="none",this.img.style.pointerEvents="none",this.updateImage(),this.img.addEventListener("mousedown",this.startDrag.bind(this)),document.addEventListener("mousemove",this.onDrag.bind(this)),document.addEventListener("mouseup",this.endDrag.bind(this)),this.img.addEventListener("wheel",this.handleWheel.bind(this)),this.prevBtn=this.createBtn("‹",{left:"16px",top:"50%",transform:"translateY(-50%)"},()=>this.prev()),this.nextBtn=this.createBtn("›",{right:"16px",top:"50%",transform:"translateY(-50%)"},()=>this.next()),this.closeBtn=this.createBtn("×",{right:"16px",top:"16px"},()=>this.close()),this.zoomInBtn=this.createBtn("+",{bottom:"20px",left:"50%",marginLeft:"40px"},()=>this.zoomIn()),this.zoomOutBtn=this.createBtn("-",{bottom:"20px",left:"50%",marginRight:"40px"},()=>this.zoomOut()),this.resetBtn=this.createBtn("0",{bottom:"20px",left:"50%"},()=>this.reset()),this.zoomLabel=document.createElement("div"),this.zoomLabel.style.cssText=`
|
|
10
|
+
position: absolute;
|
|
11
|
+
top: 16px;
|
|
12
|
+
left: 50%;
|
|
13
|
+
transform: translateX(-50%);
|
|
14
|
+
color: #fff;
|
|
15
|
+
background: rgba(0,0,0,0.6);
|
|
16
|
+
padding: 4px 8px;
|
|
17
|
+
border-radius: 4px;
|
|
18
|
+
font-size: 14px;
|
|
19
|
+
display: none;
|
|
20
|
+
`,this.indexLabel=document.createElement("div"),this.indexLabel.style.cssText=`
|
|
21
|
+
position: absolute;
|
|
22
|
+
bottom: 8px;
|
|
23
|
+
left: 50%;
|
|
24
|
+
transform: translateX(-50%);
|
|
25
|
+
color: #fff;
|
|
26
|
+
background: rgba(0,0,0,0.6);
|
|
27
|
+
padding: 2px 6px;
|
|
28
|
+
border-radius: 4px;
|
|
29
|
+
font-size: 14px;
|
|
30
|
+
`,this.container.appendChild(this.img),this.container.appendChild(this.prevBtn),this.container.appendChild(this.nextBtn),this.container.appendChild(this.closeBtn),this.container.appendChild(this.zoomInBtn),this.container.appendChild(this.zoomOutBtn),this.container.appendChild(this.resetBtn),this.container.appendChild(this.zoomLabel),this.container.appendChild(this.indexLabel),document.body.appendChild(this.container),document.addEventListener("keydown",this.handleKeydown.bind(this)),this.updateIndex()}createBtn(e,n,r){const o=document.createElement("button");return o.textContent=e,Object.assign(o.style,{position:"absolute",width:"36px",height:"36px",border:"none",borderRadius:"50%",background:"rgba(0,0,0,0.6)",color:"#fff",cursor:"pointer",fontSize:"18px",...n}),o.addEventListener("click",r),o.addEventListener("mouseover",()=>o.style.background="rgba(0,0,0,0.8)"),o.addEventListener("mouseout",()=>o.style.background="rgba(0,0,0,0.6)"),o}updateImage(){this.img.src=this.images[this.currentIndex],this.img.style.transform=`scale(${this.scale}) translate(${this.position.x}px, ${this.position.y}px)`}updateIndex(){this.indexLabel.textContent=`${this.currentIndex+1} / ${this.images.length}`}showZoomLabel(){this.zoomLabel.textContent=`${Math.round(this.scale*100)}%`,this.zoomLabel.style.display="block",this.zoomTimeout&&clearTimeout(this.zoomTimeout),this.zoomTimeout=window.setTimeout(()=>{this.zoomLabel.style.display="none"},800)}startDrag(e){this.isDragging=!0,this.dragStart={x:e.clientX,y:e.clientY},this.startPos={...this.position}}onDrag(e){if(!this.isDragging)return;const n=(e.clientX-this.dragStart.x)/this.scale,r=(e.clientY-this.dragStart.y)/this.scale;this.position.x=this.startPos.x+n,this.position.y=this.startPos.y+r,this.updateImage()}endDrag(){this.isDragging=!1}handleWheel(e){e.deltaY<0?this.zoomIn():this.zoomOut()}zoomIn(){this.scale=Math.min(this.scale+.1,3),this.updateImage(),this.showZoomLabel()}zoomOut(){this.scale=Math.max(this.scale-.1,.2),this.updateImage(),this.showZoomLabel()}reset(){this.scale=1,this.position={x:0,y:0},this.updateImage(),this.showZoomLabel()}prev(){this.currentIndex>0&&(this.currentIndex--,this.reset(),this.updateImage(),this.updateIndex())}next(){this.currentIndex<this.images.length-1&&(this.currentIndex++,this.reset(),this.updateImage(),this.updateIndex())}close(){this.container.style.display="none",document.removeEventListener("keydown",this.handleKeydown.bind(this))}handleKeydown(e){switch(e.key){case"Escape":this.close();break;case"ArrowLeft":this.prev();break;case"ArrowRight":this.next();break;case"+":case"=":this.zoomIn();break;case"-":this.zoomOut();break;case"0":this.reset();break}}open(e=0){this.currentIndex=e,this.reset(),this.updateImage(),this.updateIndex(),this.container.style.display="flex"}}const f=[m,p],y={install:a=>{f.forEach(e=>{a.component(e.name,e)})}};i.IButton=m,i.ISelect=p,i.ImagePreview=x,i.default=y,Object.defineProperties(i,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
package/package.json
CHANGED
|
@@ -1,75 +1,133 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<button
|
|
3
|
-
:class="button.classes"
|
|
4
|
-
:style="button.styles"
|
|
5
|
-
:disabled="button.disabled"
|
|
6
|
-
@click="$emit('click', $event)"
|
|
7
|
-
>
|
|
8
|
-
<slot />
|
|
9
|
-
</button>
|
|
10
|
-
</template>
|
|
11
|
-
|
|
12
1
|
<script setup lang="ts">
|
|
13
|
-
import {
|
|
2
|
+
import { computed } from 'vue'
|
|
14
3
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
4
|
+
defineOptions({
|
|
5
|
+
name: 'IButton',
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
export type ButtonType =
|
|
9
|
+
| 'default'
|
|
10
|
+
| 'primary'
|
|
11
|
+
| 'danger'
|
|
12
|
+
|
|
13
|
+
export type Size = 'small' | 'medium' | 'large'
|
|
14
|
+
|
|
15
|
+
const props = withDefaults(defineProps<{
|
|
16
|
+
label: string
|
|
17
|
+
type?: ButtonType
|
|
18
|
+
size?: Size
|
|
21
19
|
loading?: boolean
|
|
20
|
+
disabled?: boolean
|
|
21
|
+
}>(), {
|
|
22
|
+
type: 'default',
|
|
23
|
+
size: 'medium',
|
|
24
|
+
loading: false,
|
|
25
|
+
disabled: false,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const emit = defineEmits<{
|
|
29
|
+
(e: 'click', event: MouseEvent): void
|
|
30
|
+
}>()
|
|
31
|
+
|
|
32
|
+
const isDisabled = computed(() =>
|
|
33
|
+
props.disabled || props.loading
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
function handleClick(e: MouseEvent) {
|
|
37
|
+
if (isDisabled.value) return
|
|
38
|
+
emit('click', e)
|
|
22
39
|
}
|
|
23
40
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
const classes = computed(() => [
|
|
42
|
+
'i-button',
|
|
43
|
+
`i-button--${props.type}`,
|
|
44
|
+
`i-button--${props.size}`,
|
|
45
|
+
isDisabled.value && 'is-disabled',
|
|
46
|
+
props.loading && 'is-loading',
|
|
47
|
+
])
|
|
48
|
+
</script>
|
|
31
49
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
50
|
+
<template>
|
|
51
|
+
<button
|
|
52
|
+
type="button"
|
|
53
|
+
:disabled="isDisabled"
|
|
54
|
+
:class="classes"
|
|
55
|
+
@click="handleClick"
|
|
56
|
+
v-bind="$attrs"
|
|
57
|
+
>
|
|
58
|
+
<!-- 文本 -->
|
|
59
|
+
<span class="i-button__label">
|
|
60
|
+
<slot />
|
|
61
|
+
</span>
|
|
62
|
+
</button>
|
|
63
|
+
</template>
|
|
40
64
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
65
|
+
<style>
|
|
66
|
+
/* ===============================
|
|
67
|
+
Base
|
|
68
|
+
=============================== */
|
|
69
|
+
.i-button {
|
|
70
|
+
display: inline-flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
gap: 6px;
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
user-select: none;
|
|
75
|
+
border: none;
|
|
76
|
+
border-radius: 0.25rem;
|
|
77
|
+
}
|
|
47
78
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
79
|
+
/* ===============================
|
|
80
|
+
类型
|
|
81
|
+
=============================== */
|
|
82
|
+
.i-button--default {
|
|
83
|
+
background: #f5f5f5;
|
|
84
|
+
}
|
|
85
|
+
.i-button--default:hover {
|
|
86
|
+
background: #d1d1d1;
|
|
54
87
|
}
|
|
55
88
|
|
|
56
|
-
|
|
89
|
+
.i-button--primary {
|
|
90
|
+
background: #409eff;
|
|
91
|
+
color: #fff;
|
|
92
|
+
}
|
|
93
|
+
.i-button--primary:hover {
|
|
94
|
+
background: #398adb;
|
|
95
|
+
color: #fff;
|
|
96
|
+
}
|
|
57
97
|
|
|
58
|
-
|
|
59
|
-
|
|
98
|
+
.i-button--danger {
|
|
99
|
+
background: #f56c6c;
|
|
100
|
+
color: #fff;
|
|
101
|
+
}
|
|
102
|
+
.i-button--danger:hover {
|
|
103
|
+
background: #e05a5a;
|
|
104
|
+
color: #fff;
|
|
105
|
+
}
|
|
60
106
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
107
|
+
/* ===============================
|
|
108
|
+
大小
|
|
109
|
+
=============================== */
|
|
110
|
+
.i-button--small {
|
|
111
|
+
height: 1.4rem;
|
|
112
|
+
padding: 0 0.5rem;
|
|
113
|
+
font-size: 12px;
|
|
114
|
+
}
|
|
115
|
+
.i-button--medium {
|
|
116
|
+
height: 24px;
|
|
117
|
+
padding: 0 0.75rem;
|
|
118
|
+
font-size: 14px;
|
|
119
|
+
}
|
|
120
|
+
.i-button--large {
|
|
65
121
|
height: 32px;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
122
|
+
padding: 0 1rem;
|
|
123
|
+
font-size: 15px;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* ===============================
|
|
127
|
+
State
|
|
128
|
+
=============================== */
|
|
129
|
+
.i-button.is-disabled {
|
|
130
|
+
cursor: not-allowed;
|
|
131
|
+
opacity: 0.6;
|
|
69
132
|
}
|
|
70
|
-
.i-button.small { height: 24px; }
|
|
71
|
-
.i-button.medium { height: 32px; }
|
|
72
|
-
.i-button.large { height: 40px; }
|
|
73
|
-
.i-button.disabled { cursor: not-allowed; opacity: 0.6; }
|
|
74
|
-
.i-button.loading { opacity: 0.8; }
|
|
75
133
|
</style>
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// ImagePreview.ts
|
|
2
|
+
export class ImagePreview {
|
|
3
|
+
private container: HTMLDivElement
|
|
4
|
+
private img: HTMLImageElement
|
|
5
|
+
private prevBtn: HTMLButtonElement
|
|
6
|
+
private nextBtn: HTMLButtonElement
|
|
7
|
+
private closeBtn: HTMLButtonElement
|
|
8
|
+
private zoomInBtn: HTMLButtonElement
|
|
9
|
+
private zoomOutBtn: HTMLButtonElement
|
|
10
|
+
private resetBtn: HTMLButtonElement
|
|
11
|
+
private zoomLabel: HTMLDivElement
|
|
12
|
+
private indexLabel: HTMLDivElement
|
|
13
|
+
|
|
14
|
+
private images: string[]
|
|
15
|
+
private currentIndex: number = 0
|
|
16
|
+
private scale: number = 1
|
|
17
|
+
private position = { x: 0, y: 0 }
|
|
18
|
+
private isDragging = false
|
|
19
|
+
private dragStart = { x: 0, y: 0 }
|
|
20
|
+
private startPos = { x: 0, y: 0 }
|
|
21
|
+
private zoomTimeout: number | null = null
|
|
22
|
+
|
|
23
|
+
constructor(images: string[], initialIndex = 0) {
|
|
24
|
+
this.images = images
|
|
25
|
+
this.currentIndex = initialIndex
|
|
26
|
+
|
|
27
|
+
this.container = document.createElement('div')
|
|
28
|
+
this.container.className = 'ip-overlay'
|
|
29
|
+
this.container.style.cssText = `
|
|
30
|
+
position: fixed;
|
|
31
|
+
inset: 0;
|
|
32
|
+
background: rgba(0,0,0,0.8);
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
z-index: 9999;
|
|
37
|
+
`
|
|
38
|
+
this.container.addEventListener('click', e => {
|
|
39
|
+
if (e.target === this.container) this.close()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
this.img = document.createElement('img')
|
|
43
|
+
this.img.className = 'ip-image'
|
|
44
|
+
this.img.draggable = false
|
|
45
|
+
this.img.style.maxWidth = '100%'
|
|
46
|
+
this.img.style.maxHeight = '100%'
|
|
47
|
+
this.img.style.userSelect = 'none'
|
|
48
|
+
this.img.style.pointerEvents = 'none'
|
|
49
|
+
this.updateImage()
|
|
50
|
+
|
|
51
|
+
// 拖拽
|
|
52
|
+
this.img.addEventListener('mousedown', this.startDrag.bind(this))
|
|
53
|
+
document.addEventListener('mousemove', this.onDrag.bind(this))
|
|
54
|
+
document.addEventListener('mouseup', this.endDrag.bind(this))
|
|
55
|
+
// 缩放
|
|
56
|
+
this.img.addEventListener('wheel', this.handleWheel.bind(this))
|
|
57
|
+
|
|
58
|
+
// 按钮
|
|
59
|
+
this.prevBtn = this.createBtn('‹', { left: '16px', top: '50%', transform: 'translateY(-50%)' }, () => this.prev())
|
|
60
|
+
this.nextBtn = this.createBtn('›', { right: '16px', top: '50%', transform: 'translateY(-50%)' }, () => this.next())
|
|
61
|
+
this.closeBtn = this.createBtn('×', { right: '16px', top: '16px' }, () => this.close())
|
|
62
|
+
this.zoomInBtn = this.createBtn('+', { bottom: '20px', left: '50%', marginLeft: '40px' }, () => this.zoomIn())
|
|
63
|
+
this.zoomOutBtn = this.createBtn('-', { bottom: '20px', left: '50%', marginRight: '40px' }, () => this.zoomOut())
|
|
64
|
+
this.resetBtn = this.createBtn('0', { bottom: '20px', left: '50%' }, () => this.reset())
|
|
65
|
+
|
|
66
|
+
// 缩放百分比
|
|
67
|
+
this.zoomLabel = document.createElement('div')
|
|
68
|
+
this.zoomLabel.style.cssText = `
|
|
69
|
+
position: absolute;
|
|
70
|
+
top: 16px;
|
|
71
|
+
left: 50%;
|
|
72
|
+
transform: translateX(-50%);
|
|
73
|
+
color: #fff;
|
|
74
|
+
background: rgba(0,0,0,0.6);
|
|
75
|
+
padding: 4px 8px;
|
|
76
|
+
border-radius: 4px;
|
|
77
|
+
font-size: 14px;
|
|
78
|
+
display: none;
|
|
79
|
+
`
|
|
80
|
+
|
|
81
|
+
// 图片索引
|
|
82
|
+
this.indexLabel = document.createElement('div')
|
|
83
|
+
this.indexLabel.style.cssText = `
|
|
84
|
+
position: absolute;
|
|
85
|
+
bottom: 8px;
|
|
86
|
+
left: 50%;
|
|
87
|
+
transform: translateX(-50%);
|
|
88
|
+
color: #fff;
|
|
89
|
+
background: rgba(0,0,0,0.6);
|
|
90
|
+
padding: 2px 6px;
|
|
91
|
+
border-radius: 4px;
|
|
92
|
+
font-size: 14px;
|
|
93
|
+
`
|
|
94
|
+
|
|
95
|
+
this.container.appendChild(this.img)
|
|
96
|
+
this.container.appendChild(this.prevBtn)
|
|
97
|
+
this.container.appendChild(this.nextBtn)
|
|
98
|
+
this.container.appendChild(this.closeBtn)
|
|
99
|
+
this.container.appendChild(this.zoomInBtn)
|
|
100
|
+
this.container.appendChild(this.zoomOutBtn)
|
|
101
|
+
this.container.appendChild(this.resetBtn)
|
|
102
|
+
this.container.appendChild(this.zoomLabel)
|
|
103
|
+
this.container.appendChild(this.indexLabel)
|
|
104
|
+
|
|
105
|
+
document.body.appendChild(this.container)
|
|
106
|
+
|
|
107
|
+
// 键盘事件
|
|
108
|
+
document.addEventListener('keydown', this.handleKeydown.bind(this))
|
|
109
|
+
|
|
110
|
+
this.updateIndex()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private createBtn(text: string, style: Partial<CSSStyleDeclaration>, onClick: () => void) {
|
|
114
|
+
const btn = document.createElement('button')
|
|
115
|
+
btn.textContent = text
|
|
116
|
+
Object.assign(btn.style, {
|
|
117
|
+
position: 'absolute',
|
|
118
|
+
width: '36px',
|
|
119
|
+
height: '36px',
|
|
120
|
+
border: 'none',
|
|
121
|
+
borderRadius: '50%',
|
|
122
|
+
background: 'rgba(0,0,0,0.6)',
|
|
123
|
+
color: '#fff',
|
|
124
|
+
cursor: 'pointer',
|
|
125
|
+
fontSize: '18px',
|
|
126
|
+
...style
|
|
127
|
+
})
|
|
128
|
+
btn.addEventListener('click', onClick)
|
|
129
|
+
btn.addEventListener('mouseover', () => btn.style.background = 'rgba(0,0,0,0.8)')
|
|
130
|
+
btn.addEventListener('mouseout', () => btn.style.background = 'rgba(0,0,0,0.6)')
|
|
131
|
+
return btn
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private updateImage() {
|
|
135
|
+
this.img.src = this.images[this.currentIndex]
|
|
136
|
+
this.img.style.transform = `scale(${this.scale}) translate(${this.position.x}px, ${this.position.y}px)`
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private updateIndex() {
|
|
140
|
+
this.indexLabel.textContent = `${this.currentIndex + 1} / ${this.images.length}`
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private showZoomLabel() {
|
|
144
|
+
this.zoomLabel.textContent = `${Math.round(this.scale * 100)}%`
|
|
145
|
+
this.zoomLabel.style.display = 'block'
|
|
146
|
+
if (this.zoomTimeout) clearTimeout(this.zoomTimeout)
|
|
147
|
+
this.zoomTimeout = window.setTimeout(() => {
|
|
148
|
+
this.zoomLabel.style.display = 'none'
|
|
149
|
+
}, 800)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private startDrag(e: MouseEvent) {
|
|
153
|
+
this.isDragging = true
|
|
154
|
+
this.dragStart = { x: e.clientX, y: e.clientY }
|
|
155
|
+
this.startPos = { ...this.position }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private onDrag(e: MouseEvent) {
|
|
159
|
+
if (!this.isDragging) return
|
|
160
|
+
const dx = (e.clientX - this.dragStart.x) / this.scale
|
|
161
|
+
const dy = (e.clientY - this.dragStart.y) / this.scale
|
|
162
|
+
this.position.x = this.startPos.x + dx
|
|
163
|
+
this.position.y = this.startPos.y + dy
|
|
164
|
+
this.updateImage()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private endDrag() { this.isDragging = false }
|
|
168
|
+
|
|
169
|
+
private handleWheel(e: WheelEvent) {
|
|
170
|
+
if (e.deltaY < 0) this.zoomIn()
|
|
171
|
+
else this.zoomOut()
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
private zoomIn() { this.scale = Math.min(this.scale + 0.1, 3); this.updateImage(); this.showZoomLabel() }
|
|
175
|
+
private zoomOut() { this.scale = Math.max(this.scale - 0.1, 0.2); this.updateImage(); this.showZoomLabel() }
|
|
176
|
+
private reset() { this.scale = 1; this.position = { x: 0, y: 0 }; this.updateImage(); this.showZoomLabel() }
|
|
177
|
+
|
|
178
|
+
private prev() { if (this.currentIndex > 0) { this.currentIndex--; this.reset(); this.updateImage(); this.updateIndex() } }
|
|
179
|
+
private next() { if (this.currentIndex < this.images.length - 1) { this.currentIndex++; this.reset(); this.updateImage(); this.updateIndex() } }
|
|
180
|
+
public close() { this.container.style.display = 'none'; document.removeEventListener('keydown', this.handleKeydown.bind(this)) }
|
|
181
|
+
|
|
182
|
+
private handleKeydown(e: KeyboardEvent) {
|
|
183
|
+
switch(e.key) {
|
|
184
|
+
case 'Escape': this.close(); break
|
|
185
|
+
case 'ArrowLeft': this.prev(); break
|
|
186
|
+
case 'ArrowRight': this.next(); break
|
|
187
|
+
case '+': case '=': this.zoomIn(); break
|
|
188
|
+
case '-': this.zoomOut(); break
|
|
189
|
+
case '0': this.reset(); break
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
public open(index = 0) {
|
|
194
|
+
this.currentIndex = index
|
|
195
|
+
this.reset()
|
|
196
|
+
this.updateImage()
|
|
197
|
+
this.updateIndex()
|
|
198
|
+
this.container.style.display = 'flex'
|
|
199
|
+
}
|
|
200
|
+
}
|
package/src/packages/index.ts
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
// packages/index.ts
|
|
2
2
|
import type { App } from 'vue'
|
|
3
3
|
import IButton from './button/Button.vue'
|
|
4
|
+
import ISelect from './select/Select.vue'
|
|
5
|
+
import { ImagePreview } from './image-preview/ImagePreview'
|
|
6
|
+
|
|
7
|
+
const components = [IButton, ISelect]
|
|
4
8
|
|
|
5
9
|
const install = (app: App) => {
|
|
6
|
-
|
|
10
|
+
components.forEach(component => {
|
|
11
|
+
app.component(component.name!, component)
|
|
12
|
+
})
|
|
7
13
|
}
|
|
8
14
|
|
|
9
|
-
export {
|
|
10
|
-
|
|
15
|
+
export {
|
|
16
|
+
IButton,
|
|
17
|
+
ISelect,
|
|
18
|
+
ImagePreview
|
|
19
|
+
}
|
|
20
|
+
export default { install }
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<!-- ISelect.vue -->
|
|
2
|
+
<script setup lang="ts">
|
|
3
|
+
|
|
4
|
+
interface OptionItem {
|
|
5
|
+
label: string
|
|
6
|
+
value: string | number
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const props = defineProps<{
|
|
10
|
+
modelValue?: string | number
|
|
11
|
+
options: OptionItem[]
|
|
12
|
+
disabled?: boolean
|
|
13
|
+
}>()
|
|
14
|
+
|
|
15
|
+
const emit = defineEmits<{
|
|
16
|
+
(e: 'update:modelValue', value: string | number): void
|
|
17
|
+
}>()
|
|
18
|
+
|
|
19
|
+
function handleChange(e: Event) {
|
|
20
|
+
const target = e.target as HTMLSelectElement
|
|
21
|
+
emit('update:modelValue', target.value)
|
|
22
|
+
}
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<select :value="modelValue" @change="handleChange" :disabled="props.disabled">
|
|
27
|
+
<option v-for="opt in options" :key="opt.value" :value="opt.value">
|
|
28
|
+
{{ opt.label }}
|
|
29
|
+
</option>
|
|
30
|
+
</select>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<style scoped>
|
|
34
|
+
select {
|
|
35
|
+
/* padding: 4px 8px; */
|
|
36
|
+
/* border: 1px solid #ccc; */
|
|
37
|
+
/* border-radius: 4px; */
|
|
38
|
+
/* background: white; */
|
|
39
|
+
/* font-size: 14px; */
|
|
40
|
+
}
|
|
41
|
+
select:disabled {
|
|
42
|
+
/* background: #f5f5f5; */
|
|
43
|
+
/* cursor: not-allowed; */
|
|
44
|
+
}
|
|
45
|
+
</style>
|