vue 封装月份多选组件

        写这个组件的时候。element el-date-picker 还没有 type="months" 可以选择多个月份的功能。现在若想选则多个月份,可直接使用element。本文仅做个记录。

一、直接使用el-date-picker  type="months"

<div class="container">
  <div class="block">
    <span class="demonstration">周</span>
    <el-date-picker
      v-model="value1"
      type="week"
      format="yyyy 第 WW 周"
      placeholder="选择周">
    </el-date-picker>
  </div>
  <div class="block">
    <span class="demonstration">月</span>
    <el-date-picker
      v-model="value2"
      type="month"
      placeholder="选择月">
    </el-date-picker>
  </div>
</div>
<div class="container">
  <div class="block">
    <span class="demonstration">年</span>
    <el-date-picker
      v-model="value3"
      type="year"
      placeholder="选择年">
    </el-date-picker>
  </div>
  <div class="block">
    <span class="demonstration">多个日期</span>
    <el-date-picker
      type="dates"
      v-model="value4"
      placeholder="选择一个或多个日期">
    </el-date-picker>
  </div>
</div>
<div class="container">
  <div class="block">
    <span class="demonstration">多个月</span>
    <el-date-picker
      type="months"
      v-model="value5"
      placeholder="选择一个或多个月">
    </el-date-picker>
  </div>
  <div class="block">
    <span class="demonstration">多个年</span>
    <el-date-picker
      type="years"
      v-model="value6"
      placeholder="选择一个或多个年">
    </el-date-picker>
  </div>
</div>

<script>
  export default {
    data() {
      return {
        value1: '',
        value2: '',
        value3: '',
        value4: '',
        value5: '',
        value6: ''
      };
    }
  };
</script>

 二、自己封装组件

1、新建组件  SelectMonths.vue

<template>
  <div id="boxArea" ref="selectMonths" class="selectMonthBoxSquare rel clearFixed">
    <el-popover
      v-model="visible"
      placement="bottom"
      width="250"
      trigger="click"
    >
      <el-input slot="reference" v-model="inputValue" class="inputStyle" type="text" size="small" :placeholder="placeholder" readonly @focus="showBox = true">
        <i slot="prefix" class="el-input__icon el-icon-date"></i>
        <i v-if="showClear" slot="suffix" class="el-input__icon el-icon-circle-close clearIconStyle" @click="resetMonth"></i>
      </el-input>

      <div class="selectContentBox">
        <div class="contentArea">

          <div class="flex flex-wrap flex-around" style="padding: 15px 0;border-bottom: 1px solid #e5e5e5;">
            <div v-if="curIndex == DateList.length - 1" class="cursor el-icon-d-arrow-left" style="width: 15%; color: gray;" />
            <div v-else class="cursor el-icon-d-arrow-left" style="width: 15%;" @click="reduceYear" />
            <div>{{ OneY }}年</div>
            <div v-if="curIndex == 0" class="cursor t-r el-icon-d-arrow-right" style="width: 15%;  color: gray;" />
            <div v-else class="cursor t-r el-icon-d-arrow-right" style="width: 15%;" @click="addYear" />
          </div>

          <div class="conterList">
            <el-checkbox-group v-model="optTime[curIndex].queryTime" class="flex flex-wrap" @change="onChange">
              <el-row class="monthRow">
                <el-col v-for="(item,index) in DateList[curIndex].queryTime" :key="index" :span="6" class="monthCol">
                  <el-checkbox :class="[{'today': item === currentM && curIndex === (DateList.length - 1) / 2}, 'onSelect flex-x-center']" :label="`${DateList[curIndex].TimeYear}-${(item<=9)?`0${item}`:item}`">
                    {{ monthMap[item] }}月
                  </el-checkbox>
                </el-col>
              </el-row>
            </el-checkbox-group>
          </div>
        </div>

        <div class="buttonBox t-r">
          <el-button class="buttonStyle" size="mini" plain @click.stop="resetMonth">重置</el-button>
          <el-button class="buttonStyle" size="mini" type="primary" plain @click.stop="handleSubmit">确定</el-button>
        </div>
      </div>
    </el-popover>
  </div>
</template>
<script>
  export default {
    name: 'SelectMonths',
    props: {
      placeholder: {
        type: String,
        default: '请选择查询月份'
      }
    },
    data() {
      return {
        DateList: [], // 年份月份数组
        optTime: [], // 月份选中结果数组
        OneY: '', // 当前年份
        currentM: '', // 当前月份
        curIndex: 0, // 当前年份下标值
        optTimes: [], // 点击月份时的所有选中结果
        resultTimes: [], // 点击“确定”按钮后的选择结果
        showBox: false, // 是否显示月份选择弹框
        visible: false,
        inputValue: '', // 输入框的绑定值
        showClear: false, // 是否显示输入框右边的“清空”小图标
        monthMap: { // 月份显示为中文
          '1': '一',
          '2': '二',
          '3': '三',
          '4': '四',
          '5': '五',
          '6': '六',
          '7': '七',
          '8': '八',
          '9': '九',
          '10': '十',
          '11': '十一',
          '12': '十二'
        }
      }
    },
    created() {
      this.init()
    },
    mounted() {
      // 点击弹框外的任意位置关闭区域弹窗
      document.addEventListener('click', (e) => {
        // 获取弹窗对象
        const boxArea = document.getElementById('boxArea')
        // 判断弹窗对象中是否包含点击对象
        if (boxArea && !boxArea.contains(e.target)) {
          // 判断当前选中月份与上次点击“确定”按钮时的选择结果是否一致
          const equalArr = this.resultTimes.sort().toString() === this.optTimes.sort().toString()
          if (!equalArr) {
            // 如果不一致(因为是多选,所以必须是点击了“确定”按钮后才能进行查询):
            // 将选择结果恢复到上次点击“确定”按钮时的结果
            this.optTimes = this.resultTimes
            // 将输入框的值恢复到上次点击“确定”按钮时的值
            this.inputValue = this.optTimes.join(',')
            // 根据输入框是否有值来判断清空图标是否渲染
            this.showClear = !!this.inputValue !== ''
            // 将月份选中结果恢复到上次点击“确定”按钮时的选中月份
            const _opt = this.resultTimes.map(v => { return v.substring(0, 4) })
            for (const item in this.optTime) {
              this.optTime[item].queryTime = []
              _opt.map((items, indexs) => {
                if (items === this.optTime[item].TimeYear) {
                  this.optTime[item].queryTime.push(this.resultTimes[indexs])
                }
              })
            }
          }
          // 关闭弹框
          this.showBox = false
        }
      })
    },
    methods: {
      // 初始化数据,获取前20年,然后循环 每一年里面都有12个月的 得到数组 opTime 和 DateList
      init() {
        const _this = this
        const _opt = []
        const _optTime = []
        const arr = new Array(12)
        const optDate = this.getDateList()
        optDate.map((item, index) => {
          // 月份选择时el-checkbox-group绑定的值
          _optTime[index] = {
            TimeYear: item.value,
            queryTime: []
          }
          // 给每一年份设置12个月份,el-checkbox初始化显示时使用
          _opt[index] = {
            TimeYear: item.value,
            queryTime: []
          }
          for (let i = 1; i <= arr.length; i++) {
            _opt[index].queryTime.push(i)
          }
        })
        _this.optTime = _optTime
        _this.DateList = _opt
        _this.curIndex = (_this.DateList.length - 1) / 2
        // console.log('_this.curIndex', _this.curIndex)
      },
      // 获取近20年年份列表,倒序排列,最新一年在最前面
      getDateList() {
        const Dates = new Date()
        const year = Dates.getFullYear()
        this.OneY = year
        this.currentM = Dates.getMonth() + 1
        const startyear = Dates.getFullYear() - 20
        const endyear = Dates.getFullYear() + 20
        const Years = []
        for (let i = startyear; i <= endyear; i++) {
          const currentYear = { key: i, value: i }
          Years.push(currentYear)
        }
        return Years.reverse()
      },
      // 确定
      handleSubmit() {
        const _this = this
        // 更新输入框的值
        _this.inputValue = _this.optTimes.join(',')
        // 根据输入框是否有值来判断清空图标是否渲染
        _this.showClear = !!_this.inputValue !== ''
        // 将点击“确定”按钮的选择结果保存起来(该值将在哪里使用:在点击弹框以外区域关闭弹框时使用,mounted中)
        _this.resultTimes = _this.optTimes
        // 关闭弹框
        _this.showBox = false
        _this.visible = false
        _this.$emit('submitBtn', _this.resultTimes)
      },
      // 重置
      resetMonth() {
        const _this = this
        // 将年份重置到当前年份
        const Dates = new Date()
        const year = Dates.getFullYear()
        _this.OneY = year
        _this.curIndex = (_this.DateList.length - 1) / 2
        // 将已选择的月份清空
        _this.optTimes = []
        for (const i in _this.optTime) {
          _this.optTime[i].queryTime = []
        }
        // 将输入框清空
        _this.inputValue = ''
        // 根据输入框是否有值来判断清空图标是否渲染,此处必然不渲染
        this.showClear = false
        // 将点击“确定”按钮的选择结果清空
        _this.resultTimes = []
        // 关闭月份选择弹框
        _this.showBox = false
        _this.visible = false
        _this.$emit('resetBtn', _this.resultTimes)
      },
      // 左上角年份减少
      reduceYear() {
        const _this = this
        // 如果已经是最后一年了,则年份不能再减少了
        if (_this.curIndex === _this.DateList.length - 1) return
        // 当前下标值+1,根据下标值获取年份值
        _this.curIndex = _this.curIndex + 1
        _this.OneY = _this.DateList[_this.curIndex].TimeYear
      },
      // 左上角年份增加
      addYear() {
        const _this = this
        // 如果已经是当前年份了,则年份不能再增加了
        if (_this.curIndex === 0) return
        // 当前下标值-1,根据下标值获取年份值
        _this.curIndex = _this.curIndex - 1
        _this.OneY = _this.DateList[_this.curIndex].TimeYear
      },
      // 选择月份
      onChange() {
        const _this = this
        // 遍历optTime中已选择的月份,将已选结果塞到optTimes数组中
        const _opt = _this.optTime
        const arr = []
        for (const item in _opt) {
          if (_opt[item].queryTime.length > 0) _opt[item].queryTime.filter(v => { arr.push(v) })
        }
        _this.optTimes = arr
        // 更新输入框的值
        _this.inputValue = _this.optTimes.join(',')
        // 根据输入框是否有值来判断清空图标是否渲染
        _this.showClear = !!_this.inputValue !== ''
      }
    }
  }
</script>
<style lang="scss" scoped>
  .flex {
    display: -webkit-box;
    display: -webkit-flex;
    display: flex;
    justify-content: center;
  }
  .flex-wrap {
    flex-wrap: wrap;
  }
  .flex-around {
    justify-content: space-around;
  }
  .flex-x-center {
    display: -webkit-box;
    display: -webkit-flex;
    display: flex;
    -webkit-box-pack: center;
    -webkit-justify-content: center;
    -ms-flex-pack: center;
    justify-content: center;
  }
  .selectMonthBoxSquare {
    // width: 250px;
    width: 100%;
    .selectContentBox {
      position: absolute;
      top: 35px;
      left: 0;
      z-index: 2021;
      background: #ffffff;
      border: 1px solid #e5e5e5;
      border-radius: 3px;
      .contentArea {
        width: 330px;
      }
    }
  }

    .inputStyle {
      width: 100%;
    }
    .clearIconStyle {
      display: none;
    }
    .inputStyle:hover .clearIconStyle{
      display: block;
    }
    .conterList{
      .monthCol{
        .today {
          color: #1890ff;
        }
      }
      .onSelect{
        // width: 25% !important;
        padding:3px 0;
        margin: 20px 0 !important;
      }
    }
    ::v-deep .el-checkbox__input {
      display: none !important;
    }
    ::v-deep .el-checkbox__label {
      padding-left: 0px !important;
    }
    ::v-deep .el-checkbox__input.is-checked + .el-checkbox__label {
      color: #fff;
    }
    label.el-checkbox.onSelect.flex-x-center.is-checked {
      background: #409EFF;
      width: 50px;
      border-radius: 15px;
    }
    .lableStyle {
      font-size: 14px;
    }
    .el-button--mini {
      padding: 5px 15px;
      font-size: 12px;
      border-radius: 3px;
    }
    .buttonBox {
      border-top: 1px solid #e5e5e5;
      padding: 10px;
      display: flex;
      justify-content: flex-end;
    }
</style>

 2、使用组件  SelectMonths

<template>
  <div class="app-container">
    <div>
      <span class="label">月份:</span>
      <SelectMonths
        ref="selectMonths"
        v-model="monthsValue"
        placeholder="请选择月份"
        @submitBtn="submitBtn"
        @resetBtn="resetBtn" />
    </div>
  </div>
</template>

<script>
  import SelectMonths from '@/components/SelectMonths'
  export default {
    components: {
      SelectMonths
    },
    data() {
      return {
        monthsValue: null
      }
    },
    methods: {
      submitBtn(val) {
        const months = JSON.parse(JSON.stringify(val))
        const monthsArr = months.map(item => {
          return item.concat('-01')
        })
        this.monthsValue = monthsArr.join(',')
      },
      resetBtn() {
        this.monthsValue = null
      },
    }
  }
</script>

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
以下是一个基于Vue2的多选层级树组件的示例代码,你可以根据自己的需求进行修改: ```html <template> <div class="tree"> <div class="tree-item" v-for="(item, index) in treeData" :key="index"> <input type="checkbox" :id="'tree'+index" :checked="item.checked" @change="checkNode(item, $event)"> <label :for="'tree'+index">{{ item.label }}</label> <div class="tree-children" v-if="item.children && item.children.length > 0"> <tree :tree-data="item.children" :last-rank="lastRank(item)"></tree> </div> </div> </div> </template> <script> export default { name: 'tree', props: { treeData: { type: Array, default: () => [] }, lastRank: { type: Boolean, default: false } }, methods: { checkNode(node, event) { node.checked = event.target.checked if (node.children && node.children.length > 0) { node.children.forEach(child => { child.checked = event.target.checked }) } } } } </script> <style scoped> .tree { margin-left: 20px; } .tree-item { display: flex; align-items: center; } .tree-item input[type="checkbox"] { margin-right: 10px; } .tree-children { margin-left: 20px; } </style> ``` 在上述代码中,我们定义了一个名为`tree`的组件,该组件接收两个props:`treeData`和`lastRank`。其中,`treeData`是一个数组,用于表示树的数据结构;`lastRank`是一个布尔值,用于判断当前节点是否是最后一级节点。 在组件的模板中,我们使用了递归的方式来渲染整棵树。对于每个节点,我们都渲染了一个复选框和一个标签,并且根据是否有子节点来决定是否渲染子树。 在组件的方法中,我们定义了一个`checkNode`方法,用于处理节点的选中状态。当一个节点被选中时,我们需要将其所有子节点也选中;当一个节点被取消选中时,我们需要将其所有子节点也取消选中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值