You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Firefox中input type datetime-local不显示日期选择器问题求助

我懂你这个痛点——Firefox一直对原生datetime-local控件支持不太友好,直到近年的新版本才开始有限支持,旧版本直接就显示成普通文本框,确实头疼。试过Modernizr没解决也正常,因为它只是做兼容性检测,不会自动给你补全替代方案。下面给你几个实用的解决办法,按推荐程度排序:

方案1:用第三方日期时间选择器库(最省心)

原生控件兼容性拉胯,不如直接上成熟的第三方库,既能保证跨浏览器一致性,还能自定义样式。针对你的Angular项目,推荐两个选项:

选项A:Angular UI Bootstrap 组合控件

它的Datepicker和Timepicker可以组合成日期时间选择器,适配所有主流浏览器:

  1. 先引入Bootstrap和Angular UI Bootstrap的依赖到项目中
  2. 替换原生input为组合控件,同时在控制器里处理日期格式转换(因为datetime-local要求ISO 8601格式,比如2024-05-20T14:30

示例代码:

<div class="form-group" ng-class="{'has-error': vm.basicInfoForm.validFrom.$invalid && (vm.basicInfoForm.validFrom.$dirty || vm.basicInfoForm.$submitted)}">
  <label translate>.NEW.STARTDATE</label>
  <!-- 日期选择器 -->
  <p class="input-group">
    <input type="text" class="form-control" 
           uib-datepicker-popup="yyyy-MM-dd" 
           ng-model="vm.basicInfo.validFromDate" 
           is-open="vm.datePickerOpened" 
           datepicker-options="vm.dateOptions" 
           ng-required="true" 
           close-text="Close" />
    <span class="input-group-btn">
      <button type="button" class="btn btn-default" ng-click="vm.openDatePicker($event)">
        <i class="glyphicon glyphicon-calendar"></i>
      </button>
    </span>
  </p>
  <!-- 时间选择器 -->
  <p class="input-group mt-2">
    <input type="text" class="form-control" 
           uib-timepicker 
           ng-model="vm.basicInfo.validFromTime" 
           hour-step="1" 
           minute-step="15" 
           show-meridian="false" />
  </p>
  <span class="help-block error-block basic-block" translate>.NEW.CHECKDATE</span>
</div>

控制器里的逻辑:

vm.openDatePicker = function($event) {
  $event.preventDefault();
  $event.stopPropagation();
  vm.datePickerOpened = true;
};

vm.dateOptions = {
  formatYear: 'yy',
  startingDay: 1
};

// 监听日期和时间的变化,合并成符合要求的ISO格式字符串
$scope.$watchGroup(['vm.basicInfo.validFromDate', 'vm.basicInfo.validFromTime'], function(newValues) {
  const selectedDate = newValues[0];
  const selectedTime = newValues[1];
  if (selectedDate && selectedTime) {
    const year = selectedDate.getFullYear();
    const month = String(selectedDate.getMonth() + 1).padStart(2, '0');
    const day = String(selectedDate.getDate()).padStart(2, '0');
    const hours = String(selectedTime.getHours()).padStart(2, '0');
    const minutes = String(selectedTime.getMinutes()).padStart(2, '0');
    vm.basicInfo.validFrom = `${year}-${month}-${day}T${hours}:${minutes}`;
  }
});

选项B:Flatpickr(轻量无依赖)

这是个轻量级的选择器库,支持Angular指令,直接替换原生input就能用,自动处理格式和兼容性:

  1. 引入Flatpickr的CSS和JS文件
  2. 给input添加指令配置:
<div class="form-group" ng-class="{'has-error': vm.basicInfoForm.validFrom.$invalid && (vm.basicInfoForm.validFrom.$dirty || vm.basicInfoForm.$submitted)}">
  <label translate>.NEW.STARTDATE</label>
  <input type="text" class="form-control" 
         ng-model="vm.basicInfo.validFrom" 
         flatpickr="{ enableTime: true, dateFormat: 'Y-m-dTH:i' }" />
  <span class="help-block error-block basic-block" translate>.NEW.CHECKDATE</span>
</div>

它的输出格式和datetime-local要求的完全一致,不用额外做格式转换,非常省心。

方案2:检测浏览器支持并降级(不想用第三方库的话)

如果坚持想用原生控件,可以手动检测浏览器是否支持datetime-local,不支持就替换成分开的datetime控件,最后合并值:

  1. 先写个检测函数:
function supportsDatetimeLocal() {
  const testInput = document.createElement('input');
  testInput.type = 'datetime-local';
  // 检测类型是否保留,且支持valueAsDate属性
  return testInput.type === 'datetime-local' && typeof testInput.valueAsDate === 'object';
}
  1. 在视图里根据检测结果切换控件:
<div class="form-group" ng-class="{'has-error': vm.basicInfoForm.$invalid && (vm.basicInfoForm.$dirty || vm.basicInfoForm.$submitted)}">
  <label translate>.NEW.STARTDATE</label>
  <!-- 支持datetime-local的浏览器显示原生控件 -->
  <div ng-if="vm.supportsDatetimeLocal">
    <input type="datetime-local" name="validFrom" class="form-control" ng-model="vm.basicInfo.validFrom"/>
  </div>
  <!-- 不支持的浏览器显示分开的日期和时间控件 -->
  <div ng-if="!vm.supportsDatetimeLocal">
    <input type="date" name="validFromDate" class="form-control mb-2" ng-model="vm.basicInfo.validFromDate" ng-required="true"/>
    <input type="time" name="validFromTime" class="form-control" ng-model="vm.basicInfo.validFromTime" ng-required="true"/>
  </div>
  <span class="help-block error-block basic-block" translate>.NEW.CHECKDATE</span>
</div>
  1. 控制器里处理合并逻辑:
vm.supportsDatetimeLocal = supportsDatetimeLocal();

// 合并日期和时间到validFrom字段
$scope.$watchGroup(['vm.basicInfo.validFromDate', 'vm.basicInfo.validFromTime'], function(newValues) {
  if (!vm.supportsDatetimeLocal) {
    const date = newValues[0];
    const time = newValues[1];
    if (date && time) {
      vm.basicInfo.validFrom = `${date}T${time}`;
    }
  }
});

这样Chrome用户会看到原生的日期时间选择器,Firefox用户则看到分开的日期和时间选择器,都能正常输入并提交符合格式的值。


内容的提问来源于stack exchange,提问作者Nidhin Kumar

火山引擎 最新活动