您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
通过劫持Proxy方法,逆向还原Vue3 app元素到DOM
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://updategreasyfork.deno.dev/scripts/449444/1081400/Hook%20Vue3%20app.js
// ==UserScript== // @name Hook Vue3 app // @version 1.0.3 // @description 通过劫持Proxy方法,逆向还原Vue3 app元素到DOM // @author DreamNya // @license MIT // @namespace https://gf.zukizuki.org/users/809466 // ==/UserScript== const $window = window.unsafeWindow || document.defaultView || window const realLog = $window.console.log; //反劫持console.log(大部分网站都会劫持console.log) const realProxy = $window.Proxy; //劫持Proxy var vueUnhooked = new WeakSet() //以WeakSet存储已获取到但未未劫持的app对象,作为debug用变量,正常情况WeakSet应为空 var vueHooked = new WeakMap() //以WeakMap存储已劫持的app对象,DOM元素为key,app对象为value $window.Proxy = function () { let app = arguments[0]._ if (app?.uid >= 0) { //判断app let el = app.vnode.el if (el) { recordVue(el, app) //记录到WeakMap recordDOM(el, app) //挂载到DOM watch_isUnmounted(app) //观察销毁 } else { //realLog(app,el) vueUnhooked.add(app) //记录未劫持的app //realLog(vueUnhooked,app) watchEl(app.vnode) //不存在el则观察el } } return new realProxy(...arguments) } function watchEl(vnode) { //观察el 变动时还原到DOM let value = vnode.el let hooked = false Object.defineProperty(vnode, "el", { get() { return value }, set(newValue) { value = newValue if (!hooked && this.el) { hooked = true recordVue(this.el, this.component) recordDOM(this.el, this.component) watch_isUnmounted(this.component) //realLog(this.component,"已还原") } } }) } function watch_isUnmounted(app) { //观察isUnmounted 变动时销毁引用 let value = app.isUnmounted let unhooked = false Object.defineProperty(app, "isUnmounted", { get() { return value }, set(newValue) { value = newValue if (!unhooked && this.isUnmounted) { unhooked = true //realLog(this,"已删除") let el = this.vnode.el if (el) { let DOMvalue = el.__vue__ //删除DOMelement.__vue__挂载 if (DOMvalue) { if (Array.isArray(DOMvalue)) { let index = DOMvalue.findIndex(i => i == this) index > -1 && DOMvalue.splice(index, 1) el.__vue__ = DOMvalue.length > 1 ? DOMvalue : DOMvalue[0] } else { if (DOMvalue == this) { el.__vue__ = void 0 } } } let WMvalue = vueHooked.get(el) //删除WeakMap存储 if (WMvalue) { if (Array.isArray(WMvalue)) { let index = WMvalue.findIndex(i => i == this) index > -1 && WMvalue.splice(index, 1) vueHooked.set(el, WMvalue.length > 1 ? WMvalue : WMvalue[0]) } else { if (WMvalue == this) { vueHooked.delete(el) } } } } } } }) } function recordVue(el, app) { //将app记录到WeakMap中 vueUnhooked.delete(app) if (vueHooked.has(el)) { let value = vueHooked.get(el) if (Array.isArray(value)) { if (value.findIndex(i => i == app) == -1) { vueHooked.set(el, vueHooked.get(el).push(app)) } } else { if (value != app) { vueHooked.set(el, [value, app]) } } } else { vueHooked.set(el, app) } } function recordDOM(el, app) { //将app挂载到DOMelement.__vue__ if (el.__vue__) { let value = el.__vue__ if (Array.isArray(value)) { if (value.findIndex(i => i == app) == -1) { el.__vue__ = value.push(app) } } else { if (value != app) { el.__vue__ = [value, app] } } } else { el.__vue__ = app } }