You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 15:47:38