提问人:Anna_B 提问时间:7/18/2023 最后编辑:journpyAnna_B 更新时间:8/7/2023 访问量:557
如何使 iframe 的行为与水平滚动区域中的其他媒体元素一样?
How can I make an iframe behave like other media elements in a horizontal scrolling area?
问:
这是我的代码:
$(document).ready(function() {
$('.scrollable-area').on('wheel', function(e) {
var scrollLeft = $(this).scrollLeft();
var width = $(this).get(0).scrollWidth - $(this).width();
var deltaY = e.originalEvent.deltaY;
var deltaX = e.originalEvent.deltaX;
var newScrollLeft = scrollLeft + deltaY + deltaX;
if ((deltaY > 0 && newScrollLeft < width) ||
(deltaY < 0 && newScrollLeft > 0)) {
e.preventDefault();
}
if (newScrollLeft <= 0) {
$(this).scrollLeft(0);
} else if (newScrollLeft >= width) {
$(this).scrollLeft(width);
} else {
$(this).scrollLeft(newScrollLeft);
}
});
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.gallery-container {
position: relative;
width: 100%;
height: 90vh;
background-color: yellow;
overflow: hidden;
}
.scrollable-area {
width: 100%;
height: 100%;
overflow-x: auto;
}
.gallery-items {
display: flex;
min-width: 100%;
height: 100%;
}
.gallery-item {
flex: 0 0 auto;
height: 100%;
display: flex;
}
.gallery-item img {
max-width: 100%;
height: auto;
object-fit: contain;
}
.gallery-item iframe {
background-color: blue;
width: auto;
width: 800px;
}
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<div class="gallery-container">
<div class="scrollable-area">
<div class="gallery-items">
<div class="gallery-item">
<img src="https://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast%2C_Dhaka%2C_Bangladesh.JPG">
</div>
<div class="gallery-item">
<img src="https://upload.wikimedia.org/wikipedia/commons/d/da/Sky_landscape.jpg">
</div>
<div class="gallery-item">
<iframe src="https://player.vimeo.com/video/584985260" frameborder="0" allow="fullscreen"></iframe>
</div>
<div class="gallery-item">
<img src="https://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast%2C_Dhaka%2C_Bangladesh.JPG">
</div>
</div>
</div>
</div>
如果将光标放在媒体库上并正常向下滚动,则首先将水平滚动浏览库。这是故意的。但是,当包含 iframe 时,它会停止。我已经尝试在滚动过程中防止指针事件,但它会导致其他一些问题,例如无法单击视频的播放按钮。
此外,找到一种方法来始终将 iframe 调整为视频的大小并适应水平画廊的整体高度会很酷。有谁知道这是怎么回事?
答:
0赞
Wakil Ahmed
7/23/2023
#1
修改 jQuery 代码以处理图像和 iframe 的滚动事件,还可以动态调整 iframe 的大小以适合其内容,并相应地调整水平库的高度。
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script>
$(document).ready(function() {
$('.scrollable-area').on('wheel', function(e) {
var scrollLeft = $(this).scrollLeft();
var width = $(this).get(0).scrollWidth - $(this).width();
var deltaY = e.originalEvent.deltaY;
var deltaX = e.originalEvent.deltaX;
var newScrollLeft = scrollLeft + deltaY + deltaX;
if ((deltaY > 0 && newScrollLeft < width) ||
(deltaY < 0 && newScrollLeft > 0)) {
e.preventDefault();
}
if (newScrollLeft <= 0) {
$(this).scrollLeft(0);
} else if (newScrollLeft >= width) {
$(this).scrollLeft(width);
} else {
$(this).scrollLeft(newScrollLeft);
}
});
// Resize iframes to fit their content
function resizeIframes() {
$('.gallery-item iframe').each(function() {
this.height = this.contentWindow.document.body.scrollHeight + 'px';
});
}
// Call the function on initial load and on window resize
resizeIframes();
$(window).resize(function() {
resizeIframes();
});
});
</script>
评论
0赞
Anna_B
7/23/2023
这是行不通的。如果光标位于 iframe 上方,则滚动将停止。
2赞
herrstrietzel
7/24/2023
#2
您可以向滚动 div 添加覆盖层,以禁用 iframe 指针事件,并在鼠标移动时重新启用指针事件。
根据 trincot 的回答“如何检测鼠标移动何时停止”
,我们可以使用自定义事件。mousestop
- 我们通过附加覆盖来禁用 iframe 指针事件。
- 我们根据鼠标移动切换/丢弃叠加层:
如果鼠标移动停止(使用 setTimeout 延迟),我们将添加/激活叠加层以阻止 iframe 内容中的指针事件 - 启用滚轮滚动事件 在滑块换行上移动时 - 我们可以访问 iframe/滑动按钮。 - iframe 尺寸只需通过 16/9 等方式设置
aspect-ratio
let galleryWrap = document.querySelector('.gallery-container');
(function(mouseStopDelay) {
var timeout;
document.addEventListener('mousemove', function(e) {
clearTimeout(timeout);
timeout = setTimeout(function() {
var event = new CustomEvent("mousestop", {
detail: {
clientX: e.clientX,
clientY: e.clientY
},
bubbles: true,
cancelable: true
});
e.target.dispatchEvent(event);
}, mouseStopDelay);
});
}(1000));
// Example use
galleryWrap.addEventListener('mousestop', function(e) {
galleryWrap.classList.add('inactive')
});
galleryWrap.addEventListener('mousemove', function(e) {
galleryWrap.classList.remove('inactive')
});
galleryWrap.addEventListener('click', function(e) {
galleryWrap.classList.remove('inactive')
});
$(document).ready(function() {
let galleryWrap = $('.gallery-container')
let scrollArea = $('.scrollable-area')
galleryWrap.on('wheel', function(e) {
scrolling = true;
var scrollLeft = scrollArea.scrollLeft();
var width = scrollArea.get(0).scrollWidth - scrollArea.width();
var deltaY = e.originalEvent.deltaY;
var deltaX = e.originalEvent.deltaX;
var newScrollLeft = scrollLeft + deltaY + deltaX;
if ((deltaY > 0 && newScrollLeft < width) ||
(deltaY < 0 && newScrollLeft > 0)) {
e.preventDefault();
}
if (newScrollLeft <= 0) {
scrollArea.scrollLeft(0);
} else if (newScrollLeft >= width) {
scrollArea.scrollLeft(width);
} else {
scrollArea.scrollLeft(newScrollLeft);
}
});
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.gallery-container {
position: relative;
width: 100%;
height: 250px;
background-color: yellow;
overflow: hidden;
}
.scrollable-area {
width: 100%;
height: 100%;
overflow-x: auto;
}
.gallery-items {
display: flex;
min-width: 100%;
height: 100%;
}
.gallery-item {
flex: 0 0 auto;
height: 100%;
display: flex;
}
.gallery-item img {
max-width: 100%;
height: auto;
object-fit: contain;
}
.gallery-item iframe {
width: 100%;
aspect-ratio: 16/9;
display: block;
}
.scrollable-area {
position: relative;
}
.gallery-container.inactive:after {
content: "";
position: absolute;
display: block;
left: 0;
top: 0;
right: 0;
width: 100%;
height: 100%;
background: red;
opacity: 0.1;
z-index: 100;
}
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<div class="gallery-container inactive">
<div class="scrollable-area">
<div class="gallery-items">
<div class="gallery-item">
<iframe frameborder="0" scrolling="no" srcdoc='<html><body style="margin:0; padding:0;"><video style="margin:0; padding:0; width:100%; aspect-ratio:16/9" controls muted playsinline controls preload="meta"><source src="https://cdn.jsdelivr.net/npm/[email protected]/video.mp4#t0" type="video/mp4"></video></html></body>'></iframe>
</div>
<div class="gallery-item">
<img src="https://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast%2C_Dhaka%2C_Bangladesh.JPG">
</div>
<div class="gallery-item">
<img src="https://upload.wikimedia.org/wikipedia/commons/d/da/Sky_landscape.jpg">
</div>
<div class="gallery-item">
<img src="https://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast%2C_Dhaka%2C_Bangladesh.JPG">
</div>
</div>
</div>
</div>
我添加了半透明的红色调来说明叠加切换。
评论
0赞
Anna_B
7/24/2023
有趣。这是有道理的。我仍然觉得它没有发挥应有的作用。如果我开始滚动,那么它不能直接与视频配合使用。但是在无缝滚动一段时间后,它就可以工作了。您知道如何改进它以使其始终直接工作吗?
0赞
Hugo Fang
8/1/2023
#3
我认为你可以用它来实现这一点。我知道这不是一个好办法。如果你能更新源网站,没问题。setTimeout
iframe
$(document).ready(function () {
$(".scrollable-area").on("wheel", function (e) {
var scrollLeft = $(this).scrollLeft()
var width = $(this).get(0).scrollWidth - $(this).width()
var deltaY = e.originalEvent.deltaY
var deltaX = e.originalEvent.deltaX
var newScrollLeft = scrollLeft + deltaY + deltaX
if (
(deltaY > 0 && newScrollLeft < width) ||
(deltaY < 0 && newScrollLeft > 0)
) {
e.preventDefault()
}
if (newScrollLeft <= 0) {
$(this).scrollLeft(0)
} else if (newScrollLeft >= width) {
$(this).scrollLeft(width)
} else {
$(this).scrollLeft(newScrollLeft)
}
})
let frameBack = document.querySelector(".background")
frameBack.addEventListener("mousemove", (e) => {
frameBack.classList.remove("z-1")
frameBack.classList.add("-z-1")
setTimeout(() => {
frameBack.classList.remove("-z-1")
frameBack.classList.add("z-1")
}, 100)
})
})
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.gallery-container {
position: relative;
width: 100%;
height: 90vh;
background-color: yellow;
overflow: hidden;
}
.scrollable-area {
width: 100%;
height: 100%;
overflow-x: auto;
}
.gallery-items {
display: flex;
min-width: 100%;
height: 100%;
}
.gallery-item {
flex: 0 0 auto;
height: 100%;
display: flex;
}
.gallery-item img {
max-width: 100%;
height: auto;
object-fit: contain;
}
.gallery-item iframe {
background-color: blue;
width: auto;
width: 800px;
}
.relative {
position: relative;
}
.background {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.z-1 {
z-index: 1;
}
.-z-1 {
z-index: -1;
}
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<div class="gallery-container inactive">
<div class="scrollable-area">
<div class="gallery-items">
<div class="gallery-item">
<img
src="https://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast%2C_Dhaka%2C_Bangladesh.JPG"
/>
</div>
<div class="gallery-item">
<img
src="https://upload.wikimedia.org/wikipedia/commons/d/da/Sky_landscape.jpg"
/>
</div>
<div class="gallery-item relative">
<iframe
src="https://player.vimeo.com/video/584985260"
frameborder="0"
allow="fullscreen"
></iframe>
<div class="background z-1"></div>
</div>
<div class="gallery-item">
<img
src="https://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast%2C_Dhaka%2C_Bangladesh.JPG"
/>
</div>
</div>
</div>
</div>
评论
0赞
Anna_B
8/3/2023
嗯,这个想法很有趣。但是使用视频的按钮效果不佳。
0赞
Hugo Fang
8/3/2023
我以为用户可以在单击视频中的按钮之前移动鼠标。如果用户移动鼠标,则可以单击按钮。但是移动鼠标 100 毫秒后,用户无法单击按钮,因为 iframe 上方有一个隐藏层。要删除隐藏层 100 毫秒,用户应移动鼠标。除非您更新 iframe 源网站,否则似乎没有好方法。
0赞
ChipChop Gizmo
8/7/2023
#4
我过去使用过一种令人费解的方法。它是将事件侦听器注入到 iFrame 中,然后返回到父页面。
我刚刚做了一个非常快速的测试,它有点适用于你的例子。
$(document).ready(function() {
....your code here.....
...and just add this...
//this will inject event listeners to any iframe in your page, you can do the selector any way you want, this is just an example
let iframes = document.getElementsByTagName('iframe')
for(let iframe of iframes){
iframe.contentWindow.addEventListener("wheel", function(e){
//IMPORTANT: you need to call a function outside this scope as this is actually being executed inside the iframe, not here. We are basically telling the iframe to fire a function "someFunction()" inside it's parent which is this window where we are.
window.parent.someFunction(e) //someFunction() is further below
})
}
});
// this needs to exists otherwise you will get a script error
function someFunction(e){
//and we should get the wheel event re-broadcast here, thank you mister iFrame :0)
console.log(e) // on my comp don't need to do anything with this, the gallery keeps scrolling on its own or you may need to just pass this event to your main scrolling code
}
现在,如果您在 iFrame 中加载的页面实现了严格的 CORS,这很可能不起作用(您的视频示例并不挑剔,似乎工作正常)
此外,如果 iFrame 背景暴露,它可能需要一些调整,它可能不会对滚轮做出反应,但这可以通过将另一个滚轮事件附加到 iframe 本身来解决。
希望这会有所帮助,如果没有,那就有点 iFrame 琐事了。
评论