使用自定义逻辑将 HTMLVideoElement 上的 属性 覆盖为 getter/setter

Overwriting a property on a HTMLVideoElement to a getter/setter with custom logic

我想完成的事情:

我正在尝试为 chrome 编写一个扩展,为 Youtube 添加一些额外的功能。这个特殊问题与了解用户何时更改播放速率有关(这可以通过单击设置图标,然后单击速度来完成)。

我尝试过的事情:

我尝试通过将 HTMLVideoElement 上的 "playbackRate" 属性 替换为 getter/setter 对象来实现此目的,以便我可以检测何时发生这种情况。

问题:

当用户更改它时,我的所有逻辑都会运行,但是视频将不再真正改变速度。

代码:

    let videoObj = document.getElementsByTagName('video')[0];
    let storePlaybackRate = videoObj.playbackRate;
    Object.defineProperty(videoObj,'playbackRate',{
        get(){return storePlaybackRate;},
        set(val){
            storePlaybackRate = val;
            console.log("Updated Value: ",val);

            //Custom Logic that does work.

            return val;
        }
    });

要对此进行测试,只需将代码粘贴到任何 YouTube 视频的控制台中,然后更改播放速度。 console.log 发生了,但视频不再改变速度。

我已经检查过的东西

1.That 这个 属性 还不是我要覆盖的 getter/setter 对象。这是通过以下方式检查的:

Object.getOwnPropertyDescriptor(videoObj, 'playbackRate');

2.I 以为可能是因为我没有在 setter 中返回新值,但事实并非如此。

最终总结

我知道还有其他方法可以做我想做的事情,所以如果通过这种方法无法做到,那也没关系。但我真的很想了解为什么这行不通。或者如果我犯了一个错误。

谢谢。

您正在覆盖继承的 getter/setter。

HTMLVideoElement 没有自己的 getter/setter playbackRate,而是从 HTMLMediaElement.prototype 继承了一个。这就是为什么 Object.getOwnPropertyDescriptor(video,'playbackRate') returns undefined

要覆盖它,您必须存储原始描述符,并在您自己的描述符中调用它们。

originalDescriptor = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'playbackRate');

Object.defineProperty(HTMLVideoElement.prototype,'playbackRate',{
    set:function(value){
        originalDescriptor.set.call(this,value);
        console.log('value changed',value);
    },
    get:originalDescriptor.get
});

我在此示例中使用了视频原型,可以通过将 HTMLVideoElement.prototype 替换为视频元素的参考来调整特定元素的描述符。