Turbolinks 和自动播放 HTML5 视频
Turbolinks and autoplay HTML5 video
我刚开始一个 Rails 5 项目,在主页上我应该有一个视频横幅,静音,循环自动播放。我用的是Turbolinks 5,不知道能不能留着。
当我第一次加载主页时,一切正常。但是当我转到任何其他页面时,主页视频的声音开始播放。如果我回到家,声音会再次开始,覆盖之前开始的声音。
所以我有多个同时播放静音视频的声音实例。
一开始很有趣,5 秒后变成噩梦。
我看到这个问题:https://github.com/turbolinks/turbolinks/issues/177,它仍然开放,评论中没有实际解决方案。
显然这不是新问题,这个 post https://www.ruby-forum.com/topic/6803782 似乎在 2015 年谈到了同样的问题。这家伙谈到为 link 禁用 Turbolinks导致那个页面。我做不到,因为我的问题在主页上。
这是因为 Turbolinks 缓存了主页的副本 DOM。即使视频不可见,它仍然存在于缓存中,因此可以播放。 (但是,我不确定为什么它没有被静音——这 可能 是浏览器错误 :/)
我认为 Turbolinks 可以默认处理这个问题,但与此同时,这里有几个选项:
解决方案 1:在主页上禁用缓存
要防止 Turbolinks 缓存主页副本,您可以禁用该页面的缓存。例如,您可以在布局的 <head>
:
中包含以下内容
<% if @turbolinks_cache_control %>
<meta name="turbolinks-cache-control" content="<%= @turbolinks_cache_control %>">
<% end %>
然后在您的主页视图中:
<% @turbolinks_cache_control = 'no-cache' %>
缺点是当访问者重新访问主页时,您会错过性能优势。
解决方案 2:跟踪 autoplay
个元素
或者,您可以跟踪 autoplay
元素,在缓存页面之前删除 autoplay
属性,然后在呈现之前重新添加它。类似于 Persisting Elements Across Page Loads,此解决方案要求 autoplay
个元素具有唯一 ID。
在您的申请中包含以下内容 JavaScript:
;(function () {
var each = Array.prototype.forEach
var autoplayIds = []
document.addEventListener('turbolinks:before-cache', function () {
var autoplayElements = document.querySelectorAll('[autoplay]')
each.call(autoplayElements, function (element) {
if (!element.id) throw 'autoplay elements need an ID attribute'
autoplayIds.push(element.id)
element.removeAttribute('autoplay')
})
})
document.addEventListener('turbolinks:before-render', function (event) {
autoplayIds = autoplayIds.reduce(function (ids, id) {
var autoplay = event.data.newBody.querySelector('#' + id)
if (autoplay) autoplay.setAttribute('autoplay', true)
else ids.push(id)
return ids
}, [])
})
})()
此脚本在缓存页面之前获取所有 autoplay
元素,将每个 ID 存储在 autoplayIds
中,然后删除 autoplay
属性。当页面即将呈现时,它会遍历存储的 ID,并检查新主体是否包含具有匹配 ID 的元素。如果是,则重新添加 autoplay
属性,否则将 ID 推送到新的 autoplayIds
数组。这确保 autoplayIds
仅包含尚未重新呈现的 ID。
我刚开始一个 Rails 5 项目,在主页上我应该有一个视频横幅,静音,循环自动播放。我用的是Turbolinks 5,不知道能不能留着。
当我第一次加载主页时,一切正常。但是当我转到任何其他页面时,主页视频的声音开始播放。如果我回到家,声音会再次开始,覆盖之前开始的声音。
所以我有多个同时播放静音视频的声音实例。
一开始很有趣,5 秒后变成噩梦。
我看到这个问题:https://github.com/turbolinks/turbolinks/issues/177,它仍然开放,评论中没有实际解决方案。
显然这不是新问题,这个 post https://www.ruby-forum.com/topic/6803782 似乎在 2015 年谈到了同样的问题。这家伙谈到为 link 禁用 Turbolinks导致那个页面。我做不到,因为我的问题在主页上。
这是因为 Turbolinks 缓存了主页的副本 DOM。即使视频不可见,它仍然存在于缓存中,因此可以播放。 (但是,我不确定为什么它没有被静音——这 可能 是浏览器错误 :/)
我认为 Turbolinks 可以默认处理这个问题,但与此同时,这里有几个选项:
解决方案 1:在主页上禁用缓存
要防止 Turbolinks 缓存主页副本,您可以禁用该页面的缓存。例如,您可以在布局的 <head>
:
<% if @turbolinks_cache_control %>
<meta name="turbolinks-cache-control" content="<%= @turbolinks_cache_control %>">
<% end %>
然后在您的主页视图中:
<% @turbolinks_cache_control = 'no-cache' %>
缺点是当访问者重新访问主页时,您会错过性能优势。
解决方案 2:跟踪 autoplay
个元素
或者,您可以跟踪 autoplay
元素,在缓存页面之前删除 autoplay
属性,然后在呈现之前重新添加它。类似于 Persisting Elements Across Page Loads,此解决方案要求 autoplay
个元素具有唯一 ID。
在您的申请中包含以下内容 JavaScript:
;(function () {
var each = Array.prototype.forEach
var autoplayIds = []
document.addEventListener('turbolinks:before-cache', function () {
var autoplayElements = document.querySelectorAll('[autoplay]')
each.call(autoplayElements, function (element) {
if (!element.id) throw 'autoplay elements need an ID attribute'
autoplayIds.push(element.id)
element.removeAttribute('autoplay')
})
})
document.addEventListener('turbolinks:before-render', function (event) {
autoplayIds = autoplayIds.reduce(function (ids, id) {
var autoplay = event.data.newBody.querySelector('#' + id)
if (autoplay) autoplay.setAttribute('autoplay', true)
else ids.push(id)
return ids
}, [])
})
})()
此脚本在缓存页面之前获取所有 autoplay
元素,将每个 ID 存储在 autoplayIds
中,然后删除 autoplay
属性。当页面即将呈现时,它会遍历存储的 ID,并检查新主体是否包含具有匹配 ID 的元素。如果是,则重新添加 autoplay
属性,否则将 ID 推送到新的 autoplayIds
数组。这确保 autoplayIds
仅包含尚未重新呈现的 ID。