wujingjing
2024-04-22 f106e4dffb8279cb90726e83e7edd631f4c77699
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import type { App } from 'vue';
 
/**
 * 按钮波浪指令
 * @directive 默认方式:v-waves,如 `<div v-waves></div>`
 * @directive 参数方式:v-waves=" |light|red|orange|purple|green|teal",如 `<div v-waves="'light'"></div>`
 */
export function wavesDirective(app: App) {
    app.directive('waves', {
        mounted(el, binding) {
            el.classList.add('waves-effect');
            binding.value && el.classList.add(`waves-${binding.value}`);
            function setConvertStyle(obj: { [key: string]: unknown }) {
                let style: string = '';
                for (let i in obj) {
                    if (obj.hasOwnProperty(i)) style += `${i}:${obj[i]};`;
                }
                return style;
            }
            function onCurrentClick(e: { [key: string]: unknown }) {
                let elDiv = document.createElement('div');
                elDiv.classList.add('waves-ripple');
                el.appendChild(elDiv);
                let styles = {
                    left: `${e.layerX}px`,
                    top: `${e.layerY}px`,
                    opacity: 1,
                    transform: `scale(${(el.clientWidth / 100) * 10})`,
                    'transition-duration': `750ms`,
                    'transition-timing-function': `cubic-bezier(0.250, 0.460, 0.450, 0.940)`,
                };
                elDiv.setAttribute('style', setConvertStyle(styles));
                setTimeout(() => {
                    elDiv.setAttribute(
                        'style',
                        setConvertStyle({
                            opacity: 0,
                            transform: styles.transform,
                            left: styles.left,
                            top: styles.top,
                        })
                    );
                    setTimeout(() => {
                        elDiv && el.removeChild(elDiv);
                    }, 750);
                }, 450);
            }
            el.addEventListener('mousedown', onCurrentClick, false);
        },
        unmounted(el) {
            el.addEventListener('mousedown', () => {});
        },
    });
}
 
/**
 * 自定义拖动指令
 * @description  使用方式:v-drag="[dragDom,dragHeader]",如 `<div v-drag="['.drag-container .el-dialog', '.drag-container .el-dialog__header']"></div>`
 * @description dragDom 要拖动的元素,dragHeader 要拖动的 Header 位置
 * @link 注意:https://github.com/element-plus/element-plus/issues/522
 * @lick 参考:https://blog.csdn.net/weixin_46391323/article/details/105228020?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-10&spm=1001.2101.3001.4242
 */
export function dragDirective(app: App) {
    app.directive('drag', {
        mounted(el, binding) {
            if (!binding.value) return false;
 
            const dragDom = document.querySelector(binding.value[0]) as HTMLElement;
            const dragHeader = document.querySelector(binding.value[1]) as HTMLElement;
 
            dragHeader.onmouseover = () => (dragHeader.style.cursor = `move`);
 
            function down(e: any, type: string) {
                // 鼠标按下,计算当前元素距离可视区的距离
                const disX = type === 'pc' ? e.clientX - dragHeader.offsetLeft : e.touches[0].clientX - dragHeader.offsetLeft;
                const disY = type === 'pc' ? e.clientY - dragHeader.offsetTop : e.touches[0].clientY - dragHeader.offsetTop;
 
                // body当前宽度
                const screenWidth = document.body.clientWidth;
                // 可见区域高度(应为body高度,可某些环境下无法获取)
                const screenHeight = document.documentElement.clientHeight;
 
                // 对话框宽度
                const dragDomWidth = dragDom.offsetWidth;
                // 对话框高度
                const dragDomheight = dragDom.offsetHeight;
 
                const minDragDomLeft = dragDom.offsetLeft;
                const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;
 
                const minDragDomTop = dragDom.offsetTop;
                const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;
 
                // 获取到的值带px 正则匹配替换
                let styL: any = getComputedStyle(dragDom).left;
                let styT: any = getComputedStyle(dragDom).top;
 
                // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
                if (styL.includes('%')) {
                    styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100);
                    styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100);
                } else {
                    styL = +styL.replace(/\px/g, '');
                    styT = +styT.replace(/\px/g, '');
                }
 
                return {
                    disX,
                    disY,
                    minDragDomLeft,
                    maxDragDomLeft,
                    minDragDomTop,
                    maxDragDomTop,
                    styL,
                    styT,
                };
            }
 
            function move(e: any, type: string, obj: any) {
                let { disX, disY, minDragDomLeft, maxDragDomLeft, minDragDomTop, maxDragDomTop, styL, styT } = obj;
 
                // 通过事件委托,计算移动的距离
                let left = type === 'pc' ? e.clientX - disX : e.touches[0].clientX - disX;
                let top = type === 'pc' ? e.clientY - disY : e.touches[0].clientY - disY;
 
                // 边界处理
                if (-left > minDragDomLeft) {
                    left = -minDragDomLeft;
                } else if (left > maxDragDomLeft) {
                    left = maxDragDomLeft;
                }
 
                if (-top > minDragDomTop) {
                    top = -minDragDomTop;
                } else if (top > maxDragDomTop) {
                    top = maxDragDomTop;
                }
 
                // 移动当前元素
                dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
            }
 
            /**
             * pc端
             * onmousedown 鼠标按下触发事件
             * onmousemove 鼠标按下时持续触发事件
             * onmouseup 鼠标抬起触发事件
             */
            dragHeader.onmousedown = (e) => {
                const obj = down(e, 'pc');
                document.onmousemove = (e) => {
                    move(e, 'pc', obj);
                };
                document.onmouseup = () => {
                    document.onmousemove = null;
                    document.onmouseup = null;
                };
            };
 
            /**
             * 移动端
             * ontouchstart 当按下手指时,触发ontouchstart
             * ontouchmove 当移动手指时,触发ontouchmove
             * ontouchend 当移走手指时,触发ontouchend
             */
            dragHeader.ontouchstart = (e) => {
                const obj = down(e, 'app');
                document.ontouchmove = (e) => {
                    move(e, 'app', obj);
                };
                document.ontouchend = () => {
                    document.ontouchmove = null;
                    document.ontouchend = null;
                };
            };
        },
    });
}