-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathhook-vue.js
122 lines (110 loc) · 4.29 KB
/
hook-vue.js
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
// ==UserScript==
// @name Hook Vue (Deprecated)
// @description (Deprecated, use `scriptio.vueMount` & `scriptio.vueUnmount` instead) Hook Vue, providing mount and unmount hooks for components
// @reactive false
// @version 0.1.1
// @homepageURL https://github.com/PRO-2684/Scriptio-user-scripts/#hook-vue
// @author PRO_2684
// @license gpl-3.0
// ==/UserScript==
// Adapted from https://github.com/Night-stars-1/LiteLoaderQQNT-Plugin-LLAPI/blob/main/src/renderer/vue.js
// Usage:
// 1. Load this script
// 2. Listen to "vue-hooked" event to know when Vue is hooked
// 3. Use window.__VUE_MOUNT__ and window.__VUE_UNMOUNT__ to listen to component mount and unmount
(function () {
if (window.__VUE_ELEMENTS__) {
if (!window.__VUE_MOUNT__ || !window.__VUE_UNMOUNT__) {
const tip = "[Scriptio] hook-vue.js: __VUE_ELEMENTS__ is already defined, but __VUE_MOUNT__ or __VUE_UNMOUNT__ is not defined. This is likely to be a conflict with another plugin, such as 轻量工具箱 or LLAPI.";
console.error(tip);
}
return;
}
const elements = new WeakMap();
window.__VUE_ELEMENTS__ = elements;
window.__VUE_MOUNT__ = []; // Functions to call when component found ((component) => {})
window.__VUE_UNMOUNT__ = []; // Functions to call when component unmounts ((component) => {})
function watchComponentUnmount(component) {
if (!component.bum) component.bum = [];
component.bum.push(() => {
const element = component.vnode.el;
if (element) {
const components = elements.get(element);
if (components?.length == 1) {
elements.delete(element);
} else {
components?.splice(components.indexOf(component));
}
if (element.__VUE__?.length == 1) {
element.__VUE__ = undefined;
} else {
element.__VUE__?.splice(element.__VUE__.indexOf(component));
}
}
// Call functions in __VUE_UNMOUNT__ when component unmounts
window.__VUE_UNMOUNT__.forEach(
(func) => {
try { func(component) } catch (e) {
console.error(e)
}
}
);
});
}
function watchComponentMount(component) {
let value;
Object.defineProperty(component.vnode, "el", {
get() {
return value;
},
set(newValue) {
value = newValue;
if (value) {
recordComponent(component);
}
},
});
}
function recordComponent(component) {
let element = component.vnode.el;
while (!(element instanceof HTMLElement)) {
element = element.parentElement;
}
// Expose component to element's __VUE__ property
if (element.__VUE__) element.__VUE__.push(component);
else element.__VUE__ = [component];
// Add class to element
element.classList.add("vue-component");
// Map element to components
const components = elements.get(element);
if (components) components.push(component);
else elements.set(element, [component]);
watchComponentUnmount(component);
// Call functions in __VUE_MOUNT__ when component found
window.__VUE_MOUNT__.forEach(
(func) => {
try { func(component) } catch (e) {
console.error(e)
}
}
);
}
function hookVue() {
window.Proxy = new Proxy(window.Proxy, {
construct(target, [proxyTarget, proxyHandler]) {
const component = proxyTarget?._;
if (component?.uid >= 0) {
const element = component.vnode.el;
if (element) {
recordComponent(component);
} else {
watchComponentMount(component);
}
}
return new target(proxyTarget, proxyHandler);
},
});
window.dispatchEvent(new CustomEvent("vue-hooked"));
}
hookVue();
})();