通过劫持Proxy方法,逆向还原Vue3 app元素到DOM
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/449444/1080975/Hook%20Vue3%20app.js
// ==UserScript==
// @name Hook Vue3 app
// @version 1.0.2
// @description 通过劫持Proxy方法,逆向还原Vue3 app元素到DOM
// @author DreamNya
// @license MIT
// @namespace https://greasyfork.org/users/809466
// ==/UserScript==
const $window = window.unsafeWindow || document.defaultView || window
const realLog = $window.console.log; //反劫持console.log
const realProxy = $window.Proxy; //劫持Proxy
var vueApp = {} //存储所有app
var vueHooked = {} //存储已还原app
$window.Proxy = function () {
let app = arguments[0]._
if (app && app.uid >= 0) { //判断app
let el = app.vnode.el
if (el) {
if (!el.__vue__) {
el.__vue__ = app //存在el则还原__vue__
if (el.__vue__) {
recordVue(vueHooked, app)
}
}
} else {
//realLog(app,el)
watchEl(app.vnode) //不存在el则进行观察
}
recordVue(vueApp, app)
}
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) {
this.el.__vue__ = this.component
if (this.el.__vue__) {
hooked = true
recordVue(vueHooked, this.component)
//realLog(this.component,"已还原")
}
}
}
})
}
function recordVue(obj, app) { //以uid为key存储app
if (!obj[app.uid]) { //uid不存在则直接存储
obj[app.uid] = app
} else if (Array.isArray(obj[app.uid])) {
obj[app.uid].push(app)
} else {
obj[app.uid] = [obj[app.uid], app] //多个root相同uid时以数组形式存储 可能存在优化空间
}
}