Laravel 8中@push引入外部JS到@stack时Bootstrap折叠事件不生效问题
问题原因
- 依赖库加载顺序异常:引入的外部JS文件执行时,jQuery或Bootstrap JS还未加载完成。直接写在Blade模板内的脚本因为和
@stack('custom-scripts')输出位置一致,刚好在依赖库之后执行,所以可以正常绑定事件;外部JS如果加载时机早于jQuery、Bootstrap,要么会找不到$对象,要么Bootstrap的show.bs.collapse等自定义事件还未注册,自然无法触发。 - 静态资源缓存问题:修改
accordion-details.js后,浏览器依旧加载旧的缓存版本的JS文件,导致更新后的代码没有生效。 - 动态DOM绑定失效:如果页面的
.collapse元素是动态渲染生成的(比如AJAX加载、后端循环输出晚于JS执行),直接绑定事件到.collapse时对应元素还不存在,事件绑定直接失效,写在模板内的脚本可能因为执行时机刚好在DOM渲染完成后所以能绑定成功。
解决方案
- 调整依赖加载顺序,确保主模板中
@stack('custom-scripts')放在jQuery、Bootstrap JS引入之后,主模板结构参考:
<!-- 先引入jQuery --> <script src="{{ asset('js/jquery.min.js') }}"></script> <!-- 再引入Bootstrap JS --> <script src="{{ asset('js/bootstrap.min.js') }}"></script> <!-- 最后放自定义脚本栈 --> @stack('custom-scripts')
- 给静态资源添加版本号规避缓存,引入JS时追加查询参数,或者使用Laravel Mix自带的版本控制功能:
<script type="text/javascript" src="{{ URL::asset ('js/accordion-details.js?v=1.0') }}"></script>
- 把事件绑定改为事件委托形式,绑定到页面已存在的父级元素(比如document、.collapse的固定父容器),就算.collapse是动态生成的也能正常触发事件,修改
accordion-details.js代码如下:
$(document).ready(function(){ $(".collapse.show").each(function(){ $(this).prev(".card-header").find(".fa").addClass("fa-minus").removeClass("fa-plus"); }); // 改为事件委托绑定到document $(document).on('show.bs.collapse', '.collapse', function(){ console.log('open collapse'); $(this).prev(".card-header").find(".fa").removeClass("fa-plus").addClass("fa-minus"); }).on('hide.bs.collapse', '.collapse', function(){ console.log('hide collapse'); $(this).prev(".card-header").find(".fa").removeClass("fa-minus").addClass("fa-plus"); }); });
- 给外部JS标签添加
defer属性,保证JS在DOM解析完成后再执行,避免加载时机问题:
<script type="text/javascript" src="{{ URL::asset ('js/accordion-details.js') }}" defer></script>
内容的提问来源于stack exchange,提问作者Jordi Huertas
相关产品推荐
相关产品推荐

