Turbolinks:load事件在Safari不触发、Chrome重复触发问题求助
turbolinks:load不触发,同时避免Chrome重复触发的问题 兄弟,我太懂这种跨浏览器兼容性的糟心事了!之前做项目也碰到过一模一样的Turbolinks和Safari的坑,当时手动dispatch之后Chrome那边重复触发事件,导致我的初始化代码跑了两遍,各种奇怪的bug找上门。
先唠唠为啥会出这问题:Turbolinks在Chrome这类浏览器里,初始页面加载时会正常触发turbolinks:load,但Safari因为事件循环的差异,偏偏会漏掉这个初始触发。你手动调用Turbolinks.dispatch("turbolinks:load")虽然救了Safari,但Chrome本来就会触发一次,叠加手动触发就变成两次执行,搞出一堆冗余逻辑。
千万别用浏览器判断来凑活! 这种方案太脆弱了,UA可以伪造,浏览器版本一更新你的判断逻辑就可能失效,后续维护起来心累。给你俩更靠谱的方案:
方案一:用状态标记确保事件只触发一次
我们可以给页面加个状态标记,判断turbolinks:load是否已经执行过,再决定要不要手动dispatch。代码示例如下:
// 先正常绑定你的业务逻辑 document.addEventListener('turbolinks:load', function() { // 这里放你的页面初始化代码 initPageElements(); }); // 处理Safari初始不触发的问题 function fixSafariTurbolinksLoad() { // 用全局变量做触发标记 if (!window.turbolinksLoadTriggered) { Turbolinks.dispatch('turbolinks:load'); window.turbolinksLoadTriggered = true; } } // 在DOM加载完成后执行检查 document.addEventListener('DOMContentLoaded', fixSafariTurbolinksLoad);
这个方案的核心是用window.turbolinksLoadTriggered记录事件触发状态,不管是Turbolinks自动触发还是我们手动dispatch,只要触发过就不会再执行第二次,完美抹平跨浏览器的差异。
方案二:检查Turbolinks内部状态(适配Turbolinks 5+)
如果你用的是Turbolinks 5及以上版本,可以直接检查Turbolinks的内部状态来判断是否需要手动触发:
document.addEventListener('DOMContentLoaded', function() { // 检查页面是否已完成Turbolinks加载 if (!Turbolinks.controller || !Turbolinks.controller.pageIsLoaded) { Turbolinks.dispatch('turbolinks:load'); } });
这个方案更贴合Turbolinks的内部机制,但要注意不同版本的Turbolinks可能内部属性名有变化,建议先在你的项目里测试下Turbolinks.controller.pageIsLoaded是否可用。
额外提醒:升级Turbolinks版本
如果你的Turbolinks版本比较旧,建议直接升级到最新稳定版——说不定官方早就修复了Safari下的触发bug,从根源上解决问题才是最优解。
内容的提问来源于stack exchange,提问作者lucasarruda

