vue 模仿机票自定义日历组件,区间选择

1.创建组件  components > calander > index.vue

<template>
  <div class="page" v-if="show">  
    <div class="box">  
      <div class="box_head" v-if="!propshow">
        <div class="font28" @click="calanderShowData">取消</div>
        <div class="font28" @click="calanderSubmit">确定</div>        
      </div>

      <div class="box-flex">  
        <div class="flex-item item-content-current-day  item-content-tit">  
          <div class="item-content titleHead">{{currentDate}}</div>  
        </div>  
        </div>  
      </div>  
      <div class="box-flex">  
        <div class="flex-item">  
          <div class="item-content"></div>  
        </div>  
        <div class="flex-item">  
          <div class="item-content"></div>  
        </div>  
        <div class="flex-item">    
          <div class="item-content"></div>  
        </div>  
        <div class="flex-item">  
          <div class="item-content"></div>  
        </div>  
        <div class="flex-item">  
          <div class="item-content"></div>  
        </div>  
        <div class="flex-item">  
          <div class="item-content"></div>  
        </div>  
        <div class="flex-item">  
          <div class="item-content"></div>  
        </div>  
      </div>  
      <div class="box-flex">  
        <div class="flex-item flexData" v-for='(item, index) in currentDayList' :key='item' @click='itemFun(item.num,mouth[index],index, "first", item.state)' :class="{'hover-date': Section[index] && item.num, 'noBack': !item.state && item.num && !propshow}">  
            <div class="item-content red-background" v-if='currentDay === item.num && mouth[index].mouth === currentMouth.mouth && currentMouth.year === mouth[index].year' :class="{'hoverColorData' : Section[index] && item.num, 'hover-date':active[index]}">
              <p>今天</p>
              <p v-if="item.number && propshow">{{item.number}}展位</p>              
            </div>  
            <div class="item-content backgroundData" v-else :class="{'hover-date':active[index]}" >
              <p>{{item.num}}</p>
              <p v-if="item.number && propshow">{{item.number}}展位</p>
            </div>  
        </div>  
      </div>  
          <div class="box">  
      <div class="box-flex">  
        <div class="flex-item item-content-current-day  item-content-tit">  
          <div class="item-content titleHead">{{currentDateTwo}}</div>  
        </div>  

        </div>  
      </div>  
      <div class="box-flex">  
        <div class="flex-item">  
          <div class="item-content"></div>  
        </div>  
        <div class="flex-item">  
          <div class="item-content"></div>  
        </div>  
        <div class="flex-item">    
          <div class="item-content"></div>  
        </div>  
        <div class="flex-item">  
          <div class="item-content"></div>  
        </div>  
        <div class="flex-item">  
          <div class="item-content"></div>  
        </div>  
        <div class="flex-item">  
          <div class="item-content"></div>  
        </div>  
        <div class="flex-item">  
          <div class="item-content"></div>  
        </div>  
      </div>  
      <div class="box-flex">  
        <div class="flex-item flexData" v-for='(item, index) in currentDayListData' :key='item' @click='itemFun(item.num,mouths[index],index, "last", item.state)' :class="{'hover-date': Sections[index] && item.num, 'noBack': !item.state && item.num && !propshow}">  
            <div class="item-content backgroundData" :class="{'hover-date':actives[index]}">
              <p>{{item.num}}</p>
              <p v-if="item.number && propshow">{{item.number}}展位</p>
            </div>  
        </div>  
      </div> 

  <div v-if="propshow" class="propshowData"></div>
</div>  
</template>  

<script>
import vue from 'vue'
export default {
  name: 'calander',
  data () {
    return {
      calanderList: [],
      show: false,
      currentDate: '2017年05月03日',
      currentDateTwo: '2017年06月03日',
      dayList: '',
      currentDayList: [],
      currentObj: '',
      currentDay: '',
      mouth: [],
      currentMouth: null,
      hoverDate: {'date': null, 'mouth': null, 'year': null},
      activeClick: 0,
      active: [],
      actives: [],
      Section: [],
      firstIndex: 0,
      lastIndex: 0,
      currentDayListData: [],
      currentJudge: false,
      currentObjNew: '',
      Sections: [],
      lastType: '',
      fristType: '',
      numArray: [],
      numArrayTwo: []
    }
  },
  props: {
    propshow: false,
    boothArray: [], // 从父级传来的数组,中主要携带number展位数,
    calanderList: [],
    yearAndmouthFirst: {},
    yearAndmouthTwo: {},
    calanderShow: false
  },
  mounted () {
    let timeData = this.getNextMonth(new Date(),1)
    var currentObj = this.getCurrentDayString()
    this.currentDate = currentObj.getFullYear() + '' + (currentObj.getMonth() + 1) + '' + currentObj.getDate() + ''
    this.currentDateTwo = timeData.getFullYear() + '' + (timeData.getMonth() + 1) + '' + timeData.getDate() + ''
    
    // this.currentObjNew = currentObj.getFullYear() + '/' + (currentObj.getMonth() + 2) + '/' + currentObj.getDate()
    this.currentDay = currentObj.getDate()
    
    this.currentObj = currentObj
    this.currentMouth = {
      mouth: currentObj.getMonth() + 1,
      year: currentObj.getFullYear()
    }

    setTimeout(() => {
      this.setSchedule(currentObj, 'newMonth') 
      this.setSchedule(this.getNextMonth(new Date(),1), 'nextMonth')            
      // this.setSchedule(new Date(this.currentObjNew), 'nextMonth') 
    },100);
  },
  methods: {    
    monthDay: function (year, month) {
        month = parseInt(month, 10);
        var d = new Date(year, month, 0);  //这个是都可以兼容的
        var date = new Date(year + "/" + month + "/0")   //IE浏览器可以获取天数,谷歌浏览器会返回NaN
        return d.getDate();
    },
    getNextMonth: function (date,length) {
      let yy = date.getFullYear()
      let mm = date.getMonth()
      let dd = date.getDate()
      
      let nm= 0//目标月份
      nm = mm+length
      let nd = 0//目标天数
      if(this.monthDay(yy,nm+1)<dd){
        nd = this.monthDay(yy,nm+1)
      }else{
        nd = dd-1
      }

      date.setDate(1)
      date.setMonth(nm)
      date.setDate(nd)
      return date
    },
    calanderSubmit(){
      console.log(this.numArray)
      this.$emit('assignment', this.numArray)
    },
    calanderShowData(){
      this.$emit('calanderShowClick', this.calanderShow)
    },
    formatTwo (n) {
      if (n >= 10) return n
      else return '0' + n
    },
    // 判断日历的当前日期是否不可点击
    isDisabled (calander, index, item) {
      // if (new Date(calander).getTime() < new Date().getTime()) {
      //   this.mouth[index].state = 'disabled'
      //   return false
      // }
    },
    getWeekDayNextMonth(){
      var myDate = new Date()
      myDate.setMonth(myDate.getMonth() + 1);
      myDate.setDate(1);
      var weekDay=new Array(7, 1, 2, 3, 4, 5, 6)
      return weekDay[myDate.getDay()];
    },
    itemFun (item, yearAndmouth, index, type, stateClick) {  
      if (stateClick) {
        let dataD = new Date();
        let curMonthDays = new Date(dataD.getFullYear(), (dataD.getMonth()+1), 0).getDate()
        this.hoverDate = {'date': item, 'mouth': yearAndmouth.mouth, 'year': yearAndmouth.year}

        if (type == 'first') {
          var activeArrayData = this.active
          var SectionArrayData = this.Section
        } else {
          var activeArrayData = this.actives
          var SectionArrayData = this.Sections              
        }

        if (this.activeClick == 0) {
          this.yearAndmouthFirst = yearAndmouth
          this.yearAndmouthFirst.date = item
          for(let i=0; i<this.active.length; i++){
            this.active[i] = false
            vue.set(this.active, i, this.active[i])                    
          }
          for(let i=0; i<this.actives.length; i++){
            this.actives[i] = false
            vue.set(this.actives, i, this.actives[i])                    
          }
          for(let t=0; t<this.Section.length; t++){
            this.Section[t] = false
            vue.set(this.Section, t, this.Section[t])
          }
          for(let t=0; t<this.Sections.length; t++){
            this.Sections[t] = false
            vue.set(this.Sections, t, this.Sections[t])
          }
          this.numArray = []
          this.activeClick = 1
          this.fristType = type
          this.firstIndex = item
          this.yearFirst = yearAndmouth.year
          this.mouthFirst = yearAndmouth.mouth
          
          activeArrayData[index] = true
          vue.set(activeArrayData, index, activeArrayData[index])
          this.numArray.push(this.yearAndmouthFirst)
          console.log(this.numArray)
        } else if (this.activeClick == 1){  
          this.numArray = []
          this.yearAndmouthTwo = yearAndmouth
          this.yearAndmouthTwo.date = item
          if (this.firstIndex != index) {
            this.activeClick = 0
            this.lastIndex = item
            this.lastType = type
            this.yeaTwo = yearAndmouth.year
            this.mouthTwo = yearAndmouth.mouth

            activeArrayData[index] = true
            vue.set(activeArrayData, index, activeArrayData[index])
            if (this.fristType == this.lastType) {
              if (this.lastIndex > this.firstIndex) {
                var indexCenter = this.lastIndex - this.firstIndex + 1          
              } else {
                var indexCenter = this.firstIndex - this.lastIndex + 1                            
              }
              for(let j=0; j<indexCenter; j++){
                if (this.lastIndex < this.firstIndex) {
                  var indexData = j + index
                  this.numArray.push({'date': item + j, 'mouth': yearAndmouth.mouth, 'year': yearAndmouth.year})
                } else {
                  this.numArray.unshift({'date': item - j, 'mouth': yearAndmouth.mouth, 'year': yearAndmouth.year})                
                  var indexData = index - j
                }
                SectionArrayData[indexData] = true
                vue.set(SectionArrayData, indexData, SectionArrayData[indexData])
              }
            } else {
              if (this.fristType == 'first') {
                var indexCenter = curMonthDays - this.firstIndex + 1
                var indexCenters = this.lastIndex
              } else {
                var indexCenter = curMonthDays - this.lastIndex + 1
                var indexCenters = this.firstIndex       
              }
              
              for(let j=0; j<indexCenter; j++){
                if (this.fristType == 'first') {
                  var indexData = this.firstIndex + j
                  this.numArray.push({'date': indexData, 'mouth': this.mouthFirst, 'year': this.yearFirst})                
                } else {
                  var indexData = this.lastIndex + j
                  this.numArray.push({'date': item + j, 'mouth': this.mouthTwo, 'year': this.yeaTwo})                
                }
                this.Section[indexData + 1] = true
                vue.set(this.Section, indexData, this.Section[indexData]) 
              } 
            
              var monthData = this.getWeekDayNextMonth()
              for(let j=0; j<indexCenters; j++){
                if (this.fristType == 'first') {
                  var indexDatas = j + monthData - 1
                  this.numArrayTwo.unshift({'date': item - j, 'mouth': this.mouthTwo, 'year': this.yeaTwo})                
                } else {
                  var indexDatas = this.firstIndex - j + monthData -2
                  this.numArrayTwo.unshift({'date': this.firstIndex - j , 'mouth': this.mouthFirst, 'year': this.yearFirst})                
                }
                this.Sections[indexDatas] = true
                vue.set(this.Sections, indexDatas, this.Sections[indexDatas])
              }
            }
            this.numArray = this.numArray.concat(this.numArrayTwo)
          } 
        }
      }
    },
    doDay: function (e) {
      var that = this
      var currentObj = that.currentObj
      var Y = currentObj.getFullYear()
      var m = currentObj.getMonth() + 1
      let newData = new Date 
      let newMonth=newData.getMonth()+1;
      let d = currentObj.getDate()
      var str = ''
      if (e.currentTarget.dataset.key === 'left') {
        m -= 1
        if (m <= 0) {
          str = (Y - 1) + '/' + 12 + '/' + d
        } else {
          str = Y + '/' + m + '/' + d
        }
        this.currentJudge = true
      } else if(e.currentTarget.dataset.key === 'right') {
        if (newMonth !== m) {
          m += 1
          if (m <= 12) {
            str = Y + '/' + m + '/' + d
          } else {
            str = (Y + 1) + '/' + 1 + '/' + d
          }
          this.currentJudge = true
        } else {
          this.currentJudge = false          
        }
      } else if (e.currentTarget.dataset.key === 'leftTwo'){   
        if (newMonth !== m) {
          m -= 1
          if (m <= 0) {
            str = (Y - 1) + '/' + 12 + '/' + d
          } else {
            str = Y + '/' + m + '/' + d
          }
          this.currentJudge = true
        } else {
          this.currentJudge = false
        }
      } else if (e.currentTarget.dataset.key === 'rightTwo'){
        m += 1
        if (m <= 12) {
          str = Y + '/' + m + '/' + d
        } else {
          str = (Y + 1) + '/' + 1 + '/' + d
        }
        this.currentJudge = true
      }
      if (this.currentJudge) {
        currentObj = new Date(str)
        this.currentDate = currentObj.getFullYear() + '' + (currentObj.getMonth() + 1) + '' + currentObj.getDate() + ''
        this.currentDateTwo = currentObj.getFullYear() + '' + (currentObj.getMonth() + 2) + '' + currentObj.getDate() + ''        
        this.currentObjNew = currentObj.getFullYear() + '/' + (currentObj.getMonth() + 2) + '/' + currentObj.getDate() + '/'        
        
        this.currentObj = currentObj
        if (e.currentTarget.dataset.key == 'left' || e.currentTarget.dataset.key == 'right') {
          this.setSchedule(currentObj, 'newMonth')
        } else {
          this.setSchedule(new Date(this.currentObjNew), 'nextMonth')
        }
      }
    },
    getCurrentDayString: function () {
      var objDate = this.currentObj
      if (objDate !== '') {
        return objDate
      } else {
        var cobj = new Date()
        var a = cobj.getFullYear() + '/' + (cobj.getMonth() + 1) + '/' + cobj.getDate()
        return new Date(a)
      }
    },
    setSchedule: function (currentObj, type) {
      var that = this
      var m = currentObj.getMonth() + 1
      var Y = currentObj.getFullYear()
      var d = currentObj.getDate()
      var newDate = new Date()
      var newYear = newDate.getFullYear()
      var newMonth = newDate.getMonth() + 1
      
      // var dayString = Y + '/' + m + '/' + currentObj.getDate()
      var currentDayNum = new Date(Y, m, 0).getDate()
      var currentDayWeek = currentObj.getUTCDay() + 1
      
      var result = currentDayWeek - (d % 7 - 1)
      
      var firstKey = result <= 0 ? 7 + result : result
      
      var currentDayListNew = []

      var mouth = []
      var f = 0
      for (var i = 0; i < 42; i++) {
        mouth[i] = {
          'mouth': m,
          'year': Y
        }
        currentDayListNew[i] = {
          'num': '',
          'number': '',
          'state': false
        }
        if (i < firstKey - 1) {
          currentDayListNew[i].num = ''
        } else {
          if (f < currentDayNum) {
            currentDayListNew[i].num = f + 1
            f = currentDayListNew[i].num
            if (newYear == Y && newMonth == m) {
              if (f >= d) {
                currentDayListNew[i].state = true
              }
            } else {
              if (f <= d) {
                currentDayListNew[i].state = true
              }
            }
          } else if (f >= currentDayNum) {
            currentDayListNew[i].num = ''
          }
          if (this.boothArray.length > 0) {
            this.boothArray.forEach((element, indexArray) => {
              if (element.year == Y && element.mouth == m) {
                if (element.date == currentDayListNew[i].num) {
                  currentDayListNew[i].number = String(element.number)
                }
              }
            })
          }
          if (this.calanderList.length > 0) {
            this.calanderList.forEach((element, indexList) => {
              if (element.year == Y && element.mouth == m) {
                if (element.date == currentDayListNew[i].num) {
                  if (type == 'newMonth') {
                    this.Section[i] = true
                  } else {
                    this.Sections[i] = true
                  }                  
                }
              }
            });
          }          
        }
      }

      if (type == 'newMonth') {
        that.currentDayList = currentDayListNew
        that.mouth = mouth
      } else {
        that.currentDayListData = currentDayListNew     
        that.mouths = mouth                   
      }
      this.show = true                
    }
  }
}
</script>

<style scoped>
.box_head{
  height: 1.173333rem /* 88/75 */;
  background: #fff;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 .4rem /* 30/75 */;
  border-bottom: .013333rem /* 1/75 */ solid #E5E5E5;
}
.noBack{
  background: #bbb!important;
  /* border-radius: 5px!important; */
}
.hoverColorData{
  color: #fff!important;
}
.propshowData{
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  top: 0;
  background: rgba(0, 0, 0, 0.1);
  z-index: 9999;
}
.page{
  background: #fff;
  position: relative;
}
.titleHead{
  margin: .266667rem /* 20/75 */ 0!important;
}
.sectionBack{
  background: #8A2BE2;
}
page {  
  background-color: #2a8cef;  
  background:-webkit-gradient(linear, 0 0, 0 bottom, from(#2a8cef), to(#8A2BE2));  
  display: flex;  
  flex-direction: column;  
  width: 100%;  
  flex-wrap: nowrap;  
  justify-content: flex-start;  
  align-items: stretch;  
  font-size: 16px;  
  color: #222;
} 
.disabled{
  color: #ccc !important;
} 
.hover-date{
  background: #367EED;
  color: #fff !important;
  border-radius: 5px;
}  
.box {  
  display: block;  
  /* margin: 10px;   */
  border-top: .013333rem /* 1/75 */ solid #efefef;  
} 
.glyphicon-triangle-left img{
  transform:rotate(180deg)
} 
  .glyphicon img{
    width:12px;
    height: 19px;
    margin-top:15px;
  }
.box-flex {  
  display: -webkit-box;  
  display: -webkit-flex;  
  display: flex;  
  flex-wrap: wrap;  
  padding: 0 .133333rem /* 10/75 */;
}  
  
.flex-item {  
  flex-flow: nowrap;  
  flex-grow: 1;  
  flex-shrink: 1;  
  width: 14%;  
  margin: 1px 1px 1px 0px;
}  
  
.item-content {  
  margin: 1px;  
  padding: 5px 1px;  
  text-align: center;  
  /* height: 45px;   */
  /* line-height: 45px;   */
  font-size:14px;
  position: relative;
      flex-wrap: wrap;
    justify-content: center;
}  
.item-content i{
  width:100%;
  text-align: center;
  left:0;
  position: absolute;
  top:8px;
}
.item-content span{
  width:100%;
  text-align: center;
  left:0;
  position: absolute;
  top:3px;
  font-size:12px;
  color: #367EED;
  line-height: 1;
}
.item-content-tit{
  width:30%;
  /* margin: .133333rem 10/75 0; */
}
.item-content-tit .item-content{
    font-size:17px;
}
  .red-background{
    color:#367EED;
    border-radius: 5px;
  }
  
  
.item-content-current-day {  
  flex-grow: 2;  
}  
</style>

2.页面中引用组件

<calander @assignment="assignment" :propshow="propshow" :boothArray="boothArray" :calanderList="calanderList"></calander> 


<script>
    import calander from '@/components/calander'
    export default {
       components: {
         calander
       },
   data() {
      return {
        calanderList: [],
        boothArray: [],
        propshow: false,
      };
    },
    methods: {
      assignment(){
        // 组件调取父级方法
      },
    }
    }
</script>
原文地址:https://www.cnblogs.com/gqx-html/p/9962148.html