本帖最后由 steven026 于 2022-8-14 23:10 编辑
【前言警告】
本脚本库作者完全没有接触过Vue2及Vue3正向开发,也不清楚其具体正向原理(脚本原理是倒推的)
本脚本库是作者根据自身JS经验及油猴中文网脚本开发指南加上断点逆向无意中发现的通用劫持方法而写,
局限于作者水平,可能存在诸多不合理之处,尽请谅解,另外欢迎交流、探讨。
【脚本原理】
根据Vue数据绑定机制,Vue为了保证数据同步,会对每个实例均创建一个app对象用于数据存储、监听、同步;
一旦该app对象中存储的变量发生变化,Vue便会监听到该变化并将其作用到相应的DOM元素中,以实现前端交互。
该app对象存在于闭包中,Vue2将其挂载在DOM元素中的__vue__
属性中,可令油猴脚本直接获取;
但Vue3并未提供该方法,这导致通常油猴脚本无法直接获取app对象,加大针对Vue3框架的油猴脚本的开发难度。
本脚本库根据Vue3的数据绑定原理,通过劫持Proxy方法以暴露Vue3 app对象,并将其还原挂载到DOM元素中,
进而使油猴脚本可直接访问、操作该app对象,以实现油猴脚本与Vue3的快速交互。
【使用方法】
全局变量
vueHooked
[object WeakMap] 以WeakMap存储已劫持的app对象,DOM元素为key,app对象为value
(同一个元素可能有多个app对象,以数组形式存储,下同)
vueUnhooked
[object WeakSet] 以WeakSet存储已获取到但未未劫持的app对象,作为debug用变量,正常情况WeakSet应为空
DOM元素属性
DOMelement.__vue__
[object Object] 已挂载到对应DOM元素属性的Vue app对象
(类似于Vue2的DOMelement.__vue__)
【使用示例】
必要元信息(脚本猫,注意版本号,示例可能会没有更新)
// @run-at document-start
// @require https://scriptcat.org/lib/567/1.0.3/Hook%20Vue3%20app.js
必要元信息(greasyfork)
// @run-at document-start
// @require https://greasyfork.org/scripts/449444-hook-vue3-app/code/Hook%20Vue3%20app.js
脚本示例(以Bilibili为例 下同)
// ==UserScript==
// @name Bilibile VUE3
// @run-at document-start
// @match https://www.bilibili.com/*
// @require https://scriptcat.org/lib/567/1.0.3/Hook%20Vue3%20app.js
// @grant none
// ==/UserScript==
//暴露变量到全局
window._vueUnhooked_ = vueUnhooked;
window._vueHooked_ = vueHooked;
//等待元素加载
let timer = setInterval(() => {
let app = document.querySelector(".bili-video-card")
if (app?.__vue__) {
clearInterval(timer)
console.log("已加载元素", app)
}
})
实际应用
遍历app
获取元信息
数据替换(仅演示可行性)
进阶应用:通过vue获取函数、内置方法 (自行研究,各页面均不相同)
【参考文献】
@李恒道 哥哥的指导与Vue2指南:
[油猴脚本开发指南]VUE数据绑定的响应原理
[油猴脚本开发指南]Vue初探vue
[油猴脚本开发指南]通过vue获取数据
@cxxjackie 哥哥的闭包劫持方法指导
油猴劫持闭包方法