z-950 / blog

This is a blog for myself
0 stars 0 forks source link

日历组件 #2

Open z-950 opened 4 years ago

z-950 commented 4 years ago

这本是一道笔试题。最后差两个判断没有修改。 其中比较少见的是,使用new Date(2020, 1, 0).getDate()可以获取2020年1月的总天数 代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    table.calendar {
      font-size: 14px;
      border-collapse: collapse;
      width: 100%;
      table-layout: fixed;
    }

    table.calendar th {
      background: #f5f5f5;
      color: #999;
    }

    table.calendar th,
    table.calendar td {
      border: 1px solid #e1e1e1;
      padding: 0;
      height: 32px;
      line-height: 32px;
      text-align: center;
    }

    table.calendar td.current {
      background: #1890ff;
      color: #fff;
    }

    table.calendar th.pre,
    table.calendar th.next {
      color: #1890ff;
      cursor: pointer;
    }

    table.calendar th.date {
      color: #000;
    }
  </style>
</head>

<body>
  <button type="button" onclick="calendar(document.getElementById('jsContainer'), 2020, 1)">button</button>
  <div id="jsContainer">
  </div>
  <script>
    function calendar(container, year, month) {
      this.year = year;
      this.month = month;
      this.html = html;
      this.el = document.createElement("table"); //TODO: 创建分页组件根节点
      if (!el) return;
      this.el.className = 'calendar';
      this.el.innerHTML = this.html();
      container.appendChild(this.el);

      this.el.addEventListener('click', event => {
        var el = event.target;
        var isPre = el.classList.contains('pre');
        var isNext = el.classList.contains('next');
        if (!isPre && !isNext) return;
        if (isPre) {
          //TODO: 更新this.month和this.year
          if (this.month !== 1) {
            this.month--
          } else {
            this.year--
            this.month = 12
          }
        } else {
          //TODO: 更新this.month和this.year
          if (this.month !== 12) {
            this.month++
          } else {
            this.year++
            this.month = 1
          }
        }
        this.el.innerHTML = this.html();
      });

      function html() {
        var date = new Date();
        var year = +this.year || 0;
        var month = (+this.month || 0) - 1;
        var day = date.getDate();
        //TODO: 生成组件的内部html字符串
        let days = new Date(year, month + 1, 0).getDate()
        let startAt = new Date(year, month).getDay() - 1
        if (startAt === -1) startAt = 6
        const lines = Math.ceil((days + startAt) / 7)
        let endAt = (days + startAt) % 7
        if (endAt === 0) endAt = 7

        const couldBeCurrent = month === date.getMonth() && year === date.getFullYear()

        let i = 1
        const getDateTd = () => {
          const current = i
          ++i
          if (couldBeCurrent && current == day) {
            return `<td class="current">${current}</td>`
          } else {
            return `<td>${current}</td>`
          }
        }
        const getDateTdList = (n) => {
          let tdList = ''
          while (n--) {
            tdList += getDateTd()
          }
          return tdList
        }

        let html = `<thead>
                        <tr><th class="pre"><</th><th colspan="5" class="date">${this.year}.${this.month < 10 ? '0' : ''}${this.month}</th><th class="next">></th></tr>
                        <tr><th>一</th><th>二</th><th>三</th><th>四</th><th>五</th><th>六</th><th>日</th></tr>
                    </thead>
                    <tbody>`
        html += `<tr>${'<td></td>'.repeat(startAt)}${getDateTdList(7 - startAt)}</tr>`
        let count = lines - 2
        while (count--) {
          html += `<tr>${getDateTdList(7)}</tr>`
        }
        html += `<tr>${getDateTdList(endAt)}${'<td></td>'.repeat(7 - endAt)}</tr>`
        html += '</tbody>'
        return html;
      }
    }
  </script>
</body>
</html>