-
Notifications
You must be signed in to change notification settings - Fork 27
/
index.ts
128 lines (120 loc) · 4.3 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import { App, DirectiveBinding, createVNode, render, ComponentPublicInstance, ObjectDirective } from 'vue';
import type { CustomMouseMenuOptions, TouchListenFn, PreventCheckFn, ContextMenuListenFn } from './types';
import MouseMenu from './mouse-menu.vue';
function createClassDom (tag: string, className: string, innerText?: string) {
let el = document.createElement(tag);
el.setAttribute('class', className);
if (innerText) el.innerText = innerText;
return el;
}
MouseMenu.install = (app: App): void => {
app.component(MouseMenu.name, MouseMenu);
};
function CustomMouseMenu (options: CustomMouseMenuOptions) {
const className = '__mouse__menu__container';
let container:HTMLElement;
if (document.querySelector(`.${className}`)) {
container = document.querySelector(`.${className}`) as HTMLElement;
} else {
container = createClassDom('div', className);
}
const vm = createVNode(MouseMenu, options);
render(vm, container);
document.body.appendChild(container);
return vm.component?.proxy as ComponentPublicInstance<typeof MouseMenu>;
}
let MouseMenuCtx: ComponentPublicInstance<typeof MouseMenu>;
let longPressTimer: number;
let longPressTouchStart: TouchListenFn;
let longPressTouchEnd: TouchListenFn;
function addLongPressListener (el: HTMLElement, fn: TouchListenFn, longPressDuration = 500, longPressPreventDefault?: PreventCheckFn | boolean) {
longPressTouchStart = (e: TouchEvent) => {
MouseMenuCtx && MouseMenuCtx.close();
if (typeof longPressPreventDefault === 'function') {
if (longPressPreventDefault(e, el)) {
e.preventDefault();
}
} else if (typeof longPressPreventDefault === 'boolean') {
if (longPressPreventDefault) {
e.preventDefault();
}
}
if (longPressTimer) clearTimeout(longPressTimer);
longPressTimer = window.setTimeout(() => {
fn(e);
}, longPressDuration);
};
longPressTouchEnd = () => {
clearTimeout(longPressTimer);
};
el.addEventListener('touchstart', longPressTouchStart);
el.addEventListener('touchmove', longPressTouchEnd);
el.addEventListener('touchend', longPressTouchEnd);
el.addEventListener('touchcancel', longPressTouchEnd);
}
function removeLongPressListener (el: HTMLElement) {
el.removeEventListener('touchstart', longPressTouchStart);
el.removeEventListener('touchmove', longPressTouchEnd);
el.removeEventListener('touchend', longPressTouchEnd);
el.removeEventListener('touchcancel', longPressTouchEnd);
}
// 指令封装
let contextMenuEvent: ContextMenuListenFn;
let longPressEvent: TouchListenFn;
const mounted = (el: HTMLElement, binding: DirectiveBinding) => {
const { value } = binding;
if (value.menuList.length > 0) {
contextMenuEvent = (e: MouseEvent) => {
if (typeof value.disabled === 'function' && value.disabled(value.params)) return;
e.preventDefault();
MouseMenuCtx = CustomMouseMenu({
el,
...value
});
const { x, y } = e;
MouseMenuCtx.show(x,y);
};
el.removeEventListener('contextmenu', contextMenuEvent);
el.addEventListener('contextmenu', contextMenuEvent);
if (value.useLongPressInMobile && 'ontouchstart' in window) {
longPressEvent = (e: TouchEvent) => {
if (typeof value.disabled === 'function' && value.disabled(value.params)) return;
MouseMenuCtx = CustomMouseMenu({
el,
...value
});
const { touches } = e;
const { clientX, clientY } = touches[0];
MouseMenuCtx.show(clientX, clientY);
document.onmousedown = null;
el.onmousedown = null;
setTimeout(() => {
document.onmousedown = () => MouseMenuCtx.close();
el.onmousedown = () => MouseMenuCtx.close();
}, 500);
};
removeLongPressListener(el);
addLongPressListener(
el,
longPressEvent,
value.longPressDuration || 500,
value.longPressPreventDefault
);
}
} else {
throw new Error('At least set one menu list!');
}
};
const unmounted = (el: HTMLElement) => {
el.removeEventListener('contextmenu', contextMenuEvent);
if ('touchstart' in window) {
removeLongPressListener(el);
}
};
const MouseMenuDirective: ObjectDirective = {
mounted,
unmounted
};
export * from './types';
export { MouseMenuDirective, CustomMouseMenu, MouseMenuCtx };
export default MouseMenu;