vu2 自定义组件v-model

19 阅读1分钟

用法

<sw-date-picker v-model="year"></sw-date-picker>

组件

<template>
  <div class="sw-year-picker">
    <div class="sw-picker-panel-body-wrapper">
      <div class="sw-picker-panel-body">
        <div class="sw-year-picker-header">
          <i class="picker-panel-icon-btn el-date-picker-prev-btn el-icon-d-arrow-left" @click="prevHandler"></i>
          <span class="date-picker-header-label">{{ `${this.yearOptions[1].label} 年 - ${this.yearOptions[10].label} 年` }}</span>
          <i class="picker-panel-icon-btn el-date-picker-next-btn el-icon-d-arrow-right" @click="nextHandler"></i>
        </div>
        <div class="sw-picker-panel-content">
          <div class="sw-year-table">
            <div class="available" @click="$emit('input', item.label);" :style="`color:${(index==0||index==yearOptions.length-1)&&'#bbb'};`" :class="{ 'today': item.label == nowYear, 'current': item.label == value }" v-for="(item, index) in yearOptions" :key="index">
              <div class="cell">{{ item.label }}</div>
              <div class="dot"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  components: {},
  props: {
    value: {}
  },
  data() {
    return {
      nowYear: new Date().getFullYear(),
      yearRange: '',
      yearOptions: [
        { label: 2019 },
        { label: 2020 },
        { label: 2021 },
        { label: 2022 },
        { label: 2023 },
        { label: 2024 },
        { label: 2025 },
        { label: 2026 },
        { label: 2027 },
        { label: 2028 },
        { label: 2029 },
        { label: 2030 }
      ]
    }
  },
  watch: {
    value: {
      handler(newval) {
        if(this.yearOptions[1].label == newval) {
          this.yearRange = this.yearOptions[1].label + 5;
        } else if (this.yearOptions[11].label == newval) {
          this.yearRange = this.yearOptions[11].label + 5;
        } else {
          this.yearRange = newval || this.nowYear;
        }
      },
      immediate: true
    },
    yearRange: {
      handler(newval) {
        if(newval > 10000) {
          this.yearRange = 10000;
        } else if(newval < 1500) {
          this.yearRange = 1500;
        };
        this.yearOptions = this.getYearRange(newval);
      },
      immediate: true
    },
  },
  methods: {
    prevHandler() {
      this.yearRange = this.yearOptions[1].label - 5;
    },
    nextHandler() {
      this.yearRange = this.yearOptions[11].label + 5;
    },
    getYearRange(year) {
      if(isNaN(year/0)) year = this.nowYear;
      const nextDecade = Math.ceil(year / 10) * 10;
      const startYear = nextDecade - 11;
      const years = [];
      for (let y = startYear; y <= nextDecade; y++) {
        years.push({ label: y });
      }
      return years;
    }
  }
}
</script>
<style lang="scss" scoped>
.sw-year-picker {
  width: 320px;
  .sw-picker-panel-body-wrapper {
    .sw-picker-panel-body {
      .sw-year-picker-header {
        margin: 12px;
        margin-bottom: 0;
        padding-bottom: 12px;
        border-bottom: solid 1px #F4F4F4;
        text-align: center;
        .picker-panel-icon-btn {
          font-size: 12px;
          color: #222;
          border: 0;
          background: 0 0;
          cursor: pointer;
          outline: 0;
          margin-top: 8px;
          &:hover {
            color: #0082ED;
          }
        }
        .el-date-picker-prev-btn {
          float: left;
        }
        .el-date-picker-next-btn {
          float: right;
        }
        .date-picker-header-label {
          font-size: 16px;
          font-weight: 500;
          padding: 0 5px;
          line-height: 22px;
          text-align: center;
          cursor: pointer;
          color: #555;
          &:hover {
            color: #0082ED;
          }
        }
      }
      .sw-picker-panel-content {
        position: relative;
        margin: 15px;
        margin-top: 0;
        .sw-year-table {
          display: flex;
          flex-wrap: wrap;
          .available {
            position: relative;
            width: 25%;
            text-align: center;
            padding: 20px 3px;
            color: #555;
            cursor: pointer;
            .cell {
              width: 48px;
              height: 32px;
              display: block;
              line-height: 32px;
              margin: 0 auto;
            }
            .dot {
              position: absolute;
              bottom: 12px;
              left: 50%;
              transform: translateX(-50%);
              width: 4px;
              height: 4px;
              border-radius: 50%;
              background: #FF0000;
            }
          }
          .current {
            color: #0082ED;
          }
          .today {
            font-weight: bold;
            color: #0082ED;
          }
        }
      }
    }
  }
}
</style>