Pikaday JS 如何在没有 moment js 的情况下使用完整的日期和月份名称作为输入格式

Pikaday JS How to use full day and month names for input format without moment js

我正在使用 Pikaday.js 是这样的:

new Pikaday({
            field: document.getElementById('top-banner-datepicker'),
            minDate: new Date()

我知道答案就在文档中的这个例子中:

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    format: 'D/M/YYYY',
    toString(date, format) {
        // you should do formatting based on the passed format,
        // but we will just return 'D/M/YYYY' for simplicity
        const day = date.getDate();
        const month = date.getMonth() + 1;
        const year = date.getFullYear();
        return `${day}/${month}/${year}`;
    },
    parse(dateString, format) {
        // dateString is the result of `toString` method
        const parts = dateString.split('/');
        const day = parseInt(parts[0], 10);
        const month = parseInt(parts[1], 10) - 1;
        const year = parseInt(parts[2], 10);
        return new Date(year, month, day);
    }
});

但我不知道如何使用完整的日期(星期一、星期二、星期三等)和完整的月份名称(一月、二月等)而不是缩写(星期一、星期二、星期三...一月、二月、三月...等)

我不想使用 Moment.JS,因为它是一个巨大的依赖项。

非常感谢任何帮助!

谢谢

如果您希望格式化日期选择器字段,您可以使用 toLocaleString()

例如,如果您想获得十月而不是十月:

date.toLocaleString('default', {
      month: 'long' // use localestring month to get the long month
});

如果您想获得星期日而不是星期日:

date.toLocaleString('default', { // use localestring weekday to get the long day
      weekday: 'long'
});

示例片段:

var picker = new Pikaday({
  field: document.getElementById('datepicker'),
  firstDay: 1,
  minDate: new Date(),
  maxDate: new Date(2020, 12, 31),
  yearRange: [2000, 2020],
  format: 'D-M-YYYY',
  toString(date, format) {
    console.log(date.toLocaleString('default', {
      weekday: 'short' // use localestring weekday to get the short abbv of day
    }));
    console.log(date.toLocaleString('default', {
      month: 'short' // use localestring weekday to get the short abbv of month
    }));
    // you should do formatting based on the passed format,
    // but we will just return 'D/M/YYYY' for simplicity
    const day = date.getDate();
    const daylong = date.toLocaleString('default', { // use localestring weekday to get the long day
      weekday: 'long'
    });
    const month = date.getMonth() + 1;
    const monthlong = date.toLocaleString('default', {
      month: 'long' // use localestring month to get the long month
    });
    const year = date.getFullYear();
    return `${daylong}, ${monthlong}, ${day} ${year}`; // just format as you wish
  }
});
#datepicker {
  width: 200px;
}
<link href="https://pikaday.com/css/pikaday.css" rel="stylesheet" />
<script src="https://pikaday.com/pikaday.js"></script>
<label for="datepicker">Date:</label>
<input type="text" id="datepicker">

Pikaday 解析

将日期设置为正确的格式通常很容易,但棘手的部分通常是从字符串中获取日期。 Pikaday Read Me:

中有这个警告

Be careful, though. If the formatted string that you return cannot be correctly parsed by the Date.parse method (or by moment if it is available), then you must provide your own parse function in the config. This function will be passed the formatted string and the format:

parse(dateString, format = 'YYYY-MM-DD')

使用 Date.parsecan yield irregular results。这是 moment.js 派上用场的地方,因为它可以处理多种格式。当一个人直接在输入字段或其他地方键入时使用解析函数。

两种方法可能涉及使用 moment.js 的轻量级替代方案或自定义格式化程序。

方法 1:轻量级替代方案

您可以搜索 moment.js 个备选方案。我发现 this repo that lists a few. For this example, I chose luxon, as it seems to be pretty small. You can see all the token it supports here: https://moment.github.io/luxon/docs/manual/parsing.html#table-of-tokens

为了帮助解析,我添加了这个位,它去掉了工作日解析,以防万一工作日与实际日期不匹配:

      if (format.startsWith('EEEE ')) {
        format = format.split(' ').slice(1).join(' ');
        dateString = dateString.split(' ').slice(1).join(' ');
      }

这是一个工作片段:

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    format: 'EEEE LLLL d, yyyy',
    toString(date, format) {
      return luxon.DateTime.fromJSDate(date).toFormat(format);
    },
    parse(dateString, format) {
      if (format.startsWith('EEEE ')) {
        format = format.split(' ').slice(1).join(' ');
        dateString = dateString.split(' ').slice(1).join(' ');
      }
      return luxon.DateTime.fromFormat(dateString, format).toJSDate();
    }
});
div {
  position: absolute;
  bottom: 0;
}
#datepicker {
  width: 250px;
}
<link href="https://pikaday.com/css/pikaday.css" rel="stylesheet" />
<script src="https://pikaday.com/pikaday.js"></script>
<script src="https://moment.github.io/luxon/global/luxon.min.js"></script>
<div><label for="datepicker">Date:</label>
<input type="text" id="datepicker">
</div>

方法 2:自定义格式化程序

对于这个答案,我将只使用您要求的格式,但解析各种格式会变得很棘手。

自定义名称

要获得几个月的自定义名称,您可以将它们硬编码在:

    var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
    var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];

或者,由于您需要普通名称,您可以使用 Intl.DateTimeFormat 以编程方式生成它们。如果您想让月份和工作日显示在用户的区域设置中,这也很有用:

    var monthFormatter = new Intl.DateTimeFormat([], { month: 'long' });
    var months = [... new Array(12)].map((d, i) => monthFormatter.format(new Date(2020, i, 1)));
    var dayFormatter = new Intl.DateTimeFormat([], { weekday: 'long' });
    var days = [... new Array(7)].map((d, i) =>dayFormatter.format(new Date(2020, 1, 2 + i)));

要访问名称,您只需使用相应的索引(记住它们是从零开始的)

    console.log(months[new Date().getMonth()]); // current month
    console.log(days[new Date().getDay()]); // current day

因此您的自定义格式函数看起来像这样:

    toString(date, format) {
        // you should do formatting based on the passed format,
        // but we will just return 'D/M/YYYY' for simplicity
        const day = date.getDate();
        const year = date.getFullYear();
        const weekday = date.getDay();
        const month = date.getMonth(); // remember, this is zero based!
        return `${days[weekday]} ${months[month]} ${day}, ${year}`;
    },

日期解析

这是为上述格式定制的解析函数Weekday Month Day, Year:

    parse(dateString, format) {
        // split the string into the parts separated by a space
        const parts = dateString.trim().split(' ');
        var day, month, year, startIndex;
        if (parts.length >= 3) {
          if (parts.length >= 4) {
            // if there's four parts, assume the first part is the weekday, which we don't need to use to convert it to a date
            startIndex = 1; // skip the weekday
          } else {
            // if there's only three parts, assume that the weekday was omitted
            startIndex = 0;
          }
          // look up the month from our prebuilt array. If it isn't found, it'll return -1, otherwise it will return the (zero based) numerical month.
          month = months.indexOf(parts[startIndex]);
          day = parts[startIndex + 1];
          // if there's a comma after the day, remove it
          if (day.endsWith(',')) {
             day = day.substring(0, day.length - 1);
          }
          day = +day; // convert the string into a number
          year = +parts[startIndex + 2]; // convert the string year into a number
        }
        if (parts.length < 3 // there is less than 3 parts
          || month === -1    // the month wasn't found
          || isNaN(day)      // the day isn't a number
          || isNaN(year)) {  // the year isn't a number
          return Date.parse(dateString); // fall back to default Date parsing
        }
        return new Date(year, month, day);
    }

总的来说,它看起来像这样:

var monthFormatter = new Intl.DateTimeFormat([], { month: 'long' });
var months = [... new Array(12)].map((d, i) => monthFormatter.format(new Date(2020, i, 1)))
var dayFormatter = new Intl.DateTimeFormat([], { weekday: 'long' });
var days = [... new Array(7)].map((d, i) =>dayFormatter.format(new Date(2020, 1, 2 + i)))

// Alternatively you can just hard code these:
// var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
// var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];


var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    format: 'D/M/YYYY',
    toString(date, format) {
        // you should do formatting based on the passed format,
        // but we will just return 'D/M/YYYY' for simplicity
        const day = date.getDate();
        const year = date.getFullYear();
        const weekday = date.getDay();
        const month = date.getMonth(); // remember, this is zero based!
        return `${days[weekday]} ${months[month]} ${day}, ${year}`;
    },
    parse(dateString, format) {
        // split the string into the parts separated by a space
        const parts = dateString.trim().split(' ');
        var day, month, year, startIndex;
        if (parts.length >= 3) {
          if (parts.length >= 4) {
            // if there's four parts, assume the first part is the weekday, which we don't need to use to convert it to a date
            startIndex = 1; // skip the weekday
          } else {
            // if there's only three parts, assume that the weekday was omitted
            startIndex = 0;
          }
          // look up the month from our prebuilt array. If it isn't found, it'll return -1, otherwise it will return the (zero based) numerical month.
          month = months.indexOf(parts[startIndex]);
          day = parts[startIndex + 1];
          // if there's a comma after the day, remove it
          if (day.endsWith(',')) {
             day = day.substring(0, day.length - 1);
          }
          day = +day; // convert the string into a number
          year = +parts[startIndex + 2]; // convert the string year into a number
        }
        if (parts.length < 3 // there is less than 3 parts
          || month === -1    // the month wasn't found
          || isNaN(day)      // the day isn't a number
          || isNaN(year)) {  // the year isn't a number
          return Date.parse(dateString); // fall back to default Date parsing
        }
        return new Date(year, month, day);
    }
});
div {
  position: absolute;
  bottom: 0;
}
#datepicker {
  width: 250px;
}
<link href="https://pikaday.com/css/pikaday.css" rel="stylesheet" />
<script src="https://pikaday.com/pikaday.js"></script>
<div><label for="datepicker">Date:</label>
<input type="text" id="datepicker">
</div>

不打算写一本书,因为这种默认格式可以用 Date 实现,特别是方法 toLocaleDateString(),其中 long 是 non-abbreviated weekday/month:

dateLocale: 'en-US',
dateOptions: {weekday: 'long', year: 'numeric', month: 'long', day: 'numeric'},
toString(date, format) {
    return date.toLocaleDateString(this.dateLocale, this.dateOptions);
},

即使格式化的可能性相当有限,
进步还是,支持multi-locale没问题