Closed LightQuanta closed 4 months ago
这个能获取到总的评论列表数据, 但如何将单独的评论元素和数据对应起来呢? (现在元素上还是不知道怎么取 id)
这个能获取到总的评论列表数据, 但如何将单独的评论元素和数据对应起来呢? (现在元素上还是不知道怎么取 id)
看了下,每一个.reply-item
下的.root-reply-container
里的.root-reply-avatar
元素上有属性data-root-reply-id
,里面的值能和评论属性上的rpid
和rpid_str
对上,用这个应该可以?
分别可以用document.querySelector(".comment").__vue_app__._context.provides.store._state.data.apiData.replyList.res.data.replies[*].rpid_str
和
document.querySelectorAll(".reply-item")[*].querySelector(".root-reply-avatar").dataset.rootReplyId
来获取
看了下,每一个.reply-item下的.root-reply-container里的.root-reply-avatar元素上有属性data-root-reply-id,里面的值能和评论属性上的rpid和rpid_str对上,用这个应该可以?
这个是一级评论的, 评论回复的头像上仍然是这个 ID
@the1812 目前个人大概摸索出了两种方法来映射DOM与数据:
在页面中执行该函数:
/**
* 将评论区 VNode 进行暴露
* @param {import('vue').VNode} vnode 评论区实例核心 VNode `window.commentContainer._vnode`
*/
function exposeVNode(vnode) {
if (
vnode.el &&
// el 存在并且没有被暴露
// 此处是为了防止所有暴露的 vnode 都被更改为模板树的 vnode
// 模板树 vnode 接受的 props 数量很少,而以组件实例接受的 props 会很完整
// 组件实例 vnode 永远比模板树 vnode 要先被暴露
// 目前 (2024.04.17) 其结构如下:
// /** 组件实例,component 属性不为 null */
// vnode: {
// el: dom1,
// children: null
// component: {
// ...,
// /** 模板树,children 属性不为 null */
// subTree: {
// ...,
// el: dom1,
// children: [vnode1, vnode2, ...],
// component: null
// }
// }
// }
!vnode.el._vnode
) {
vnode.el._vnode = vnode
}
// 该 vnode 为组件实例
if (vnode.component?.subTree) {
exposeVNode(vnode.component.subTree)
}
// 该 vnode 为模板树
else if (Array.isArray(vnode.children)) {
vnode.children.forEach(exposeVNode)
}
}
这个函数会将所有的vnode映射到真实DOM上面,假如该DOM是一个组件的根节点,那么他会获得这个组件的 props
随后就可以通过暴露的 vnode 与 store 内的评论数据进行匹配:
这种方案的优缺点如下:
使用 mixin
api,直接对每个组件进行注入
该方法已经在个人实现的评论区ip展示脚本进行实践:https://github.com/QingXia-Ela/unlock-bilibili-PcBrowser-comment/blob/main/index.js#L38
commentContainer.__vue_app__.mixin({
...hooks,
})
这种方案的优缺点如下:
mixin
会对所有的组件应用一遍,可能性能不佳,需要做测试按照第一种方法实现成功了 性能方面打开 15 条评论执行了 3842 次 exposeVNode, 目前只加了个遇到 reply item / sub reply item 提前停止递归, 性能我再研究下怎么优化
按照第一种方法实现成功了 性能方面打开 15 条评论执行了 3842 次 exposeVNode, 目前只加了个遇到 reply item / sub reply item 提前停止递归, 性能我再研究下怎么优化
可以试一下用类名限定范围,比如我先获取评论区dom元素类名,然后一层层往上查,一直查到根节点,这样就有了一个类名列表,后面再递归暴露vnode的时候只需要看看类名是否存在于类名列表里面就可以了,这样应该可以稍微优化一点性能?只是一个设想,还没有尝试。
测试后效果不佳,且评论是取决于实际展示组件数量,基本所有首屏展示的评论进行递归处理后递归次数都在3500次左右
捣鼓了一些优化的方法, 效果还可以
parentElement
向上告诉节点递归的范围 (往元素上写入一个 VNodeTargets
symbol)vnode.el[VNodeTargets]
的则不需要向下递归parentElement
递归不会经过这个节点, 需要将父元素的 VNodeTargets
复制给 Fragment 并继续向下递归vnode.el
, 需要将父元素的 VNodeTargets
flatMap 出子元素的 VNodeTargets
后复制到 vnode
上, 下一层的 children 直接从 vnode[VNodeTargets]
上读取测试了 22 条评论 (包含 10 条一级评论, 12 条回复), CPU 6x slowdown
优化前 | 优化后 | |
---|---|---|
递归次数 | 8459 | 93 |
总耗时 | 255.3ms | 46.9ms |
解除 CPU slowdown 后耗时 4.5ms
对应功能
comment-api.ts
问题描述
B站新版评论区疑似是更新了vue版本啥的,使用原先的getVueData无法再正确获取新版评论的相关数据,进而导致parseCommentItemV2失效
部分相关问题:
4646 #4643
经测试,现在可以使用
获取评论区相关的数据
脚本版本
v2.8.9-40-g29059634f
脚本管理器及版本
Tampermonkey v5.0.1
浏览器及版本
Firefox 123.0.1
播放器版本
4.8.8-740859de
播放策略
默认
错误信息
附加截图
致遇到了相同问题准备回复的人
太长不看: 1、遇到了相同的问题:请用左下角的 reaction 点赞 2、实时关注该 Issue 的后续进展:请用 Issue 页上的 Subscribe 功能(在 PC 端按钮通常位于页面右侧)。 请您回复前务必确认您有在本 Issue 之外补充了其它相关信息(比如 Log)再行回复以免对他人造成不必要的困扰
完整版
由于每个 Issue 甚至整个项目都是可以订阅通知的, 对于已经有人汇报过的 Bug, 如果您也遇到了并且没有其他信息要补充, 可以直接在左下点个赞表示 +1, 不要再去新增评论。想关注后续的可以用 Subscribe,Subscribe 之后该 Issue 如果有变动都可以收到通知,如果不想被回复打扰可以使用更加进阶的 Customize 功能,勾选 "Closed" & "Reopened"。Closed 通常代表该 Issue 已被解决,极少数情况下的 Reopened 代表该 Issue 的问题重新出现。如果您新增了无意义评论,因为 Issue 这个 bug tracker 与邮件列表类似,订阅某个 Issue 的用户会在每次这个 Issue 有新的动态时收到一封新的提醒邮件。也就是说,在 Issue 中的一个不能提供新的信息的评论,相当于给所有订阅这个 Issue 的用户发了一封垃圾邮件(spam)。尤其项目的维护者也是订阅者中的一员,太多垃圾邮件会对维护者带来很多不必要的困扰。发送垃圾邮件在开源社区通常是不那么受欢迎的行为。