Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

Background to the case

This project adopts the technology stack of VUe2. X + elementUi. At the end of the project development, due to some special reasons, all the date selector components need to be added to the lunar calendar, holidays, etc. The date component basically uses the El-Data-picker component. Due to various reasons such as the large project and the complex business of the component used, the el-Data-picker component can only be removed and rebuilt.

1. Pull the separate component out and run normally

  1. Will be innode_modules > element-ui > packagesUnder thedate-pickerMake a copy of the contents of the component folder into your own projectcomponentsDirectory;
  2. inmain.jsImport and drop folderscomponentsUnder folderdate-pickercomponent
// Import the modified element's datepicker
import DatePicker from './components/datePicker/index'
Vue.use(ElementUI)
Vue.use(DatePicker)
Copy the code
  1. At this timenpm run devThe project does not run properly and reports the following errorscrollbarThere was a problem with the build.

At this point you need to putdate-pickerThere are two entries under the folderscrollbarCode to comment out (ElementUi is introduced globally in this project)

4. When we restarted the project, we found that the project started normally anddate-pickercomponentLooks like it’s workingIn fact, there is an interaction problem >When we putdate-pickerComponents in thedialogWhen you pop up in the window component, you will notice that the date picker does not show up when it is opened twice.

At this point, I deeply suspected that it was because of this way of introductiondate-picker > picker.vueInside the source codeel-inputinfocusWhat’s wrong with getting focus when I play layer by layerdebuggerWhen looking for the root of the problem, keep looking for the picture below

At this point js logic code is not a problem, when I am puzzled, I suddenly want to see the corresponding pagedomRender the case at this timeThe corresponding DOM structure is found in the page

5. When the corresponding DOM structure is discovered, one dom is also foundelementthepopup-managerReset for this componentz-indexProperties, thez-indexNormally it increments, but here it’s possible that because I pulled the component out again, the component corresponds toz-indexAnd we start over. The simple solution is to give thedomSet a bigger onez-index.

2, Modify datePicker component, add lunar calendar and holidays

  1. It can be found by observationdatePickerComponent’s date pickerdatePicker > src > basic > date-table.vueFile, and we only need to put the corresponding lunar calendar and holiday display in{{ cell.text }}Just below the code.
  2. To get the corresponding lunar date, a method commonly used on the network is used here. The code is shown below (with adjustments to the getLunarFestival function of this code later) :
// date.js
/** * @1900-2100 range of Gregorian calendar, lunar calendar interchange *@charset UTF8 *@Author  Jea Yang (JJonline@JJonline.Cn)
 * @Time    The 2014-7-21 *@Time    2016-8-13 Fixed 2033HEX, Attribution Annals *@Time    2016-9-25 Fixed lunar LeapMonth Param Bug
 * @Time    2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
 * @Version Solar2lunar (1987,11,01); //[you can ignore params of prefix 0] * @calendar: calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0] */
export default {
  /** * Calendar 1900-2100 run size information table *@Array Of Property
   * @return Hex* /
  lunarInfo: [0x04bd8.0x04ae0.0x0a570.0x054d5.0x0d260.0x0d950.0x16554.0x056a0.0x09ad0.0x055d2.0x04ae0.0x0a5b6.0x0a4d0.0x0d250.0x1d255.0x0b540.0x0d6a0.0x0ada2.0x095b0.0x14977.0x04970.0x0a4b0.0x0b4b5.0x06a50.0x06d40.0x1ab54.0x02b60.0x09570.0x052f2.0x04970.0x06566.0x0d4a0.0x0ea50.0x16a95.0x05ad0.0x02b60.0x186e3.0x092e0.0x1c8d7.0x0c950.0x0d4a0.0x1d8a6.0x0b550.0x056a0.0x1a5b4.0x025d0.0x092d0.0x0d2b2.0x0a950.0x0b557.0x06ca0.0x0b550.0x15355.0x04da0.0x0a5b0.0x14573.0x052b0.0x0a9a8.0x0e950.0x06aa0.0x0aea6.0x0ab50.0x04b60.0x0aae4.0x0a570.0x05260.0x0f263.0x0d950.0x05b57.0x056a0.0x096d0.0x04dd5.0x04ad0.0x0a4d0.0x0d4d4.0x0d250.0x0d558.0x0b540.0x0b6a0.0x195a6.0x095b0.0x049b0.0x0a974.0x0a4b0.0x0b27a.0x06a50.0x06d40.0x0af46.0x0ab60.0x09570.0x04af5.0x04970.0x064b0.0x074a3.0x0ea50.0x06b58.0x05ac0.0x0ab60.0x096d5.0x092e0.0x0c960.0x0d954.0x0d4a0.0x0da50.0x07552.0x056a0.0x0abb7.0x025d0.0x092d0.0x0cab5.0x0a950.0x0b4a0.0x0baa4.0x0ad50.0x055d9.0x04ba0.0x0a5b0.0x15176.0x052b0.0x0a930.0x07954.0x06aa0.0x0ad50.0x05b52.0x04b60.0x0a6e6.0x0a4e0.0x0d260.0x0ea65.0x0d530.0x05aa0.0x076a3.0x096d0.0x04afb.0x04ad0.0x0a4d0.0x1d0b6.0x0d250.0x0d520.0x0dd45.0x0b5a0.0x056d0.0x055b2.0x049b0.0x0a577.0x0a4b0.0x0aa50.0x1b255.0x06d20.0x0ada0.0x14b63.0x09370.0x049f8.0x04970.0x064b0.0x168a6.0x0ea50.0x06b20.0x1a6c4.0x0aae0.0x092e0.0x0d2e3.0x0c960.0x0d557.0x0d4a0.0x0da50.0x05d55.0x056a0.0x0a6d0.0x055d4.0x052d0.0x0a9b8.0x0a950.0x0b4a0.0x0b6a6.0x0ad50.0x055a0.0x0aba4.0x0a5b0.0x052b0.0x0b273.0x06930.0x07337.0x06aa0.0x0ad50.0x14b55.0x04b60.0x0a570.0x054e4.0x0d160.0x0e968.0x0d520.0x0daa0.0x16aa6.0x056d0.0x04ae0.0x0a9d4.0x0a2d0.0x0d150.0x0f252.0x0d520,]./ / 2100

  /** * The days of each month in the Gregorian calendar *@Array Of Property
   * @return Number* /
  solarMonth: [31.28.31.30.31.30.31.31.30.31.30.31]./** ** ** ** ** ** ** **@Array Of Property trans [" a ", "b", "c", "ding", "e", "f", "age", "xin" and "I" and "j"] *@return Cn string
   */
  Gan: ['\u7532'.'\u4e59'.'\u4e19'.'\u4e01'.'\u620a'.'\u5df1'.'\u5e9a'.'\u8f9b'.'\u58ec'.'\u7678',]./** ** ** ** **@Array Of Property
   * @trans[" son ", "ugly", "Yin" and "frame", ""," the third ", "afternoon", "not", "shen", "unitary" and "xu-gou", "hai"] *@return Cn string
   */
  Zhi: ['\u5b50'.'\u4e11'.'\u5bc5'.'\u536f'.'\u8fb0'.'\u5df3'.'\u5348'.'\u672a'.'\u7533'.'\u9149'.'\u620c'.'\u4ea5',]./** ** The Chinese Zodiac *@Array Of Property
   * @trans[" mouse ", "cow", "tiger", "rabbit", "dragon", "snake", "horse", "sheep", "monkey", "chicken", "dog", "pig"] *@return Cn string
   */
  Animals: ['\u9f20'.'\u725b'.'\u864e'.'\u5154'.'\u9f99'.'\u86c7'.'\u9a6c'.'\u7f8a'.'\u7334'.'\u9e21'.'\u72d7'.'\u732a',]./** * Solar calendar */
  festival: {
    1-1 ' ': { title: New Year's Day },
    '2-14': { title: 'Valentine's Day' },
    '5-1': { title: Labor Day },
    '5-4': { title: Youth Day },
    '6-1': { title: Children's Day },
    '9-10': { title: Teachers' Day },
    10-1 ' ': { title: National Day },
    '12 to 25': { title: 'Christmas' },

    '3-8': { title: Women's Day },
    '3-12': { title: Arbor Day },
    4-1 ' ': { title: April Fool's Day },
    '5-12': { title: Nurse's Day },
    7 '1': { title: 'Party Founding Day' },
    '8-1': { title: Army Day },
    '12 to 24': { title: 'Silent Night'}},/** * Lunar Festival */
  lfestival: {
    '12-30': { title: 'New Year's eve },
    1-1 ' ': { title: 'New Year' },
    1-15 ' ': { title: Lantern Festival },
    '5-5': { title: Dragon Boat Festival },
    '8-15': { title: Mid-Autumn Festival },
    '9-9': { title: 'Double Ninth Festival' },
    7 '7': { title: 'festival'}},/** * Returns a solar calendar holiday defined by default */
  getFestival() {
    return this.festival
  },

  /** * returns the default definition of the contents of the holiday */
  getLunarFestival(y,m,d) {
    return this.lfestival
  },

  / * * * *@param {Object} Enter the data according to the format of festival, set the solar calendar festival */
  setFestival(param = {}) {
    this.festival = param
  },

  / * * * *@param {Object} Enter data in the format of LFestival to set lunar festival */
  setLunarFestival(param = {}) {
    this.lfestival = param
  },

  /** * 24 solar terms quick reference *@Array Of Property
   * @trans[" slight cold, "" it", "spring", "rain", the "insects awaken", "spring", "qingming festival", "gu yu", "summer", "grain full", "grain in ear", "the summer solstice", "slight heat", "great heat", "beginning of autumn", "the end of heat" and "millennium", "the autumnal equinox", "cold dew", "frost", "the beginning of winter," "light snow", "snow", "winter solstice" ] *@return Cn string
   */
  solarTerm: ['\u5c0f\u5bd2'.'\u5927\u5bd2'.'\u7acb\u6625'.'\u96e8\u6c34'.'\u60ca\u86f0'.'\u6625\u5206'.'\u6e05\u660e'.'\u8c37\u96e8'.'\u7acb\u590f'.'\u5c0f\u6ee1'.'\u8292\u79cd'.'\u590f\u81f3'.'\u5c0f\u6691'.'\u5927\u6691'.'\u7acb\u79cb'.'\u5904\u6691'.'\u767d\u9732'.'\u79cb\u5206'.'\u5bd2\u9732'.'\u971c\u964d'.'\u7acb\u51ac'.'\u5c0f\u96ea'.'\u5927\u96ea'.'\u51ac\u81f3',]./** * the 24 solar terms in 1900-2100 *@Array Of Property
   * @return 0x string For splice
   */
  sTermInfo: ['9778397bd097c36b0b6fc9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bcf97c3598082c95f8c965cc920f'.'97bd0b06bdb0722c965ce1cfcc920f'.'b027097bd097c36b0b6fc9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bcf97c359801ec95f8c965cc920f'.'97bd0b06bdb0722c965ce1cfcc920f'.'b027097bd097c36b0b6fc9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bcf97c359801ec95f8c965cc920f'.'97bd0b06bdb0722c965ce1cfcc920f'.'b027097bd097c36b0b6fc9274c91aa'.'9778397bd19801ec9210c965cc920e'.'97b6b97bd19801ec95f8c965cc920f'.'97bd09801d98082c95f8e1cfcc920f'.'97bd097bd097c36b0b6fc9210c8dc2'.'9778397bd197c36c9210c9274c91aa'.'97b6b97bd19801ec95f8c965cc920e'.'97bd09801d98082c95f8e1cfcc920f'.'97bd097bd097c36b0b6fc9210c8dc2'.'9778397bd097c36c9210c9274c91aa'.'97b6b97bd19801ec95f8c965cc920e'.'97bcf97c3598082c95f8e1cfcc920f'.'97bd097bd097c36b0b6fc9210c8dc2'.'9778397bd097c36c9210c9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bcf97c3598082c95f8c965cc920f'.'97bd097bd097c35b0b6fc920fb0722'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bcf97c3598082c95f8c965cc920f'.'97bd097bd097c35b0b6fc920fb0722'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bcf97c359801ec95f8c965cc920f'.'97bd097bd097c35b0b6fc920fb0722'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bcf97c359801ec95f8c965cc920f'.'97bd097bd097c35b0b6fc920fb0722'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bcf97c359801ec95f8c965cc920f'.'97bd097bd07f595b0b6fc920fb0722'.'9778397bd097c36b0b6fc9210c8dc2'.'9778397bd19801ec9210c9274c920e'.'97b6b97bd19801ec95f8c965cc920f'.'97bd07f5307f595b0b0bc920fb0722'.'7f0e397bd097c36b0b6fc9210c8dc2'.'9778397bd097c36c9210c9274c920e'.'97b6b97bd19801ec95f8c965cc920f'.'97bd07f5307f595b0b0bc920fb0722'.'7f0e397bd097c36b0b6fc9210c8dc2'.'9778397bd097c36c9210c9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bd07f1487f595b0b0bc920fb0722'.'7f0e397bd097c36b0b6fc9210c8dc2'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bcf7f1487f595b0b0bb0b6fb0722'.'7f0e397bd097c35b0b6fc920fb0722'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bcf7f1487f595b0b0bb0b6fb0722'.'7f0e397bd097c35b0b6fc920fb0722'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bcf7f1487f531b0b0bb0b6fb0722'.'7f0e397bd097c35b0b6fc920fb0722'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b97bd19801ec9210c965cc920e'.'97bcf7f1487f531b0b0bb0b6fb0722'.'7f0e397bd07f595b0b6fc920fb0722'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b97bd19801ec9210c9274c920e'.'97bcf7f0e47f531b0b0bb0b6fb0722'.'7f0e397bd07f595b0b0bc920fb0722'.'9778397bd097c36b0b6fc9210c91aa'.'97b6b97bd197c36c9210c9274c920e'.'97bcf7f0e47f531b0b0bb0b6fb0722'.'7f0e397bd07f595b0b0bc920fb0722'.'9778397bd097c36b0b6fc9210c8dc2'.'9778397bd097c36c9210c9274c920e'.'97b6b7f0e47f531b0723b0b6fb0722'.'7f0e37f5307f595b0b0bc920fb0722'.'7f0e397bd097c36b0b6fc9210c8dc2'.'9778397bd097c36b0b70c9274c91aa'.'97b6b7f0e47f531b0723b0b6fb0721'.'7f0e37f1487f595b0b0bb0b6fb0722'.'7f0e397bd097c35b0b6fc9210c8dc2'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b7f0e47f531b0723b0b6fb0721'.'7f0e27f1487f595b0b0bb0b6fb0722'.'7f0e397bd097c35b0b6fc920fb0722'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b7f0e47f531b0723b0b6fb0721'.'7f0e27f1487f531b0b0bb0b6fb0722'.'7f0e397bd097c35b0b6fc920fb0722'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b7f0e47f531b0723b0b6fb0721'.'7f0e27f1487f531b0b0bb0b6fb0722'.'7f0e397bd097c35b0b6fc920fb0722'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b7f0e47f531b0723b0b6fb0721'.'7f0e27f1487f531b0b0bb0b6fb0722'.'7f0e397bd07f595b0b0bc920fb0722'.'9778397bd097c36b0b6fc9274c91aa'.'97b6b7f0e47f531b0723b0787b0721'.'7f0e27f0e47f531b0b0bb0b6fb0722'.'7f0e397bd07f595b0b0bc920fb0722'.'9778397bd097c36b0b6fc9210c91aa'.'97b6b7f0e47f149b0723b0787b0721'.'7f0e27f0e47f531b0723b0b6fb0722'.'7f0e397bd07f595b0b0bc920fb0722'.'9778397bd097c36b0b6fc9210c8dc2'.'977837f0e37f149b0723b0787b0721'.'7f07e7f0e47f531b0723b0b6fb0722'.'7f0e37f5307f595b0b0bc920fb0722'.'7f0e397bd097c35b0b6fc9210c8dc2'.'977837f0e37f14998082b0787b0721'.'7f07e7f0e47f531b0723b0b6fb0721'.'7f0e37f1487f595b0b0bb0b6fb0722'.'7f0e397bd097c35b0b6fc9210c8dc2'.'977837f0e37f14998082b0787b06bd'.'7f07e7f0e47f531b0723b0b6fb0721'.'7f0e27f1487f531b0b0bb0b6fb0722'.'7f0e397bd097c35b0b6fc920fb0722'.'977837f0e37f14998082b0787b06bd'.'7f07e7f0e47f531b0723b0b6fb0721'.'7f0e27f1487f531b0b0bb0b6fb0722'.'7f0e397bd097c35b0b6fc920fb0722'.'977837f0e37f14998082b0787b06bd'.'7f07e7f0e47f531b0723b0b6fb0721'.'7f0e27f1487f531b0b0bb0b6fb0722'.'7f0e397bd07f595b0b0bc920fb0722'.'977837f0e37f14998082b0787b06bd'.'7f07e7f0e47f531b0723b0b6fb0721'.'7f0e27f1487f531b0b0bb0b6fb0722'.'7f0e397bd07f595b0b0bc920fb0722'.'977837f0e37f14998082b0787b06bd'.'7f07e7f0e47f149b0723b0787b0721'.'7f0e27f0e47f531b0b0bb0b6fb0722'.'7f0e397bd07f595b0b0bc920fb0722'.'977837f0e37f14998082b0723b06bd'.'7f07e7f0e37f149b0723b0787b0721'.'7f0e27f0e47f531b0723b0b6fb0722'.'7f0e397bd07f595b0b0bc920fb0722'.'977837f0e37f14898082b0723b02d5'.'7ec967f0e37f14998082b0787b0721'.'7f07e7f0e47f531b0723b0b6fb0722'.'7f0e37f1487f595b0b0bb0b6fb0722'.'7f0e37f0e37f14898082b0723b02d5'.'7ec967f0e37f14998082b0787b0721'.'7f07e7f0e47f531b0723b0b6fb0722'.'7f0e37f1487f531b0b0bb0b6fb0722'.'7f0e37f0e37f14898082b0723b02d5'.'7ec967f0e37f14998082b0787b06bd'.'7f07e7f0e47f531b0723b0b6fb0721'.'7f0e37f1487f531b0b0bb0b6fb0722'.'7f0e37f0e37f14898082b072297c35'.'7ec967f0e37f14998082b0787b06bd'.'7f07e7f0e47f531b0723b0b6fb0721'.'7f0e27f1487f531b0b0bb0b6fb0722'.'7f0e37f0e37f14898082b072297c35'.'7ec967f0e37f14998082b0787b06bd'.'7f07e7f0e47f531b0723b0b6fb0721'.'7f0e27f1487f531b0b0bb0b6fb0722'.'7f0e37f0e366aa89801eb072297c35'.'7ec967f0e37f14998082b0787b06bd'.'7f07e7f0e47f149b0723b0787b0721'.'7f0e27f1487f531b0b0bb0b6fb0722'.'7f0e37f0e366aa89801eb072297c35'.'7ec967f0e37f14998082b0723b06bd'.'7f07e7f0e47f149b0723b0787b0721'.'7f0e27f0e47f531b0723b0b6fb0722'.'7f0e37f0e366aa89801eb072297c35'.'7ec967f0e37f14998082b0723b06bd'.'7f07e7f0e37f14998083b0787b0721'.'7f0e27f0e47f531b0723b0b6fb0722'.'7f0e37f0e366aa89801eb072297c35'.'7ec967f0e37f14898082b0723b02d5'.'7f07e7f0e37f14998082b0787b0721'.'7f07e7f0e47f531b0723b0b6fb0722'.'7f0e36665b66aa89801e9808297c35'.'665f67f0e37f14898082b0723b02d5'.'7ec967f0e37f14998082b0787b0721'.'7f07e7f0e47f531b0723b0b6fb0722'.'7f0e36665b66a449801e9808297c35'.'665f67f0e37f14898082b0723b02d5'.'7ec967f0e37f14998082b0787b06bd'.'7f07e7f0e47f531b0723b0b6fb0721'.'7f0e36665b66a449801e9808297c35'.'665f67f0e37f14898082b072297c35'.'7ec967f0e37f14998082b0787b06bd'.'7f07e7f0e47f531b0723b0b6fb0721'.'7f0e26665b66a449801e9808297c35'.'665f67f0e37f1489801eb072297c35'.'7ec967f0e37f14998082b0787b06bd'.'7f07e7f0e47f531b0723b0b6fb0721'.'7f0e27f1487f531b0b0bb0b6fb0722',]./** **@Array Of Property
   * @trans [' day ',' one ',' two ',' three ',' four ',' five ',' six ',' seven ',' eight ',' nine ',' ten '] *@return Cn string
   */
  nStr1: ['\u65e5'.'\u4e00'.'\u4e8c'.'\u4e09'.'\u56db'.'\u4e94'.'\u516d'.'\u4e03'.'\u516b'.'\u4e5d'.'\u5341',]./** ** Date to lunar name list *@Array Of Property
   * @trans [' chu ',' ten ',' 20 ',' 30 '] *@return Cn string
   */
  nStr2: ['\u521d'.'\u5341'.'\u5eff'.'\u5345']./** ** month to lunar name list *@Array Of Property
   * @trans [' is', 'a', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'winter', 'la'] *@return Cn string
   */
  nStr3: ['\u6b63'.'\u4e8c'.'\u4e09'.'\u56db'.'\u4e94'.'\u516d'.'\u4e03'.'\u516b'.'\u4e5d'.'\u5341'.'\u51ac'.'\u814a',]./** * Returns the total number of days * in year Y of the lunar calendar@param lunar Year
   * @return Number
   * @eg:var count = calendar.lYearDays(1987) ; //count=387 */
  lYearDays: function(y) {
    var i,
      sum = 348
    for (i = 0x8000; i > 0x8; i >>= 1) {
      sum += this.lunarInfo[y - 1900] & i ? 1 : 0
    }
    return sum + this.leapDays(y)
  },

  /** * return lunar y year leap month which month; Returns 0 * if y has no leap month@param lunar Year
   * @return Number (0-12)
   * @eg:var leapMonth = calendar.leapMonth(1987) ; //leapMonth=6 */
  leapMonth: function(y) {
    // Leap code \ 4U 95f0
    return this.lunarInfo[y - 1900] & 0xf
  },

  /** * returns the number of leap months in y of the lunar calendar 0 * if there is no leap month in that year@param lunar Year
   * @return Number (0, 29, 30) *@eg:var leapMonthDay = calendar.leapDays(1987) ; //leapMonthDay=29 */
  leapDays: function(y) {
    if (this.leapMonth(y)) {
      return this.lunarInfo[y - 1900] & 0x10000 ? 30 : 29
    }
    return 0
  },

  /** * Returns the total number of days in m (non-leap month) in y year of the lunar calendar. Use the leapDays method * to calculate the number of days when M is a leap month@param lunar Year
   * @return Number (-1, 29, 30) *@egVar MonthDay = calendar. MonthDays (1987,9); //MonthDay=29 */
  monthDays: function(y, m) {
    if (m > 12 || m < 1) {
      return -1
    } // The month parameter ranges from 1 to 12
    return this.lunarInfo[y - 1900] & (0x10000 >> m) ? 30 : 29
  },

  /** * return to Gregorian calendar (!) Y Number of days in m months *@param solar Year
   * @return Number (-1, 28, 29, 30, 31) *@eg:var solarMonthDay = calendar.leapDays(1987) ; //solarMonthDay=30 */
  solarDays: function(y, m) {
    if (m > 12 || m < 1) {
      return -1
    } // Return -1 if the argument is incorrect
    var ms = m - 1
    if (ms == 1) {
      // The leap level rule in February will return 28 or 29 after confirmation
      return (y % 4= =0 && y % 100! =0) || y % 400= =0 ? 29 : 28
    } else {
      return this.solarMonth[ms]
    }
  },

  /** * The lunar year is converted to the ganzhi year *@param  LYear Number of years in a Lunar year *@return Cn string
   */
  toGanZhiYear: function(lYear) {
    var ganKey = (lYear - 3) % 10
    var zhiKey = (lYear - 3) % 12
    if (ganKey == 0) ganKey = 10 // If the remainder is 0, it is the last celestial trunk
    if (zhiKey == 0) zhiKey = 12 // If the remainder is 0, it is the last branch
    return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]},/** * Gregorian calendar month, day to determine the constellation *@param  cMonth [description]
   * @param  cDay [description]
   * @return Cn string
   */
  toAstro: function(cMonth, cDay) {
    var s =
      '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e 4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
    var arr = [20.19.21.21.21.22.23.23.23.23.22.22]
    return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1]?2 : 0), 2) + '\u5ea7' / / a
  },

  /** * The offset is passed to return the dry branch *@param Offset Indicates the offset with respect to the offset *@return Cn string
   */
  toGanZhi: function(offset) {
    return this.Gan[offset % 10] + this.Zhi[offset % 12]},/** * pass to Gregorian calendar (!) Year Y gets the date of the NTH solar term * in the Gregorian calendar@param Y Gregorian calendar year (1900-2100); N The solar terms of the 24 solar terms (1~24); N =1(minor cold) *@return day Number
   * @eg:var _24 = calendar.getterm (1987,3); / / _24 = 4; It means the beginning of spring on February 4, 1987
  getTerm: function(y, n) {
    if (y < 1900 || y > 2100) {
      return -1
    }
    if (n < 1 || n > 24) {
      return -1
    }
    var _table = this.sTermInfo[y - 1900]
    var _info = [
      parseInt('0x' + _table.substr(0.5)).toString(),
      parseInt('0x' + _table.substr(5.5)).toString(),
      parseInt('0x' + _table.substr(10.5)).toString(),
      parseInt('0x' + _table.substr(15.5)).toString(),
      parseInt('0x' + _table.substr(20.5)).toString(),
      parseInt('0x' + _table.substr(25.5)).toString(),
    ]
    var _calday = [
      _info[0].substr(0.1),
      _info[0].substr(1.2),
      _info[0].substr(3.1),
      _info[0].substr(4.2),

      _info[1].substr(0.1),
      _info[1].substr(1.2),
      _info[1].substr(3.1),
      _info[1].substr(4.2),

      _info[2].substr(0.1),
      _info[2].substr(1.2),
      _info[2].substr(3.1),
      _info[2].substr(4.2),

      _info[3].substr(0.1),
      _info[3].substr(1.2),
      _info[3].substr(3.1),
      _info[3].substr(4.2),

      _info[4].substr(0.1),
      _info[4].substr(1.2),
      _info[4].substr(3.1),
      _info[4].substr(4.2),

      _info[5].substr(0.1),
      _info[5].substr(1.2),
      _info[5].substr(3.1),
      _info[5].substr(4.2),]return parseInt(_calday[n - 1])},/** * returns the Chinese colloquial representation of the month passed into the lunar calendar@param lunar month
   * @return Cn string
   * @eg:var cnMonth = calendar.toChinaMonth(12) ; //cnMonth=' 12 '*/
  toChinaMonth: function(m) {
    = > \ u6708 / / month
    if (m > 12 || m < 1) {
      return -1
    } // Return -1 if the argument is incorrect
    var s = this.nStr3[m - 1]
    s += '\u6708' // Add the month
    return s
  },

  /** * incoming lunar date number returns Chinese character representation *@param lunar day
   * @return Cn string
   * @eg:var cnDay = calendar.toChinaDay(21) ; //cnMonth=' 21 '*/
  toChinaDay: function(d) {
    / / day = > \ u65e5
    var s
    switch (d) {
      case 10:
        s = '\u521d\u5341'
        break
      case 20:
        s = '\u4e8c\u5341'
        break
        break
      case 30:
        s = '\u4e09\u5341'
        break
        break
      default:
        s = this.nStr2[Math.floor(d / 10)]
        s += this.nStr1[d % 10]}return s
  },

  /** * The year can be roughly converted => The exact demarcation line is "Start of Spring" *@param y year
   * @return Cn string
   * @eg:var animal = calendar.getAnimal(1987) ; / / animal = 'rabbit' * /
  getAnimal: function(y) {
    return this.Animals[(y - 4) % 12]},/** ** <=>JSON *@param y  solar year
   * @param m  solar month
   * @param d  solar day
   * @return JSON object
   * @eg: the console log (calendar. Solar2lunar,11,01 (1987)); * /
  solar2lunar: function(y, m, d) {
    let {workday, holiday} = this.initHoliday()
    // The parameter ranges from 1900.1.31 to 2100.12.31
    y = parseInt(y)
    m = parseInt(m)
    d = parseInt(d)
    // Year limit
    if (y < 1900 || y > 2100) {
      return -1 // undefined is converted to a number to NaN
    }
    // The maximum number of parameters in the Gregorian calendar
    if (y == 1900 && m == 1 && d < 31) {
      return -1
    }
    // Did not transfer the date
    if(! y) {var objDate = new Date()}else {
      var objDate = new Date(y, parseInt(m) - 1, d)
    }
    var i,
      leap = 0,
      temp = 0
    // Modify ymD parameters
    var y = objDate.getFullYear(),
      m = objDate.getMonth() + 1,
      d = objDate.getDate()
    var offset =
      (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) -
        Date.UTC(1900.0.31)) /
      86400000
    for (i = 1900; i < 2101 && offset > 0; i++) {
      temp = this.lYearDays(i)
      offset -= temp
    }
    if (offset < 0) {
      offset += temp
      i--
    }

    // Is it today
    var isTodayObj = new Date(),
      isToday = false
    if (
      isTodayObj.getFullYear() == y &&
      isTodayObj.getMonth() + 1 == m &&
      isTodayObj.getDate() == d
    ) {
      isToday = true
    }
    / / week
    var nWeek = objDate.getDay(),
      cWeek = this.nStr1[nWeek]
    // The number indicates the day of the week, following China's custom of starting on Monday
    if (nWeek == 0) {
      nWeek = 7
    }
    / / the lunar New Year
    var year = i
    var leap = this.leapMonth(i) // Leap which month
    var isLeap = false

    // Leap month
    for (i = 1; i < 13 && offset > 0; i++) {
      / / leap month
      if (leap > 0 && i == leap + 1 && isLeap == false) {
        --i
        isLeap = true
        temp = this.leapDays(year) // Calculate the number of leap months in lunar calendar
      } else {
        temp = this.monthDays(year, i) // Calculate the number of days in a common lunar month
      }
      // Remove leap months
      if (isLeap == true && i == leap + 1) {
        isLeap = false
      }
      offset -= temp
    }
    // Leap months cause array subscripts to overlap inversely
    if (offset == 0 && leap > 0 && i == leap + 1) {
      if (isLeap) {
        isLeap = false
      } else {
        isLeap = true
        --i
      }
    }
    if (offset < 0) {
      offset += temp
      --i
    }
    / / the lunar month
    var month = i
    / / the lunar day
    var day = offset + 1
    //
    var sm = m - 1
    var gzY = this.toGanZhiYear(year)

    // The two solar terms of the month
    // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
    var firstNode = this.getTerm(y, m * 2 - 1) // Returns the start date of the month
    var secondNode = this.getTerm(y, m * 2) // Returns the start date of the month

    // Correct dry branch moon according to 12 solar terms
    var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
    if (d >= firstNode) {
      gzM = this.toGanZhi((y - 1900) * 12 + m + 12)}// The solar term of the incoming date
    var isTerm = false
    var Term = null
    if (firstNode == d) {
      isTerm = true
      Term = this.solarTerm[m * 2 - 2]}if (secondNode == d) {
      isTerm = true
      Term = this.solarTerm[m * 2 - 1]}// The difference between the day of the month and 1900/1/1
    var dayCyclical = Date.UTC(y, sm, 1.0.0.0.0) / 86400000 + 25567 + 10
    var gzD = this.toGanZhi(dayCyclical + d - 1)
    // The constellation to which the date belongs
    var astro = this.toAstro(m, d)

    var solarDate = y + The '-' + (m + ' ').padStart(2.0) + The '-' + (d + ' ').padStart(2.0)
    var lunarDate = year + The '-' + month + The '-' + day

    var festival = this.festival
    var lfestival = this.getLunarFestival(year, month, day)

    var festivalDate = m + The '-' + d
    var lunarFestivalDate = month + The '-' + day

    return {
      isWork: workday.includes(solarDate),
      isHoliday: holiday.includes(solarDate),
      date: solarDate,
      lunarDate: lunarDate,
      festival: festival[festivalDate] ? festival[festivalDate].title : null.lunarFestival: lfestival[lunarFestivalDate]
        ? lfestival[lunarFestivalDate].title
        : null.lYear: year,
      lMonth: month,
      lDay: day,
      Animal: this.getAnimal(year),
      IMonthCn: (isLeap ? '\u95f0' : ' ') + this.toChinaMonth(month),
      IDayCn: this.toChinaDay(day),
      cYear: y,
      cMonth: m,
      cDay: d,
      gzYear: gzY,
      gzMonth: gzM,
      gzDay: gzD,
      isToday: isToday,
      isLeap: isLeap,
      nWeek: nWeek,
      ncWeek: '\u661f\u671f' + cWeek,
      isTerm: isTerm,
      Term: Term,
      astro: astro,
    }
  },

  /** * Get detailed Gregorian calendar, lunar object information <=>JSON *@param y  lunar year
   * @param m  lunar month
   * @param d  lunar day
   * @param IsLeapMonth Lunar month is leap or not@return JSON object
   * @eg: the console log (calendar. Lunar2solar,9,10 (1987)); * /
  lunar2solar: function(y, m, d, isLeapMonth) {
    // The parameter ranges from 1900.1.31 to 2100.12.1
    y = parseInt(y)
    m = parseInt(m)
    d = parseInt(d)
    varisLeapMonth = !! isLeapMonthvar leapOffset = 0
    var leapMonth = this.leapMonth(y)
    var leapDay = this.leapDays(y)
    if(isLeapMonth && leapMonth ! = m) {return -1
    } // The leap month in the calendar year is not the same as the month in which the leap month is passed
    if ((y == 2100 && m == 12 && d > 1) || (y == 1900 && m == 1 && d < 31)) {
      return -1
    } // The maximum value is exceeded
    var day = this.monthDays(y, m)
    var _day = day
    //bugFix 2016-9-25
    //if month is leap, _day use leapDays method
    if (isLeapMonth) {
      _day = this.leapDays(y, m)
    }
    if (y < 1900 || y > 2100 || d > _day) {
      return -1
    } // Check the validity of the parameter

    // Calculate the lunar time difference
    var offset = 0
    for (var i = 1900; i < y; i++) {
      offset += this.lYearDays(i)
    }
    var leap = 0,
      isAdd = false
    for (var i = 1; i < m; i++) {
      leap = this.leapMonth(y)
      if(! isAdd) {// Handle leap months
        if (leap <= i && leap > 0) {
          offset += this.leapDays(y)
          isAdd = true
        }
      }
      offset += this.monthDays(y, i)
    }
    // The leap month lunar calendar needs to supplement the time difference of the previous leap month in that year
    if (isLeapMonth) {
      offset += day
    }
    // The first day of the first lunar month in 1900 is 0 hours 0 minutes 0 seconds on January 30, 1900 (this time is also the beginning point of this lunar calendar)
    var stmap = Date.UTC(1900.1.30.0.0.0)
    var calObj = new Date((offset + d - 31) * 86400000 + stmap)
    var cY = calObj.getUTCFullYear()
    var cM = calObj.getUTCMonth() + 1
    var cD = calObj.getUTCDate()
    return `${cY}${cM}${cD}`
    // return this.solar2lunar(cY, cM, cD)
  },
  // Annual holiday schedule
  initHoliday: function(){
    let workday = ['2018-01-01'.'2018-02-02'] // Define it here
    let holiday = ['2018-03-01'.'2018-04-02'] 
    return {workday,holiday}
  }
}
Copy the code

}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}

import calendar from '@/utils/date.js' // Import the defined date.js


// This code is the contents of the rows() function in method, which can be matched by searching for text in the file

if(! row[0]) {
    row[0] = { type: 'week'.text: getWeekNumber(nextDate(startDate, i * 7 + 1)), lunar: calendar.solar2lunar(this.year, this.month, nextDate(startDate, i * 7 + 1))}}if (j + i * 7 >= numberOfDaysFromPreviousMonth) {
  cell.text = count++
  cell.lunar = calendar.solar2lunar(this.year, this.month + 1, cell.text) // A new one
} else {
  cell.text = dateCountOfLastMonth - (numberOfDaysFromPreviousMonth - j % 7) + 1 + i * 7
  cell.type = 'prev-month'
  cell.lunar = calendar.solar2lunar(this.year, this.month, cell.text) // A new one}}else {
if (count <= dateCountOfMonth) {
  cell.text = count++
  cell.lunar = calendar.solar2lunar(this.year, this.month + 1, cell.text) // A new one
} else {
  cell.text = count++ - dateCountOfMonth
  cell.type = 'next-month'
  cell.lunar = calendar.solar2lunar(this.year, this.month + 2, cell.text) // A new one}}Copy the code
  1. Render the structure related to lunar calendar and holidays under the corresponding DOM element (CSS style is omitted here, self-modified, various state style has a lot of adjustment, self-processing for the style), the key code is as follows:
<div :class="{'is-weekend': [6,7]. Includes (cell.lunar. NWeek), 'is-work':cell.lunar.>
  <span>
    {{ cell.text }}
  </span>
  // The section tag is used here for a special reason, explained in the next step
  <section style="position: relative; top: 14px;">{{cell.lunar.lunarFestival? cell.lunar.lunarFestival:(cell.lunar.festival ? Lunar: (cell. Lunar.IDayCn == 'lunar '? cell.lunar.IMonthCn:cell.lunar.IDayCn )) }}</section>
</div>
Copy the code

At this time the lunar calendar, holidays, weekends can be displayed normally. Just when I thought I could relax, I found a new problem.

When I click on the lunar calendar area, there is no trigger date selection issue

Now I find that the selected date is delegated to the entire date component by event delegate, and the section tag cannot trigger the selected event. If we use span or div tags, we cannot tell which target is referring to. Delegate the section click event to the entire outer component at the same time. The key codes are as follows:

handleClick (event) {
      let target = event.target
      if (target.tagName === 'SPAN' || target.tagName == 'SECTION') {
        target = target.parentNode.parentNode
      }
      if (target.tagName === 'DIV') {
        target = target.parentNode
      }
}
Copy the code

Four, New Year’s Eve festival problems

What you want at this point is basically done, and the mood is also comfortable. However, soon there was another problem, that is, when the twelfth lunar month only 29 days, the New Year’s Eve corresponds to the twelfth lunar month 29, not the twelfth lunar month 30, and the festival in my code is the date object directly corresponding

/** * Lunar Festival */
  lfestival: {
    '12-30': { title: 'New Year's eve },
    1-1 ' ': { title: 'New Year' },
    1-15 ' ': { title: Lantern Festival },
    '5-5': { title: Dragon Boat Festival },
    '8-15': { title: Mid-Autumn Festival },
    '9-9': { title: 'Double Ninth Festival' },
    7 '7': { title: 'festival'}},Copy the code

“MonthDays” () “monthDays” () “monthDays” () “” monthDays” () “” monthDays” () “” monthDays” () “” monthDays” () “” monthDays” ()” This means that THERE is no way for me to tell the difference between setting New Year’s Eve for the 29th of the 12th month and setting New Year’s Eve for the 30th of the 12th month. I also began to doubt the correctness of this method. After consulting materials for many times, I found that this method is used on the Internet. This method can only be left at that. The back of the original want to study how to get the New Year’s Eve in JS, also did not understand, here if there is a big guy know, can you guide me?

Finally, in my insistence, it is not the proper way to find a way: general idea is through the lunar date backwards to calculate the corresponding Gregorian calendar date, if the corresponding date of the Gregorian calendar, the lunar month, 30 then also means that the lunar 30 exist, if calculated backwards 30 corresponds to the solar calendar lunar return 1, means that this month, only 29 days. From this we can tell whether New Year’s Eve is the 30th or 29th day of the 12th month.

Key code modifications are as follows:

  /** * y, m, and d are the corresponding lunar year, month, and day respectively
  getLunarFestival(y,m,d) {
    if (m == 12 && d == 29) {
      if (this.lunar2solar(y,m,30) = = -1) {
        delete this.lfestival['12-30']
        this.lfestival['12-29'] = {title: 'New Year's eve}}else {
        delete this.lfestival['12-29']
        this.lfestival['12-30'] = {title: 'New Year's eve}}}return this.lfestival
  },
Copy the code

conclusion

At this point, the second development of the calendar component is complete, also is a basic understanding of the calendar component, this wanted to find other components how to deal with the New Year’s Eve festival, at least has not found the corresponding processing. Here is another successful picture! Demo code address.