原生js手撸一个日历支持范围选择带背景色

11次阅读

共计 19172 个字符,预计需要花费 48 分钟才能阅读完成。

  • 一个支持范围选择的日历(移动端)

需求原型:
1、日历默认显示当前月,并且标注当日的日期,当日以后得日期置灰不可以选择。
2、日历支持选择某单个日期和范围选择,并且选中的两个日期之间要加背景色。
3、限制最多选择 6 个月,超出六个月提示“最多选择 6 个月”,并且日历滚动到选择的起始日期位置,保留开始日期的选中效果,继续选择结束日期。
4、在显示周的元素下面,要有个显示当前滚动到的年月的元素并带有动画效果。
demo 采用的是 rem 布局。
需求大概就是这个样子,下面贴代码咯:

  • 具体实现逻辑

index.html


    <!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title> 日历 </title>
    <meta name="viewport" content="width=device-width, user-scalable=no">
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">
    <meta name="viewport"
        content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no,viewport-fit=cover">
    <meta content="telephone=no" name="format-detection" />
    <title>Document</title>
    <link rel="stylesheet" href="./base.css">
    <link rel="stylesheet" href="./calnder.css">
</head>

<body>
    <div class="header-top" id="header-top" v-show="controlState === 2" v-cloak>
        <div class="control-box">
            <span> 日历范围选择 </span>
            <span class="close__btn" @click="closeCalendar"></span>
        </div>
        <ul id="week-item"></ul>
        <div class="current-time">
            <input type="text" id="current-time" readonly>
        </div>
    </div>
    <div class="main">
        <div class="mode-one" id="mode-one">
            <div id="week-box"></div>
        </div>
        <div class="calendar__dialog"> 最多可选六个月,请重新选择!</div>
        <div class="footer-box">
            <div class="confirm-btn"> 确定 </div>
        </div>
    </div>
    <script src="./resize.js"></script>
    <script src="./utils.js"></script>
    <script>
        // 默认显示当前月
        window.scrollTo(0, document.body.scrollHeight);

        let startYear = 2010;
        let $Yday = Utils.getElement('.j-year-day');
        let $Yhour = Utils.getElement('.j-year-hour');
        let $Dh = Utils.getElement('.j-day-h');
        let $Dm = Utils.getElement('.j-day-m');
        let $Ds = Utils.getElement('.j-day-s');
        let $CurrentTime = Utils.getElement('.j-time');
        let vm = {timeArr: []
        }
        let date = new Date()
        let year = date.getFullYear();
        let thisMonth = date.getMonth();
        let thisDay = date.getDate();
        let dayS = 24 * 60 * 60;
        let dateS = date.getTime();
        let dateEndS = new Date(year, 11, 31, 23, 59, 59).getTime();
        let weeks = ['日', '一', '二', '三', '四', '五', '六'];
        let dayStr = '';
        let dayItem = '';
        for (let i = 0; i < weeks.length; i++) {dayItem += '<li class="week-item">' + weeks[i] + '</li>'
        }
        let ulContent = Utils.getElement('.header-top ul');
        ulContent.innerHTML = dayItem;

        // 立即生成日历 html
        ;(function createCalendar(y) {let calnderBody = Utils.getElement('.mode-one');
            for (y; y <= year; y++) {calnderBody.innerHTML = handelYear(y);
            }
        })(startYear)

        // 循环月份
        function handelYear(y) {for (let month = 0; month <= 11; month++) {if (y === year) {if (month > thisMonth) break;
                }
                // 每个月的第一天
                let firstDay = new Date(y, month, 1);
                let dayInMonth = daysInMonth(month, y);
                // 每个月的最后一天
                let lastDay = new Date(y, month, dayInMonth);

                let weekday = firstDay.getDay(); // 星期几 0-6
                let lastDayWeekDay = lastDay.getDay(); // 当月的最后一天星期几 0-6
                let date = 1; // 第一天,计数用
                let showMonth = month + 1;
                let newMonth = Utils.timePad(showMonth)
                dayStr += '<div class="current-month">' + y + '年' + newMonth + '月 </div><div class="month">';
                // 补齐前面的空格
                for (let i = 0; i < weekday; i++) {dayStr += '<div class="item"></div>';}
                for (; date <= dayInMonth; date++) {
                    let copyDate = date;
                    let newDate = Utils.timePad(copyDate)
                    if (month == thisMonth && date == thisDay && y == year) {dayStr += '<div class="item now dateItem"data-disabled=' + (date > thisDay) +
                            'data-current=' + y + '-' + newMonth + '-' + newDate + '>' + date + '</div>';
                    } else if (month == thisMonth && y == year) {// data-disabled='+ (date > thisDay) +'
                        dayStr += '<div class="item dateItem"data-disabled=' + (date > thisDay) + 'data-current=' +
                            y + '-' + newMonth + '-' + newDate + '>' + date + '</div>';
                    } else {
                        dayStr += '<div class="item dateItem"data-current=' + y + '-' + newMonth + '-' + newDate +
                            '>' + date + '</div>';
                    }
                    weekday++
                    if (weekday % 7 == 0) {weekday = 0;}
                }
                // 补齐后面的空格
                for (let j = 0; j < (7 - lastDayWeekDay - 1); j++) {dayStr += '<div class="item"></div>';}
                // dayStr += '<br/></div>';
                dayStr += '<p class="after-dom"data-time=' + y + '年' + newMonth + '月 ></p></div>';
            }
            return dayStr
        }
        
        document.body.onclick = function (ev) {
            let e = ev || window.event;
            checkActive();
            let currBox = Utils.getElement('.current-time #current-time');
            // 如果不是 iphone 7plus 和 iphonex 机型 要加一个月
            if (currBox) {if (isIphonex()) {currBox.value = year + '年' + Utils.timePad(thisMonth) + '月'
                } else if (getPhoneType().replace(/\s*/g, "") ==='iphone6' || getPhoneType().replace(/\s*/g, "") ==='iphone5s' && !isIphonex()) {currBox.value = year + '年' + Utils.timePad(thisMonth + 1) + '月';
                } else if (getPhoneType() === 'iphone6 plus') {currBox.value = year + '年' + Utils.timePad(thisMonth + 1) + '月';

                } else {currBox.value = year + '年' + Utils.timePad(thisMonth) + '月';
                }
            }
        }
        // 监听滚动条事件
        document.addEventListener('scroll', handelEvent, false)

        function handelEvent(e) {scrollFunc();
            let monthBox = Utils.getAllElement('.current-month'),
                currBox = Utils.getElement('.current-time #current-time');
            let monthBoxList = Utils.getAllElement('.after-dom');
            let top = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
            _Set('scrollTop', top)
            if (scrollDirection == 'down') {
                // 判断 月盒子是否和头部日期盒子重叠,如果重叠就显示当前月的时间
                let listenCurTime = [];
                handelTitleAnimate(listenCurTime, monthBox, currBox, 'pushDown', 'pushUp', 1)
            } else if (scrollDirection == 'up') {
                // 判断每个月的盒子是否和头部日期盒子重叠
                let listenCurTime = [];
                handelTitleAnimate(listenCurTime, monthBoxList, currBox, 'pushUp', 'pushDown', 2);
            }

        }
        // 处理滑动时候,头部日期动画效果
        function handelTitleAnimate(arr, ele, ele1, class1, class2, type) {// let arr = [];
            for (let i = 0; i < ele.length; i++) {if (collision(ele1, ele[i])) {if (type === 1) {ele1.value = ele[i].innerText;
                        arr.push(ele1.value)
                    } else {ele1.value = ele[i].getAttribute('data-time');
                        arr.push(ele1.value);
                    }
                }
            }
            if (arr.length) {ele1.classList.remove(class1);
                ele1.classList.add(class2);
            } else {ele1.classList.remove(class2);
            }
        }
        // 点击每个日期事件
        function getCurrnetTime() {let itemDay = document.querySelectorAll('.month .dateItem');
            let items;
            for (let i = 0, len = itemDay.length; i < len; i++) {items = itemDay[i];
                if (items.dataset.disabled === 'true') {items.classList.add('disabled')
                }
                document.onclick = function (ev) {
                    let e = ev || window.event;
                    let target = e.target || e.srcElement;
                    let confirmBtn = Utils.getElement('.footer-box div');
                    if (target.classList.contains('dateItem') === true) {
                        let now = target.dataset.current;
                        let isAllowChose = target.dataset.disabled;
                        // 如果是今天之后的日期,点击无效
                        if (isAllowChose === 'true') return;
                        if (vm.timeArr.length < 2) {vm.timeArr.push(now)
                            target.classList.add('active');
                            if (vm.timeArr.length > 1) {
                                // scopeValue 表示选中的日期范围值
                                let scopeValue = getAll(vm.timeArr[0], vm.timeArr[1]);
                                // 比较选中两个日期的大小,如果是倒序选择的,就重新选
                                // result 表示是否是正序选择
                                let result = CompareDate(vm.timeArr[0], vm.timeArr[1]);
                                if (!result) {checkClass('active');
                                    vm.timeArr.splice(0, 1)
                                    target.classList.add('active')
                                } else {
                                    // 选中的日期范围去匹配相应的 dom,加 class
                                    handelClass(scopeValue, undefined);
                                }
                                handelFinalBox(vm.timeArr[0], vm.timeArr[1], vm.timeArr);

                            }

                        } else {(vm.timeArr = [], vm.timeArr.push(now));
                            checkClass('active');
                            handelFinalBox(vm.timeArr[0], vm.timeArr[1], vm.timeArr)
                            target.classList.add('active')
                        }
                        if (vm.timeArr.length == 1) {confirmBtn.classList.add('cover_back')
                            handelClass(undefined, vm.timeArr);
                            createVal(vm.timeArr);
                            vm.maxDate = calcDate(vm.timeArr[0]);
                            _Set('lastTop', _Get('scrollTop'))

                        } else if (vm.timeArr.length == 2) {
                            // 拼接选择日期值
                            createVal(vm.timeArr)
                            // 判断如果超出可选范围,就提示重新选择
                            if (CompareDate(vm.maxDate, vm.timeArr[1])) {
                                // 清除选中的日期,只保留第一个选择值,currentChose 存第一次选择的值,让 timeArr 的值和本地存储的值都变成第一个选中的值
                                window.scrollTo(0, _Get('lastTop'));
                                Utils.getElement('.calendar__dialog').style.display = 'block'
                                vm.timeArr = [];
                                checkClass('l-border');
                                checkClass('r-border');
                                checkClass('cover-background');
                                var data = _Get('currentChose')[0];
                                vm.timeArr.push(data)
                                _Set('currentChose', data.split());
                                _Set('choseValue', data.split()[0]);
                                target.classList.remove('active')
                                setTimeout(function () {Utils.getElement('.calendar__dialog').style.display = 'none'
                                }, 2000);
                            }

                        } else {confirmBtn.classList.add('cover_back')
                        }

                    }
                    // 点击确定按钮,需清楚选中的日期值
                    confirmBtn.onclick = function (e) {if (!e.target.classList.contains('cover_back')) return;
                        handelClass(undefined, vm.timeArr);
                        console.log(vm.timeArr)

                    }
                }
            }
        }

        getCurrnetTime();
        function setDisabled() {let endDate = calcDate(vm.timeArr[0]);
            // leftDom 表示结束日期,之后所有的 dom 只是当前 6 个月可以选择,超出范围不能选择;// 计算出当前日期和 endDate 的区间
            let canChose = getAll(vm.timeArr[0], endDate);
            let itemDay = document.querySelectorAll('.month .dateItem');
            for (let i = 0, len = itemDay.length; i < len; i++) {let every = itemDay[i].getAttribute('data-current'),
                    ele = itemDay[i];
                if (canChose.indexOf(every) < 0) {ele.classList.add('disabled')
                    ele.setAttribute('data-disabled', true)
                } else {ele.classList.remove('disabled')
                    ele.setAttribute('data-disabled', false)
                }
            }
        }
        // 拼接选中日期值
        function createVal(arr) {
            // 如果不跨年,就不显示年份
            if (arr.length === 1) {let finalArr = arr[0];
                _Set('choseValue', finalArr);
                _Set('currentChose', vm.timeArr);
            } else if (arr.length === 2) {// 拼接选择日期值 ["2018-12-26","2019-02-26"]
                let containValue = arr[0] + '至' + arr[1];
                _Set('choseValue', containValue);
                _Set('currentChose', vm.timeArr);
            }
        }
        // 检测是否含有某个 class
        function checkClass(str) {let itemDay = document.querySelectorAll('.dateItem');
            for (let i = 0; i < itemDay.length; i++) {let item = itemDay[i];
                if (item.classList.contains(str) == true) {item.classList.remove(str);
                }
            }
        }

        // 给选中范围内的日期加 class
        function handelClass(arr, choseArr) {let itemDay = document.querySelectorAll('.dateItem');
            for (let i = 0; i < itemDay.length; i++) {if (arr) {let item = itemDay[i].getAttribute('data-current');
                    if (arr.indexOf(item) > -1) {itemDay[i].classList.add('cover-background');
                    }
                }
                if (choseArr) {if (choseArr.length == 1 || !choseArr.length) {itemDay[i].classList.remove('cover-background');
                    }
                }
            }
        }
        // 处理选中两个日期后圆角问题
        function handelFinalBox(fValue, eValue, itemArr) {let itemDay = document.querySelectorAll('.dateItem');
            for (let i = 0; i < itemDay.length; i++) {let item = itemDay[i].getAttribute('data-current');
                // 如果选择两个
                if (itemArr.length > 1) {if (item === fValue && itemArr.length > 1) {itemDay[i].classList.add('l-border');
                    }
                    if (item === eValue && itemArr.length > 1) {itemDay[i].classList.add('r-border');
                    }
                } else {itemDay[i].classList.remove('l-border');
                    itemDay[i].classList.remove('r-border');
                }
            }
        }
        // init 页面时候,处理添加 active 和 cover-backgoround 类名
        function checkActive() {
            let doc = document,
                itemDay = doc.querySelectorAll('.month .dateItem'),
                item;
            if (_Get('currentChose')) {let currentChose = _Get('currentChose');
                let arrLi = doc.querySelectorAll('.month .dateItem');
                Array.prototype.forEach.call(arrLi, function (ele) {let curr = ele.getAttribute('data-current');
                    if (currentChose.length === 1) {
                        // 选择单个日期的情况
                        if (curr === currentChose[0]) {ele.classList.add('active')
                        }
                    } else if (currentChose.length === 2) {let scopeValue = getAll(currentChose[0], currentChose[1]);
                        // 如果是选中范围的情况
                        if (scopeValue.indexOf(curr) > -1) {ele.classList.add('cover-background');
                            // 如果选择两个
                            if (currentChose.length > 1) {if (curr === currentChose[0] && currentChose.length > 1) {ele.classList.add('l-border');
                                }
                                if (curr === currentChose[1] && currentChose.length > 1) {ele.classList.add('r-border');
                                }
                            } else {ele.classList.remove('l-border');
                                ele.classList.remove('r-border');
                            }
                        }
                    }
                })

            }
        }
    </script>
</body>

</html>

base.css


    html, body {
    width: 100%;
    height: 100%;
  }
  
  #app {
    width: 100%;
    height: 100%;
  }
  
  article,
  aside,
  details,
  figcaption,
  figure,
  footer,
  header,
  hgroup,
  menu,
  nav,
  section {display: block;}
  
  input,
  select,
  textarea {font-size: 100%;}
  
  th {text-align: inherit;}
  
  a img,
  fieldset,
  img {border: 0;}
  
  ol,
  ul {list-style: none;}
  
  caption,
  th {text-align: left;}
  
  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    font-size: 100%;
    font-weight: 500;
  }
  
  a:hover {text-decoration: underline;}
  
  a,
  ins {text-decoration: none;}
  
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }
  
  ::-webkit-input-placeholder {color: #939799;}
  
  :-moz-placeholder {color: #939799;}
  
  ::-moz-placeholder {color: #939799;}
  
  input::-ms-clear, input::-ms-reveal {display: none;}
  
  @media screen and (max-width: 1024px) {
    #app {
      width: auto;
      height: auto;
    }
    .continer {
      position: relative !important;
      width: 100%;
      height: 100% !important;
      display: flex;
      justify-content: center;
      padding-top: 70px !important;
      padding-bottom: 170px;
    }
  }
  
  @media screen and (min-width: 1025px) {
    #app {
      width: 100% !important;
      height: 100% !important;
    }
  }
  

calnder.css


    
.header-top {
    position: fixed;
    top: 0;
    left: 0;
    background: #fff;
    width: 100%;
    z-index: 999;
  }
  
  .header-top .control-box {
    width: 100%;
    height: 1.6rem;
    font-size: 0.42667rem;
    font-weight: 400;
    color: #363c54;
    padding: 0.53333rem 0.8rem 0.53333rem 0.66667rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  
  .header-top .control-box span:nth-child(2) {
    display: inline-block;
    width: 0.53333rem;
    height: 0.53333rem;
    /* background: url("../static/images/close.png") no-repeat center; */
    background-size: cover;
  }
  
  .header-top .pushUp {
    animation: moveDown .5s  alternate;
    -webkit-animation: moveDown .5s  alternate;
    -moz-animation: moveDown .5s  alternate;
    -o-animation: moveDown .5s  alternate;
    -ms-animation: moveDown .5s  alternate;
  }
  
  .header-top .pushDown {
    animation: moveUp .5s  alternate;
    -webkit-animation: moveUp .5s  alternate;
    -moz-animation: moveUp .5s  alternate;
    -o-animation: moveUp .5s  alternate;
    -ms-animation: moveUp .5s  alternate;
  }
  
  @keyframes moveUp {
    0% {transform: translateY(-0.8rem);
    }
    50% {transform: translateY(0.53333rem);
    }
    100% {transform: translateY(0);
    }
  }
  
  @keyframes moveDown {
    0% {transform: translateY(-0.8rem);
    }
    50% { }
    100% {transform: translateY(0);
    }
  }
  
  .header-top #week-item {
    width: 90%;
    height: 1.06667rem;
    list-style: none;
    display: flex;
    text-align: center;
    justify-content: space-around;
    align-items: center;
    margin: 0 auto;
    position: relative;
    background: #fff;
    z-index: 10;
    padding-right: 0.34667rem;
  }
  
  .header-top #week-item::after {
    background-color: #f0f1f2;
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 1px;
    transform-origin: 0 0;
  }
  
  .header-top #week-item li {
    font-size: 0.37333rem;
    font-weight: 400;
    color: #363c54;
  }
  
  .header-top .current-time {
    width: 100%;
    text-align: center;
    font-size: 0.37333rem;
    font-weight: 400;
    color: #9b9da9;
    background: #fff;
  }
  
  .header-top .current-time #current-time {
    height: 1.04rem;
    line-height: 1.04rem;
    text-align: center;
    font-size: 0.37333rem;
    font-weight: 400;
    color: #9b9da9;
    border: none;
    background: #fff;
    transition: .3s all;
    border-color: transparent;
    -webkit-appearance: none;
  }
  
  .main {
    width: 100%;
    height: 100%;
  }
  
  .main .current-month {
    width: 90%;
    height: 1.06667rem;
    line-height: 1.06667rem;
    font-size: 0.37333rem;
    font-weight: 400;
    text-align: center;
    margin: 0.13333rem auto;
    color: #9b9da9;
    position: relative;
  }
  
  .main .current-month::before {
    background-color: #f0f1f2;
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 1px;
    transform-origin: 0 0;
  }
  
  .main .l-border {border-radius: 50% 0 0 50% !important;}
  
  .main .r-border {border-radius: 0 50% 50% 0 !important;}
  .main .calendar__dialog{
      display: none;
      width: 7.73333rem;
      height: 1.73333rem;
      line-height: 1.73333rem;
      background: rgba(0, 0, 0, 0.8);
      border-radius: 0.13333rem;
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      text-align: center;
      font-size: 0.42667rem;
      font-weight: 400;
      color: white;
      z-index: 999;
  }
  
  .mode-one {
    width: 100%;
    align-content: space-between;
    margin-top: 2.93333rem;
    background: #fff;
    padding-bottom: 2rem;
  }
  
  .mode-one .month {
    position: relative;
    color: #141414;
    width: 100%;
    padding: 0 0.64rem 0 0.72rem;
  }
  
  .mode-one .month .after-dom {
    width: 100%;
    height: 1rem;
    position: absolute;
    left: 0;
    bottom: 0;
    z-index: 10;
  }
  
  .mode-one .dateItem {cursor: pointer;}
  
  .mode-one .disabled {color: #cdced4 !important;}
  
  .mode-one .cover-background {background: #20c997;}
  
  .mode-one .month .item {
    display: inline-block;
    width: 1.2rem;
    height: 1.2rem;
    font-size: 0.37333rem;
    line-height: 1.2rem;
    font-weight: 400;
    text-align: center;
    vertical-align: middle;
    position: relative;
    color: #363C54;
    margin: 0.12rem 0;
    z-index: 11;
  }
  
  .mode-one .now::after {
    background-color: #20c997;
    content: "";
    position: absolute;
    left: 50%;
    margin-left: -1.5px;
    bottom: 3px;
    width: 3px;
    height: 3px;
    border-radius: 50%;
    transform-origin: 0 0;
  }
  
  .mode-one .month .active {
    background: #20c997;
    border-radius: 50%;
  }
  
  .calendar-content {
    width: 100%;
    height: 100%;
    overflow: scroll;
  }
  
  .calendar__box {
    width: 100%;
    height: 100%;
    z-index: 998;
  }
  
  .footer-box {
    width: 100%;
    height: 2rem;
    background: white;
    position: fixed;
    left: 0;
    bottom: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    -webkit-transform: translateZ(0);
    margin-top: 2rem;
    z-index: 12;
  }
  
  .footer-box div {
    width: 8.66667rem;
    height: 1.2rem;
    line-height: 1.2rem;
    background: #CDCED4;
    border-radius: 0.6rem;
    text-align: center;
    font-size: 0.42667rem;
    font-weight: 400;
    color: white;
  }
  
  .cover_back {background: #20c997 !important;}
  
  .hideCalendar {
    transition: .3 all;
    transform: translateX(-100%, 0) !important;
  }
  

resize.js

; (function () {resize()
    window.onresize = resize;
})()    

function resize () {if (document.documentElement.clientWidth >= 750) {
        document.documentElement.style.fontSize = '75px';
        return
    }
    document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px'
}

utils.js


    let Utils = {getElement(selector) {return document.querySelector(selector);
    },
    getAllElement(selector) {return document.querySelectorAll(selector);
    },
    timePad(time) {return time < 10 ? '0' + time : time;}
}
function daysInMonth(month, year) {return new Date(year, month + 1, 0).getDate();}

function _Set(data_id, data) {if (data_id != "") {if (data) {
            var lsobj = window.localStorage;
            var datajson = JSON.stringify(data);
            lsobj.setItem(data_id, datajson);
        }
    }
}

function _Get(data_id) {if (data_id != "") {
        var data = null;
        var lsdata = window.localStorage;
        try {var datajson = lsdata.getItem(data_id);
            datajson = JSON.parse(datajson);
            data = datajson;
        } catch (e) { } finally {return data;}
    }
}


let scrollAction = {
    x: 'undefined',
    y: 'undefined'
},
scrollDirection;

// 判断页面滚动方向
function scrollFunc() {if (typeof scrollAction.x == 'undefined') {
    scrollAction.x = window.pageXOffset;
    scrollAction.y = window.pageYOffset;
}
let diffX = scrollAction.x - window.pageXOffset;
let diffY = scrollAction.y - window.pageYOffset;
if (diffX < 0) {
    // Scroll right
    scrollDirection = 'right';
} else if (diffX > 0) {
    // Scroll left
    scrollDirection = 'left';
} else if (diffY < 0) {
    // Scroll down
    scrollDirection = 'down';
} else if (diffY > 0) {
    // Scroll up
    scrollDirection = 'up';
} else {// First scroll event}
scrollAction.x = window.pageXOffset;
scrollAction.y = window.pageYOffset;
};

// 检测两个 div 是否重叠
function collision(target, current) {
    let targetX = target.offsetLeft;
    let targetY = target.offsetTop;
    let targetW = target.offsetWidth;
    let targetH = target.offsetHeight;
    let currentX = current.offsetLeft;
    let currentY = current.getBoundingClientRect().top;
    let currentW = current.offsetWidth;
    let currentH = current.offsetHeight;
    return (targetX + targetW > currentX && targetX < currentX + currentW && targetY + targetH > currentY &&
        targetY < currentY + currentH);
}

// 计算当前选择日期往后推 6 个月
function calcDate(str) {str = str.replace(/-/g, '/');
    let date = new Date(str);
    // 日期转文本方式一:let year = date.getFullYear(); // 年
    let month = date.getMonth() + 7; // 月 + 6 个月  因为 js 里 month 从 0 开始,所以要加 1
    if (month > 12) {
        year++;
        month -= 12;
    }
    let date2 = new Date(year, month, 0); // 新的年月
    let day1 = date.getDate();
    let day2 = date2.getDate();
    if (day1 > day2) { // 防止 + 6 月后没有 31 天
        day1 = day2;
    }
    str = year + '-' +
        Utils.timePad(month) +
        '-' +
        Utils.timePad(day1);
    return str;
}

// 获取两个日期之间的值
Date.prototype.format = function () {
    let s = '';
    let mouth = (this.getMonth() + 1) >= 10 ? (this.getMonth() + 1) : ('0' + (this.getMonth() + 1));
    let day = this.getDate() >= 10 ? this.getDate() : ('0' + this.getDate());
    s += this.getFullYear() + '-'; // 获取年份。s += mouth + "-"; // 获取月份。s += day; // 获取日。return (s); // 返回日期。};
// 获取两个日期之间的值
function getAll(begin, end) {let arr = [];
    let ab = begin.split("-");
    let ae = end.split("-");
    let db = new Date();
    db.setUTCFullYear(ab[0], ab[1] - 1, ab[2]);
    let de = new Date();
    de.setUTCFullYear(ae[0], ae[1] - 1, ae[2]);
    let unixDb = db.getTime() - 24 * 60 * 60 * 1000;
    let unixDe = de.getTime() - 24 * 60 * 60 * 1000;
    for (let k = unixDb; k <= unixDe;) {//console.log((new Date(parseInt(k))).format());
        k = k + 24 * 60 * 60 * 1000;
        arr.push((new Date(parseInt(k))).format());
    }
    return arr;
}
// 比较两个日期大小
function CompareDate(d1, d2) {return ((new Date(d1.replace(/-/g, "\/"))) < (new Date(d2.replace(/-/g, "\/"))));
}

function getPhoneType() {
    // 正则, 忽略大小写
    var pattern_phone = new RegExp("iphone", "i");
    var pattern_android = new RegExp("Android", "i");
    var userAgent = navigator.userAgent.toLowerCase();
    var isAndroid = pattern_android.test(userAgent);
    var isIphone = pattern_phone.test(userAgent);
    var phoneType = "phoneType";
    if (isAndroid) {var zh_cnIndex = userAgent.indexOf("-");
        var spaceIndex = userAgent.indexOf("build", zh_cnIndex + 4);
        var fullResult = userAgent.substring(zh_cnIndex, spaceIndex);
        phoneType = fullResult.split(";")[1];
    } else if (isIphone) {
        //6   w=375    6plus w=414   5s w=320     5 w=320
        var wigth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
        if (wigth > 400) {phoneType = "iphone6 plus";} else if (wigth > 370) {phoneType = "iphone6";} else if (wigth > 315) {phoneType = "iphone5s";} else {phoneType = "iphone 4s";}
    } else {phoneType = "您的设备太先进了";}
    return phoneType;
}

function isIphonex() {if (typeof window !== 'undefined' && window) {return /iphone/gi.test(window.navigator.userAgent) && window.screen.height >= 812;
    }
    return false;
}

end ···
代码有待优化,日后再说吧

正文完
 0