我正在写一个用户脚本试图减少过大的音频元素。如何访问已创建但未放置在DOM中的音频元素?
在网站本身,它有类似于:
function () {
var audioElement = document.createElement('audio');
audioElement.setAttribute('src', 'http://www.example.com/sound.mp3');
callbackFn = function() {
audioElement.volume = way_too_high;
audioElement.load();
audioElement.play();
};
//...
}();
在我的用户名中,我想做类似的事情
function () {
newCallbackFunction = function() {
var audioElement = document.querySelector('audio'); // doesn't work, presumably because never added to DOM
audioElement.volume = 0.1 * audioElement.volume;
audioElement.load();
audioElement.play();
};
// ...
}();
但我似乎无法访问它。我真的不明白这些物体住在哪里。如果他们不在DOM中,他们怎么能玩?它们似乎只是存在于某个地方,因为它们可以播放,但对我来说如何找到它们并不明显。
因为callbackFn
是异步调用的,所以你可以在HTMLMediaElement.prototype
属性上改变volume
的setter,这样你对感兴趣的src
元素的音量变化将导致原始的setter被调用的音量为1/10默认情况下会调用它:
const { prototype } = HTMLMediaElement;
const { set: setter, get: getter } = Object.getOwnPropertyDescriptor(prototype, 'volume');
Object.defineProperty(prototype, 'volume', {
get() {
return getter.call(this);
},
set(arg) {
const newArg = this.src.endsWith('/sounds/warframe_alarm.mp3')
? arg / 10
: arg;
setter.call(this, newArg);
}
});
当然,请注意,当您无法更改页面的现有JS(例如使用用户脚本)时,这只是一种破解。
我正在寻找一种方法来访问网页中存在但尚未添加到DOM的音频元素
非常肯定做这样的事情的唯一方法是使用像使用document.createElement
运行的页面代码之前运行的代码覆盖createElement
这样的hack。
鉴于问题的代码和现代浏览器的autoplay
策略已经改变的事实,你可以在用户操作后找到DOM
中的哪个元素开始媒体播放,你可以删除并用一个设置volume
并调用原始函数的函数替换事件处理程序处理程序,例如
<!DOCTYPE html>
<html>
<head>
</head>
<body>
click
<script>
(function() {
var audioElement = document.createElement('audio');
audioElement.setAttribute('src', 'https://upload.wikimedia.org/wikipedia/commons/6/6e/Micronesia_National_Anthem.ogg');
callbackFn = function() {
audioElement.load();
audioElement.play();
};
document.onclick = callbackFn;
//...
function intercept(volume, audioElement) {
const fn = document.onclick;
document.onclick = null;
document.onmouseup = function() {
audioElement.volume = volume;
fn();
};
}
intercept(.2, audioElement)
})();
</script>
</body>
</html>
plinkr桶