如何为Angular uibmodal添加默认加载器直至内容加载完成
嘿,这个需求很实用——要让uibModal默认就带加载器,不用每个弹窗都重复写逻辑对吧?其实我们可以通过自定义默认模板+拦截resolve的方式来实现,全程不用改每个modal的调用代码,下面一步步来:
实现Angular UI Bootstrap Modal默认加载器的方案
1. 替换Modal默认模板
首先,我们得换掉uibModal自带的默认模板,让它天生就带加载器的结构。你可以在项目里新建一个模板文件,比如叫modal-default-template.html,内容写这样:
<div class="modal fade" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal-dialog {{sizeClass}}"> <div class="modal-content"> <!-- 加载器容器:内容未加载完成时显示 --> <div class="modal-loader" ng-if="!$ctrl.isContentLoaded"> <div class="spinner">正在加载...</div> <!-- 这里可以换成你项目里的加载动画组件 --> </div> <!-- 实际内容容器:加载完成后显示 --> <div ng-if="$ctrl.isContentLoaded"> <div class="modal-header" ng-include="headerTemplateUrl"></div> <div class="modal-body" ng-include="contentTemplateUrl"></div> <div class="modal-footer" ng-include="footerTemplateUrl"></div> </div> </div> </div> </div>
然后在Angular的配置阶段,用$uibModalProvider把这个模板设为全局默认:
angular.module('你的项目模块名') .config(['$uibModalProvider', function($uibModalProvider) { $uibModalProvider.options.templateUrl = 'path/to/modal-default-template.html'; }]);
2. 包装Modal服务,拦截加载状态
接下来要处理加载逻辑:在modal的resolve异步操作完成前,保持加载器显示;所有数据准备好后,切换到显示内容。我们可以包装原生的$uibModal服务,统一处理这个逻辑:
angular.module('你的项目模块名') .factory('customModalService', ['$uibModal', '$q', function($uibModal, $q) { return { open: function(options) { // 初始化resolve(如果没有的话) options.resolve = options.resolve || {}; // 新增一个内部resolve,用来等待所有用户自定义的resolve完成 options.resolve._loaderWatcher = ['$q', function($q) { // 把所有用户resolve转成Promise,等待全部完成 var resolvePromises = []; angular.forEach(options.resolve, function(resolveFn) { // 排除我们自己加的_loaderWatcher,避免循环 if (resolveFn !== options.resolve._loaderWatcher) { resolvePromises.push($q.when(resolveFn())); } }); return $q.all(resolvePromises); }]; // 打开modal,获取实例 var modalInstance = $uibModal.open(options); // 初始化加载状态 modalInstance.opened.then(function() { modalInstance.$ctrl.isContentLoaded = false; // 等待内部的_loaderWatcher完成,标记加载完成 modalInstance.resolve._loaderWatcher().then(function() { modalInstance.$ctrl.isContentLoaded = true; }).catch(function() { // 就算resolve失败(比如API报错),也要隐藏加载器 modalInstance.$ctrl.isContentLoaded = true; }); }); return modalInstance; } }; }]);
3. 给加载器加样式
为了让加载器在弹窗里居中显示,加一点基础CSS:
.modal-loader { display: flex; justify-content: center; align-items: center; min-height: 200px; } .spinner { font-size: 18px; color: #666; /* 这里可以替换成你项目里的CSS加载动画,比如旋转的圆圈 */ }
4. 日常使用方式
现在你只需要用customModalService.open()替代原生的$uibModal.open(),所有弹窗都会自动在数据加载前显示加载器:
customModalService.open({ templateUrl: '你的弹窗内容模板.html', controller: '你的弹窗控制器', resolve: { // 这里放你的异步数据请求,比如从API拿数据 modalData: ['yourApiService', function(yourApiService) { return yourApiService.fetchData(); }] } });
如果遇到特殊场景不需要加载器,你可以在open选项里加个skipLoader: true参数,然后在customModalService里判断是否跳过加载器逻辑。
小提示
- 如果弹窗是纯静态内容(不需要resolve数据),可以在open时直接传
isContentLoaded: true,避免加载器一闪而过。 - 加载器的HTML和样式可以直接换成你项目里统一的加载组件,保持视觉风格一致。
内容的提问来源于stack exchange,提问作者mohaidar
相关产品推荐
相关产品推荐

