AngularJS中mwl-calendar自定义指令切换视图后数据不显示问题
解决AngularJS切换mwl-calendar视图后自定义月单元格宽度变量丢失的问题
看起来你遇到的核心问题是:切换回月视图时,新渲染的单元格元素不会触发window.load事件(页面早已加载完成),而resize事件只有窗口尺寸变化时才会执行,导致monthCalendarDayDivWidth没有被重新初始化,模板无法读取到有效值。下面给你几个针对性的解决方案:
1. 优化sizeElt指令,添加初始化计算逻辑
首先,我们需要让指令在元素渲染完成后立即计算宽度,而不是只依赖window.load和resize事件。同时要注意清理事件监听避免内存泄漏,用$timeout确保元素已完全渲染到DOM中:
tabs.directive('sizeElt', ['$window', '$timeout', function ($window, $timeout) { return { link: link, restrict: 'A' }; function link(scope, element, attrs) { // 封装复用的宽度计算函数 const calculateWidth = () => { scope.windowWidth = $window.innerWidth; scope.monthCalendarDayDivWidth = element[0].offsetWidth; // 手动触发digest(如果不在Angular上下文里) if(!scope.$$phase) scope.$apply(); }; // 元素渲染完成后立即计算宽度 $timeout(calculateWidth); // 监听窗口resize事件 angular.element($window).on('resize', calculateWidth); // 指令销毁时解绑事件,避免内存泄漏 scope.$on('$destroy', () => { angular.element($window).off('resize', calculateWidth); }); } }]);
2. 监听日历视图切换事件,主动触发宽度计算
mwl-calendar提供了视图切换的回调事件(on-view-change),我们可以利用它在切回月视图时主动触发宽度计算:
步骤1:在日历组件上绑定视图切换回调
<mwl-calendar <!-- 其他日历配置 --> on-view-change="handleCalendarViewChange(view)" ></mwl-calendar>
步骤2:在控制器中处理视图切换,广播重新计算事件
// 假设你用了controllerAs语法,这里的vm是控制器实例 vm.handleCalendarViewChange = (view) => { // 当切换回月视图时,广播事件通知所有sizeElt指令重新计算宽度 if(view.name === 'month') { $scope.$broadcast('recalculateMonthCellWidths'); } };
步骤3:在sizeElt指令中监听广播事件
在刚才的指令link函数里添加:
// 监听视图切换后的重新计算广播 scope.$on('recalculateMonthCellWidths', () => { $timeout(calculateWidth); });
3. 优化变量作用域,避免作用域继承问题
如果你的模板使用了controllerAs语法(比如vm),建议把monthCalendarDayDivWidth挂载到控制器实例上,而不是直接放在scope里,避免作用域继承导致的变量丢失:
修改模板:
<small style="position: absolute; bottom: 10px; left: 5px">{{vm.monthCalendarDayDivWidth}} <div style="display:inline-block;margin-bottom: 5px;" ng-repeat="(petitTitle, events) in day.groups track by petitTitle"> <span ng-if="events.length > 1 && vm.monthCalendarDayDivWidth > 130"> {{events[0].description}} </span> <span ng-if="events.length > 1 && vm.monthCalendarDayDivWidth <= 130"> {{littleTitle}} </span> </div> </small>
修改指令中的赋值:
const calculateWidth = () => { scope.windowWidth = $window.innerWidth; // 假设控制器实例在scope上的名称是vm scope.vm.monthCalendarDayDivWidth = element[0].offsetWidth; if(!scope.$$phase) scope.$apply(); };
或者更稳妥的方式是用双向绑定传递变量,避免作用域歧义:
tabs.directive('sizeElt', ['$window', '$timeout', function ($window, $timeout) { return { link: link, restrict: 'A', // 双向绑定父作用域的变量 scope: { elementWidth: '=' } }; function link(scope, element, attrs) { const calculateWidth = () => { scope.elementWidth = element[0].offsetWidth; }; $timeout(calculateWidth); angular.element($window).on('resize', calculateWidth); scope.$on('$destroy', () => angular.element($window).off('resize', calculateWidth)); } }]);
然后模板中使用:
<div size-elt element-width="vm.monthCalendarDayDivWidth" class="cal-month-day {{day.cssClass}}">
为什么之前的强制赋值没用?
你尝试的$scope.monthCalendarDayDivWidth = $scope.windowWidth > 1080 ? 140 : 110是硬编码值,不是实际元素的宽度,而且如果视图切换后创建了新的作用域,这个赋值可能没作用到新的月单元格所在的作用域里。
内容的提问来源于stack exchange,提问作者user10863293
相关产品推荐
相关产品推荐

