├── pages ├── logs │ ├── logs.wxss │ ├── logs.json │ ├── logs.wxml │ └── logs.js └── index │ ├── index.json │ ├── index.wxss │ ├── index.wxml │ └── index.js ├── My-calendar ├── my-calendar.json ├── icon │ ├── iconfont.eot │ ├── iconfont.ttf │ ├── iconfont.woff │ ├── iconfont.woff2 │ ├── iconfont.svg │ └── iconfont.wxss ├── my-calendar.wxss ├── my-calendar.wxml └── my-calendar.js ├── README ├── GIF.gif ├── img │ ├── code.png │ ├── css.png │ ├── js.png │ ├── logo.png │ ├── wxml.png │ ├── code2.png │ ├── 指定日期选择.gif │ ├── 简单日期选择.gif │ ├── 自定义主题.gif │ ├── 基本日期范围选择.gif │ ├── 指定日期选择带文本.gif │ ├── 指定范围日期选择.gif │ └── 指定范围日期范围选择.gif └── oldReadme.md ├── sitemap.json ├── app.wxss ├── app.json ├── project.config.json ├── app.js └── README.md /pages/logs/logs.wxss: -------------------------------------------------------------------------------- 1 | /* pages/logs/logs.wxss */ -------------------------------------------------------------------------------- /pages/logs/logs.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {} 3 | } -------------------------------------------------------------------------------- /My-calendar/my-calendar.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /README/GIF.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/GIF.gif -------------------------------------------------------------------------------- /pages/logs/logs.wxml: -------------------------------------------------------------------------------- 1 | 2 | pages/logs/logs.wxml 3 | -------------------------------------------------------------------------------- /README/img/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/code.png -------------------------------------------------------------------------------- /README/img/css.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/css.png -------------------------------------------------------------------------------- /README/img/js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/js.png -------------------------------------------------------------------------------- /README/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/logo.png -------------------------------------------------------------------------------- /README/img/wxml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/wxml.png -------------------------------------------------------------------------------- /README/img/code2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/code2.png -------------------------------------------------------------------------------- /README/img/指定日期选择.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/指定日期选择.gif -------------------------------------------------------------------------------- /README/img/简单日期选择.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/简单日期选择.gif -------------------------------------------------------------------------------- /README/img/自定义主题.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/自定义主题.gif -------------------------------------------------------------------------------- /README/img/基本日期范围选择.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/基本日期范围选择.gif -------------------------------------------------------------------------------- /README/img/指定日期选择带文本.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/指定日期选择带文本.gif -------------------------------------------------------------------------------- /README/img/指定范围日期选择.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/指定范围日期选择.gif -------------------------------------------------------------------------------- /README/img/指定范围日期范围选择.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/README/img/指定范围日期范围选择.gif -------------------------------------------------------------------------------- /My-calendar/icon/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/My-calendar/icon/iconfont.eot -------------------------------------------------------------------------------- /My-calendar/icon/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/My-calendar/icon/iconfont.ttf -------------------------------------------------------------------------------- /My-calendar/icon/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/My-calendar/icon/iconfont.woff -------------------------------------------------------------------------------- /My-calendar/icon/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4freeman/my-calendar/HEAD/My-calendar/icon/iconfont.woff2 -------------------------------------------------------------------------------- /pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "my-calendar": "../../My-calendar/my-calendar" 4 | } 5 | } -------------------------------------------------------------------------------- /pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | page{ 2 | padding: 16px; 3 | box-sizing: border-box; 4 | } 5 | radio-group{ 6 | margin-bottom: 16px; 7 | } -------------------------------------------------------------------------------- /sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | .container { 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | justify-content: space-between; 8 | padding: 200rpx 0; 9 | box-sizing: border-box; 10 | } 11 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/index/index", 4 | "pages/logs/logs" 5 | ], 6 | "window": { 7 | "backgroundTextStyle": "light", 8 | "navigationBarBackgroundColor": "#fff", 9 | "navigationBarTitleText": "WeChat", 10 | "navigationBarTextStyle": "black" 11 | }, 12 | "sitemapLocation": "sitemap.json" 13 | } -------------------------------------------------------------------------------- /pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true, 12 | "autoAudits": false 13 | }, 14 | "compileType": "miniprogram", 15 | "libVersion": "2.7.2", 16 | "appid": "wxf3548f3bda8cc26b", 17 | "projectname": "wxapp-demo", 18 | "debugOptions": { 19 | "hidedInDevtools": [] 20 | }, 21 | "isGameTourist": false, 22 | "simulatorType": "wechat", 23 | "simulatorPluginLibVersion": {}, 24 | "condition": { 25 | "search": { 26 | "current": -1, 27 | "list": [] 28 | }, 29 | "conversation": { 30 | "current": -1, 31 | "list": [] 32 | }, 33 | "game": { 34 | "currentL": -1, 35 | "list": [] 36 | }, 37 | "miniprogram": { 38 | "current": -1, 39 | "list": [] 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /pages/logs/logs.js: -------------------------------------------------------------------------------- 1 | // pages/logs/logs.js 2 | Page({ 3 | 4 | /** 5 | * 页面的初始数据 6 | */ 7 | data: { 8 | 9 | }, 10 | 11 | /** 12 | * 生命周期函数--监听页面加载 13 | */ 14 | onLoad: function (options) { 15 | 16 | }, 17 | 18 | /** 19 | * 生命周期函数--监听页面初次渲染完成 20 | */ 21 | onReady: function () { 22 | 23 | }, 24 | 25 | /** 26 | * 生命周期函数--监听页面显示 27 | */ 28 | onShow: function () { 29 | 30 | }, 31 | 32 | /** 33 | * 生命周期函数--监听页面隐藏 34 | */ 35 | onHide: function () { 36 | 37 | }, 38 | 39 | /** 40 | * 生命周期函数--监听页面卸载 41 | */ 42 | onUnload: function () { 43 | 44 | }, 45 | 46 | /** 47 | * 页面相关事件处理函数--监听用户下拉动作 48 | */ 49 | onPullDownRefresh: function () { 50 | 51 | }, 52 | 53 | /** 54 | * 页面上拉触底事件的处理函数 55 | */ 56 | onReachBottom: function () { 57 | 58 | }, 59 | 60 | /** 61 | * 用户点击右上角分享 62 | */ 63 | onShareAppMessage: function () { 64 | 65 | } 66 | }) -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | // 展示本地存储能力 5 | var logs = wx.getStorageSync('logs') || [] 6 | logs.unshift(Date.now()) 7 | wx.setStorageSync('logs', logs) 8 | 9 | // 登录 10 | wx.login({ 11 | success: res => { 12 | // 发送 res.code 到后台换取 openId, sessionKey, unionId 13 | } 14 | }) 15 | // 获取用户信息 16 | wx.getSetting({ 17 | success: res => { 18 | if (res.authSetting['scope.userInfo']) { 19 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 20 | wx.getUserInfo({ 21 | success: res => { 22 | // 可以将 res 发送给后台解码出 unionId 23 | this.globalData.userInfo = res.userInfo 24 | 25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 26 | // 所以此处加入 callback 以防止这种情况 27 | if (this.userInfoReadyCallback) { 28 | this.userInfoReadyCallback(res) 29 | } 30 | } 31 | }) 32 | } 33 | } 34 | }) 35 | }, 36 | globalData: { 37 | userInfo: null 38 | } 39 | }) -------------------------------------------------------------------------------- /My-calendar/icon/iconfont.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Created by iconfont 9 | 10 | 11 | 12 | 13 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /pages/index/index.js: -------------------------------------------------------------------------------- 1 | Page({ 2 | data: { 3 | start: "", 4 | stop: "", 5 | theme: null, 6 | themes: { 7 | green: { 8 | bg: "#67C23A", 9 | fontColor: "#fff", 10 | rangeStartColor: "#F56C6C", 11 | rangeColor: "#fde2f2", 12 | rangeEndColor: "#F56C6C" 13 | }, 14 | pink: { 15 | bg: "#F56C6C", 16 | fontColor: "#fff", 17 | rangeStartColor: "#67C23A", 18 | rangeColor: "#e1f3d8", 19 | rangeEndColor: "#67C23A" 20 | }, 21 | blue: { 22 | bg: "#409efe", 23 | fontColor: "#fff", 24 | rangeStartColor: "#79bbff", 25 | rangeColor: "#b3d8ff", 26 | rangeEndColor: "#79bbff" 27 | } 28 | }, 29 | items: [ 30 | { name: 'green', value: '绿色', checked: true }, 31 | { name: 'pink', value: '粉色' }, 32 | { name: 'blue', value: '蓝色' } 33 | ] 34 | }, 35 | onLoad () { 36 | this.setData({ 37 | theme: this.data.themes.green 38 | }); 39 | }, 40 | 41 | radioChange: function (e) { 42 | this.setData({ 43 | theme: this.data.themes[e.detail.value] 44 | }); 45 | }, 46 | 47 | select ({detail: {begin: {text: brgin}, over: {text: over}}}) { 48 | this.setData({ 49 | start: begin, 50 | stop: over 51 | }); 52 | } 53 | }) -------------------------------------------------------------------------------- /README/oldReadme.md: -------------------------------------------------------------------------------- 1 | # 小程序日期、日期范围选择 日历组件 2 | *这不是最新版本,最新版本点这里* 3 | 4 | *效果如图:* 5 | 6 | ![avatar](./GIF.gif) 7 | 8 | ## 如何使用 9 | 按照小程序官方组件说明,引入该仓库下的My-calendar组件即可 10 | 11 | ## 属性 12 | ||属性名|参数类型|是否必选|说明|可选值|默认值| 13 | |-|-|-|-|-|-|-| 14 | |1|useType|\|no|指定选择类型(range范围选择、touch日期选择)| range\touch|range| 15 | |2|confirmText|\|no|确认按钮显示文本||| 16 | |3|confirmType|\|no|指定选择完成时机(end选择完成即触发confirm、button点击确认按钮才触发confirm)|end\button|end| 17 | |4|date|\|no|单选模式时用作指定默认选择日期(字符必须为xxxx-xx-xx格式)||| 18 | |5|start|\|no|范围选择模式时用作指定默认范围开始日期,必须为xxxx-xx-xx格式字符串||| 19 | |6|stop|\|no|范围选择模式时用作指定默认范围结束日期,必须为xxxx-xx-xx格式字符串||| 20 | |7|min|\|no|起始选择最小日期限制,必须为xxxx-xx-xx格式字符串或“now”,为now时表示起始范围不得小于今天|now|| 21 | |8|max|\|no|起始选择最大日期限制,必须为xxxx-xx-xx格式字符串||| 22 | 23 | 24 | ## 事件 25 | ||事件名|说明|携带参数| 26 | |-|-|-|-| 27 | |1|cancel|点击取消按钮触发的事件| | 28 | |1|confirm|点击确定按钮触发的事件| 详见下方代码 | 29 | 30 | ```javascript 31 | /* 32 | *confirm事件携带参数 33 | */ 34 | 35 | //日期范围选择模式时 36 | detail: { 37 | begin: { 38 | text: "2002-12-12", 39 | time: "324234234",//时间戳 40 | }, 41 | over: { 42 | text: "2002-12-22", 43 | time: "2342342342",//时间戳 44 | } 45 | } 46 | //日期单选模式时 47 | detail: { 48 | text: "xxxx-xx-xx", 49 | time: "1234123123",//时间戳 50 | } 51 | 52 | ``` 53 | 54 | *水平有限,欢迎指点和star(fork的兄弟,都fork了就帮我点个star吧~~)* 55 | -------------------------------------------------------------------------------- /My-calendar/icon/iconfont.wxss: -------------------------------------------------------------------------------- 1 | @font-face {font-family: "iconfont"; 2 | src: url('iconfont.eot?t=1561384157179'); /* IE9 */ 3 | src: url('iconfont.eot?t=1561384157179#iefix') format('embedded-opentype'), /* IE6-IE8 */ 4 | url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAKwAAsAAAAABogAAAJkAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgpweAE2AiQDDAsIAAQgBYRtBzgbwAXIrrApw/VIoPayHkPcWD/A7eMdyBmLh//2+98+M3PvNxHwJLq6iKTfqRBVQrESqYQKoeCR/PZ/Lg/YqDxflqcINsW6kPz+ltOMHAtHRk7PiAl5E26wAQfhghrgpvOte66/rwtuc7Ml6Be3z3M5vQl0IPPb2Tlda9DY0496AcYBBboHRpGVUBqAZrK2DTAyTvun9wm0mmRoH9ucXrRGinBZILa08lujTkZR9HqzUE/sLeKFSnN6mIrnxefjj50xIqmycO3xu+uoNfuBG/mx8ehyRsgS+HCFjHUthbg6WTmvK3Suq9XZW26vFSGdlW+cwui565f+8RJRC3vbwTJXEz9yohD82DgggQzqbm1Yy7Rg+39NiPb2e703Hwbp88GQ+vp4i/efB/Djfn/0/unPdPrdqSZ/nFt9s+y+zrn0L118J4Hg8bVf69q3UQr4tvf/kTwF7m5+ZTT4RSZwqHiW0JuLY0yMQSxrB0IJ1oy4hjDR62+/ewAeJDQb2BFrMtEgazZPFnYdlTa7UWt2EK3WbA+36cO6orRg1RshdPtG0ukLsm6/ZGGPqAz6R607umh1NvrObLMYenKU0ReMIHgAHZYFxX6ZlP1nqG4yn9uWgr9CbnQeXMvp17dYIJ+xoblVnggBcZnDhh7DLCuh4jLBUKxYpJraNk29yArLvDVxFEM+gSIg8ABooVKBsvFiMnj/GaTcyPh4QddVX0GsoacHLosDkFtnAem+5ZnGLcUjBAGElXJgQ7NQJlMC1fSsBAoJS7yjVJmyo1GEOq373fn3nYBW4bU5UuQoqi0k8QasVSxuqwUAAA==') format('woff2'), 5 | url('iconfont.woff?t=1561384157179') format('woff'), 6 | url('iconfont.ttf?t=1561384157179') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ 7 | url('iconfont.svg?t=1561384157179#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family: "iconfont" !important; 12 | /* font-size: 16px; */ 13 | font-style: normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-left2:before { 19 | content: "\e703"; 20 | } 21 | 22 | .icon-right1:before { 23 | content: "\e72d"; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /My-calendar/my-calendar.wxss: -------------------------------------------------------------------------------- 1 | @import "./icon/iconfont.wxss"; 2 | .my-calendar{ 3 | width:100%; 4 | height:auto; 5 | padding: 16px; 6 | box-sizing: border-box; 7 | background: #32bdda; 8 | /* border-radius: 4px; */ 9 | } 10 | 11 | /* 第一行取消、确认 */ 12 | .my-calendar .tools{ 13 | height:16px; 14 | width: 100%; 15 | display: flex; 16 | justify-content: space-between; 17 | } 18 | .my-calendar .tools view{ 19 | font-family:PingFangSC-Regular; 20 | font-weight:400; 21 | /* color:rgba(255,255,255,1); */ 22 | line-height:16px; 23 | font-size:16px; 24 | 25 | } 26 | 27 | /* 第二行 月数选择 */ 28 | .month-select{ 29 | height: 18px; 30 | width: 100%; 31 | display: flex; 32 | justify-content: space-between; 33 | align-items: center; 34 | margin-top:20px; 35 | } 36 | .month-select .icon-wrap{ 37 | height: 18px; 38 | width: 18px; 39 | display: flex; 40 | justify-content: space-around; 41 | align-items: center; 42 | } 43 | .month-select .icon{ 44 | height:11px; 45 | font-size: 11px; 46 | /* background: red */ 47 | } 48 | .month-select .text-wrap{ 49 | display: flex; 50 | align-items: center; 51 | justify-content: space-around; 52 | flex-grow: 1; 53 | } 54 | .month-select .text{ 55 | font-size:18px; 56 | font-family:PingFangSC-Semibold; 57 | font-weight:600; 58 | /* color:rgba(255,255,255,1); */ 59 | line-height:18px; 60 | } 61 | 62 | /* 第三行 星期显示 */ 63 | .week-show{ 64 | height:16px; 65 | overflow: hidden; 66 | margin-top:15px; 67 | display: flex; 68 | justify-content: space-around; 69 | } 70 | .week-show .child{ 71 | height: 16px; 72 | line-height: 16px; 73 | width: 14.28%; 74 | text-align: center; 75 | 76 | font-family:PingFangSC-Regular; 77 | font-weight:400; 78 | /* color:rgba(255,255,255,1); */ 79 | font-size:16px; 80 | } 81 | 82 | /* 第四行 日期显示以及选择 */ 83 | .day-wrap{ 84 | width:100%; 85 | height: auto; 86 | margin-top:18px; 87 | overflow: hidden; 88 | } 89 | .day-wrap .spacing{ 90 | float: left; 91 | width:14.28%; 92 | padding-bottom:14.28%; 93 | } 94 | .day-wrap .day{ 95 | float: left; 96 | width:14.28%; 97 | text-align: center; 98 | padding-bottom:14.28%; 99 | overflow: hidden; 100 | position: relative; 101 | margin: 1% 0; 102 | } 103 | .day-wrap .day .day-inside-wrap{ 104 | position: absolute; 105 | left:0;top:0; 106 | height:100%; 107 | width: 100%; 108 | border-radius: 100%; 109 | } 110 | .day-wrap .day .day-inside{ 111 | width: 100%; 112 | height: auto; 113 | position: absolute; 114 | left: 50%;top:50%; 115 | transform: translate(-50%, -50%); 116 | 117 | font-size:16px; 118 | font-family:PingFangSC-Regular; 119 | font-weight:400; 120 | /* color:rgba(255,255,255,1); */ 121 | } 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | /*为范围时候的样式类*/ 132 | .day-wrap .range{ 133 | border-radius:0; 134 | /* background: rgba(255,255,255,0.5); */ 135 | } 136 | .day-wrap .range .day-inside{ 137 | /* color:rgba(56,185,212,1); */ 138 | } 139 | 140 | /*为范围左侧开头时*/ 141 | .day-wrap .range-left{ 142 | border-radius:0; 143 | border-top-left-radius: 50%; 144 | border-bottom-left-radius: 50%; 145 | /* background: rgba(255,255,255,0.5); */ 146 | } 147 | .day-wrap .range-left .day-inside{ 148 | /* color:rgba(56,185,212,1); */ 149 | } 150 | 151 | /*为范围中间时*/ 152 | .day-wrap .range-center{ 153 | border-radius:100%; 154 | background: rgba(255,255,255,0.5); 155 | } 156 | .day-wrap .range-center .day-inside{ 157 | color:rgba(56,185,212,1); 158 | } 159 | 160 | /*为范围右侧开头时*/ 161 | .day-wrap .range-right{ 162 | border-radius:0; 163 | border-top-right-radius: 50%; 164 | border-bottom-right-radius: 50%; 165 | /* background: rgba(255,255,255,0.5); */ 166 | } 167 | .day-wrap .range-right .day-inside{ 168 | /* color:rgba(56,185,212,1); */ 169 | } 170 | 171 | /*为范围选开始位置时样式*/ 172 | .day-wrap .start{ 173 | border-top-left-radius: 50%; 174 | border-bottom-left-radius: 50%; 175 | /* background: rgba(255,255,255,0.5); */ 176 | position: relative; 177 | } 178 | .day-wrap .start .day-inside-wrap{ 179 | /* background: #fff; */ 180 | } 181 | .day-wrap .start .day-inside{ 182 | /* color:rgba(56,185,212,1); */ 183 | } 184 | 185 | /*仅选开始位置时样式*/ 186 | .day-wrap .start-only{ 187 | border-radius: 100%; 188 | /* background: rgba(255,255,255,0.5); */ 189 | /* position: relative; */ 190 | } 191 | .day-wrap .start-only .day-inside-wrap{ 192 | /* background: #fff; */ 193 | } 194 | .day-wrap .start-only .day-inside{ 195 | /* color:rgba(56,185,212,1); */ 196 | } 197 | 198 | /*为范围选结束位置时样式*/ 199 | .day-wrap .stop{ 200 | border-top-right-radius: 50%; 201 | border-bottom-right-radius: 50%; 202 | /* background: rgba(255,255,255,0.5); */ 203 | position: relative; 204 | } 205 | .day-wrap .stop .day-inside-wrap{ 206 | /* background: #fff; */ 207 | } 208 | .day-wrap .stop .day-inside{ 209 | /* color:rgba(56,185,212,1); */ 210 | } 211 | 212 | /*仅选结束位置时样式*/ 213 | .day-wrap .stop-only{ 214 | border-radius: 100%; 215 | /* background: rgba(255,255,255,0.5); */ 216 | /* position: relative; */ 217 | } 218 | .day-wrap .stop-only .day-inside-wrap{ 219 | /* background: #fff; */ 220 | } 221 | .day-wrap .stop-only .day-inside{ 222 | /* color:rgba(56,185,212,1); */ 223 | } 224 | 225 | 226 | /*为日期单选择时候*/ 227 | .day-wrap .point{ 228 | /* background:rgba(255,106,40,1); */ 229 | border-radius: 100%; 230 | /* color: #fff; */ 231 | } 232 | 233 | /* 指定actives日期选择时 ,在单选模式选中样式基础上改为了方形 */ 234 | .day-wrap .actives-point{ 235 | /* background:rgba(255,106,40,1); */ 236 | border-radius: 2px; 237 | /* color: #fff; */ 238 | } -------------------------------------------------------------------------------- /My-calendar/my-calendar.wxml: -------------------------------------------------------------------------------- 1 | 37 | 38 | 39 | 40 | 41 | 42 | 取消 43 | {{title}} 44 | {{confirmText}} 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {{nowDate.text}} 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 周日 75 | 周一 76 | 周二 77 | 周三 78 | 周四 79 | 周五 80 | 周六 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | {{item.date}} 99 | 100 | 101 | 102 | 103 | 106 | 109 | {{item.date}} 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | {{item.date}} 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | {{item.date}} 133 | 134 | {{item.text}} 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # My-calendar 小程序日历组件 2 | 若看不见展示图片请[点击这里](https://gitee.com/lilin123/my-calendar) 3 | 4 | ![图片看不见请翻墙](./README/img/logo.png) 5 | 6 | ## 应用场景展示 7 | 8 | ### 1.基本日期选择 9 | ![图片看不见请翻墙](./README/img/简单日期选择.gif) 10 |
11 | 查看源码 12 | 13 |
14 | 15 | 16 | ```html 17 | 18 | 19 | 20 | 29 | ``` 30 | 31 | 32 | ```js 33 | Page({ 34 | data: { 35 | date: "", 36 | calendarShow: false, 37 | }, 38 | select ({detail}) { 39 | this.setData({ date: detail.text }); 40 | this.offCalendar(); 41 | }, 42 | openCalendar () { 43 | this.setData({calendarShow: true}); 44 | }, 45 | offCalendar () { 46 | this.setData({ calendarShow: false }); 47 | } 48 | }); 49 | ``` 50 |
51 | 52 | ### 2.指定日期选择 53 | ![图片看不见请翻墙](./README/img/指定日期选择.gif) 54 |
55 | 查看源码 56 | 57 |
58 | 59 | 60 | ```html 61 | 62 | 63 | 72 | ``` 73 | 74 | 75 | ```js 76 | Page({ 77 | data: { 78 | actives: ["2019-06-23", "2019-06-25", "2019-06-30"],/*指定允许选择的日期*/ 79 | date: "", 80 | calendarShow: false, 81 | }, 82 | select ({detail}) { 83 | this.setData({ date: detail.text }); 84 | this.offCalendar(); 85 | }, 86 | openCalendar () { 87 | this.setData({calendarShow: true}); 88 | }, 89 | offCalendar () { 90 | this.setData({ calendarShow: false }); 91 | } 92 | }); 93 | ``` 94 | 95 |
96 | 97 | ### 3.指定日期选择带文本 98 | ![图片看不见请翻墙](./README/img/指定日期选择带文本.gif) 99 |
100 | 查看源码 101 | 102 |
103 | 104 | 105 | ```html 106 | 107 | 108 | 117 | ``` 118 | 119 | 120 | ```js 121 | Page({ 122 | data: { 123 | actives: [ 124 | {date: "2019-06-24", text: "¥1333.3"}, //每个单元增加了text属性用于定义需要显示的文本 125 | {date: "2019-06-25", text: "¥998.01"}, 126 | {date: "2019-06-26", text: "¥998.01"}, 127 | {date: "2019-06-27", text: "¥998.01"} 128 | ], 129 | date: "", 130 | calendarShow: false, 131 | }, 132 | select ({detail}) { 133 | this.setData({ date: detail.text }); 134 | this.offCalendar(); 135 | }, 136 | openCalendar () { 137 | this.setData({calendarShow: true}); 138 | }, 139 | offCalendar () { 140 | this.setData({ calendarShow: false }); 141 | } 142 | }); 143 | ``` 144 |
145 | 146 | ### 4.指定范围日期选择 147 | ![图片看不见请翻墙](./README/img/指定范围日期选择.gif) 148 |
149 | 查看源码 150 | 151 |
152 | 153 | 154 | ```html 155 | 156 | 157 | 169 | ``` 170 | 171 | 172 | ```js 173 | Page({ 174 | data: { 175 | date: "", 176 | calendarShow: false, 177 | }, 178 | select ({detail :{text}}) { 179 | this.setData({ 180 | date: text 181 | }); 182 | this.offCalendar(); 183 | }, 184 | openCalendar () { 185 | this.setData({calendarShow: true}); 186 | }, 187 | offCalendar () { 188 | this.setData({ calendarShow: false }); 189 | } 190 | }); 191 | ``` 192 | 193 |
194 | 195 | 196 | ### 5.基本日期范围选择 197 | ![图片看不见请翻墙](./README/img/基本日期范围选择.gif) 198 |
199 | 查看源码 200 | 201 |
202 | 203 | 204 | ```html 205 | 206 | 207 | 208 | 217 | ``` 218 | 219 | 220 | ```js 221 | Page({ 222 | data: { 223 | start: "", 224 | stop: "", 225 | calendarShow: false, 226 | }, 227 | select ({detail :{begin: {text:begin}, over: {text: over}}}) { 228 | console.log(begin, over); 229 | this.setData({ 230 | start: begin, 231 | stop: over 232 | }); 233 | this.offCalendar(); 234 | }, 235 | openCalendar () { 236 | this.setData({calendarShow: true}); 237 | }, 238 | offCalendar () { 239 | this.setData({ calendarShow: false }); 240 | } 241 | }); 242 | 243 | ``` 244 |
245 | 246 | ### 6.指定范围日期范围选择 247 | ![图片看不见请翻墙](./README/img/指定范围日期范围选择.gif) 248 |
249 | 查看源码 250 | 251 |
252 | 253 | 254 | ```html 255 | 256 | 257 | 258 | 269 | 270 | ``` 271 | 272 | 273 | ```js 274 | Page({ 275 | data: { 276 | start: "", 277 | stop: "", 278 | calendarShow: false 279 | }, 280 | select ({detail :{begin: {text: begin}, over: {text: over}}}) { 281 | console.log(begin, over); 282 | this.setData({ 283 | start: begin, 284 | stop: over 285 | }); 286 | this.offCalendar(); 287 | }, 288 | openCalendar () { 289 | this.setData({ calendarShow: true }); 290 | }, 291 | offCalendar () { 292 | this.setData({ calendarShow: false }); 293 | } 294 | }); 295 | ``` 296 |
297 | 298 | ### 7.自定义主题 299 | ![图片看不见请翻墙](./README/img/自定义主题.gif) 300 | 301 | *^-^我不是ui,配色大家随便看就行* 302 |
303 | 查看源码 304 | 305 |
306 | 307 | 308 | ```html 309 | 310 | 313 | 314 | 315 | 327 | ``` 328 | 329 | 330 | ```js 331 | Page({ 332 | data: { 333 | start: "", 334 | stop: "", 335 | theme: null, 336 | themes: { 337 | green: { 338 | bg: "#67C23A", 339 | fontColor: "#fff", 340 | rangeStartColor: "#F56C6C", 341 | rangeColor: "#fde2f2", 342 | rangeEndColor: "#F56C6C" 343 | }, 344 | pink: { 345 | bg: "#F56C6C", 346 | fontColor: "#fff", 347 | rangeStartColor: "#67C23A", 348 | rangeColor: "#e1f3d8", 349 | rangeEndColor: "#67C23A" 350 | }, 351 | blue: { 352 | bg: "#409efe", 353 | fontColor: "#fff", 354 | rangeStartColor: "#79bbff", 355 | rangeColor: "#b3d8ff", 356 | rangeEndColor: "#79bbff" 357 | } 358 | }, 359 | items: [ 360 | { name: 'green', value: '绿色', checked: true }, 361 | { name: 'pink', value: '粉色' }, 362 | { name: 'blue', value: '蓝色' } 363 | ] 364 | }, 365 | onLoad () { 366 | this.setData({ 367 | theme: this.data.themes.green 368 | }); 369 | }, 370 | 371 | radioChange: function (e) { 372 | this.setData({ 373 | theme: this.data.themes[e.detail.value] 374 | }); 375 | }, 376 | 377 | select ({detail: {begin: {text: brgin}, over: {text: over}}}) { 378 | this.setData({ 379 | start: begin, 380 | stop: over 381 | }); 382 | } 383 | }) 384 | ``` 385 |
386 | 387 |
388 |
389 | 390 | ## 属性、事件 391 | ### 1.通用属性 392 | |属性|说明|数据类型|默认值|可选值|备注/注意| 393 | |-|-|-|-|-|-| 394 | |title|标题|String|-|-|-| 395 | |useType|使用模式|String|"range"|"range"、"touch"|touch为日期单选模式,range为日期范围选择模式|-| 396 | |isChangeYear|是否启用年份切换|Boolean|false|-|-| 397 | |confirmText|确认按钮文本|String|"确定"|-|-| 398 | |confirmType|指定什么时候触发confirm事件|String|"button"|"button"、"end"|为button时表示要点击确定按钮才触发confirm,为end时选择结束就触发confirm| 399 | |min|设置最小选择日期(含)|String|-|"now"|格式必须为日期字符串如: xxxx-xx-xx, 为now时候表示以今天为最小选择日期起始| 400 | |max|设置最大选择日期(含)|String|-|-|格式必须为日期字符串如: xxxx-xx-xx| 401 | 402 | ### 2.日期单选模式属性 403 | |属性|说明|数据类型|默认值|可选值|备注/注意| 404 | |-|-|-|-|-|-| 405 | |date|初始化选中日期|String|-|-|格式必须为日期字符串如: xxxx-xx-xx| 406 | |actives|指定可选择日期|Array|-|-|普通用法["xxx-xx-xx", ...];显示文本用法[{date: "xxxx-xx-xx", text: "¥998,,0"}, ...]| 407 | 408 | ### 3.日期范围选择模式属性 409 | |属性|说明|数据类型|默认值|可选值|备注/注意| 410 | |-|-|-|-|-|-| 411 | |start|指定范围开始选中|String|-|-|格式必须为日期字符串如: xxxx-xx-xx| 412 | |stop|指定范围结束选中|String|-|-|格式必须为日期字符串如: xxxx-xx-xx| 413 | 414 | ### 4.主题属性 415 | |属性|说明|数据类型|默认值|可选值|备注/注意| 416 | |-|-|-|-|-|-| 417 | |background|背景颜色|String|-|-|css\wxss支持的颜色都可以| 418 | |isShadow|是否显示阴影|Boolean|true|true、false|-| 419 | |isRound|是否显示圆角|Boolean|true|true、false|-| 420 | |touchColor|日期单选选中的颜色|String|-|-|css\wxss支持的颜色都可以| 421 | |rangeStartColor|日期范围选择起始选中颜色|String|-|-|css\wxss支持的颜色都可以| 422 | |rangeColor|日期范围选中起始和结束之间的颜色|String|-|-|css\wxss支持的颜色都可以| 423 | |rangeEndColor|日期范围选择结束选中颜色|String|-|-|css\wxss支持的颜色都可以| 424 | |fontColor|字体颜色|String|-|-|css\wxss支持的颜色都可以| 425 | 426 | ### 5.事件 427 | |事件|说明|参数|参数类型|备注/注意| 428 | |-|-|-|-|-| 429 | |cancel|点击取消按钮触发|-|-|没有传参| 430 | |confirm|点击确定或选择完成时候触发|{detail: {*}}|Object|日期范围选择模式、日期单选模式参数不同,请看下面的代码| 431 | ```js 432 | /** 433 | * @description confirm事件的携带参数说明 434 | */ 435 | 436 | //为日期单选模式时 437 | { 438 | detail: { 439 | text: "2019-12-12", 440 | time: 111111 //时间戳 441 | } 442 | } 443 | 444 | //为日期范围选择模式时 445 | { 446 | detail: { 447 | begin: { 448 | text: "2019-12-12", 449 | time: 111111 450 | }, 451 | over: { 452 | text: "2019-12-13", 453 | time: 111111 454 | } 455 | } 456 | } 457 | ``` 458 | -------------------------------------------------------------------------------- /My-calendar/my-calendar.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | 3 | properties: { 4 | /** 5 | * @description 背景颜色 6 | */ 7 | background:{ 8 | type: String, 9 | value: "#fff", 10 | }, 11 | /** 12 | * @description 是否需要阴影 13 | */ 14 | isShadow: { 15 | type: Boolean, 16 | value: true, 17 | }, 18 | /** 19 | * @description 是否圆角 20 | */ 21 | isRound: { 22 | type: Boolean, 23 | value: true 24 | }, 25 | /** 26 | * @description 字体颜色 27 | */ 28 | fontColor: { 29 | type: String, 30 | value: "#000" 31 | }, 32 | /** 33 | * @description 日期单选模式下选中的日期颜色 34 | */ 35 | touchColor: { 36 | type: String, 37 | value: "#409efe" 38 | }, 39 | /** 40 | * @description 日期范围选择模式下,范围开始日期的颜色 41 | */ 42 | rangeStartColor: { 43 | type: String, 44 | value: "#409efe" 45 | }, 46 | /** 47 | * @description 日期范围选择模式下,处于范围之间的日期颜色 48 | */ 49 | rangeColor: { 50 | type: String, 51 | value: "#a0cfff" 52 | }, 53 | /** 54 | * @description 日期范围选择模式下,范围结束的日期颜色 55 | */ 56 | rangeEndColor: { 57 | type: String, 58 | value: "#409efe" 59 | }, 60 | /** 61 | * @deacription 标题 62 | */ 63 | title: { 64 | type: String, 65 | value: "标题" 66 | }, 67 | /** 68 | * @description 使用类型(范围选择还是仅选择日期) [ "touch" | "range" ] 69 | */ 70 | useType: { 71 | type: String, 72 | value: "range", 73 | observer: function(newV, oldV){ 74 | if(oldV != ""){ 75 | this.init(); 76 | } 77 | } 78 | }, 79 | /** 80 | * @description 是否启用年份切换 81 | */ 82 | isChangeYear: { 83 | type: Boolean, 84 | value: false 85 | }, 86 | /** 87 | * @description 确定按钮文字 88 | */ 89 | confirmText: { 90 | type: String, 91 | value: "确定" 92 | }, 93 | /** 94 | * @description 完成类型,分为选择出发完成 和 点击按钮出发完成 95 | */ 96 | confirmType: { 97 | type: String, 98 | value: "button",//可选button和end 99 | }, 100 | /** 101 | * @description 起始日期(useType === 'range'时可用) 102 | */ 103 | start: { 104 | type: String, 105 | value: "", 106 | observer: function(newV, oldV){ 107 | if(oldV != ""){//判断不让第一次初始化时候触发更新动作 108 | this.initRange(); 109 | } 110 | } 111 | }, 112 | /** 113 | * @description 结束日期(useType === 'range'时可用) 114 | */ 115 | stop: { 116 | type: String, 117 | value: "", 118 | observer: function(newV, oldV){ 119 | if(oldV != ""){//判断不让第一次初始化时候触发更新动作 120 | this.initRange(); 121 | } 122 | } 123 | }, 124 | /** 125 | * @description 最小选择日期 126 | */ 127 | min: { 128 | type: String, 129 | value: "" 130 | }, 131 | /** 132 | * @description 最大选择日期 133 | */ 134 | max: { 135 | type: String, 136 | value: "" 137 | }, 138 | /** 139 | * @description 指定可选日期(单选多选都可用) 140 | */ 141 | actives: { 142 | type: Array, 143 | value: null 144 | }, 145 | /** 146 | * @description 单选模式日期 147 | */ 148 | date: { 149 | type: String, 150 | value: "", 151 | observer: function(newV, oldV) { 152 | if (oldV != "" && this.properties.useType === "touch") { 153 | this.initTouch(); 154 | } 155 | } 156 | } 157 | 158 | }, 159 | 160 | data: { 161 | 162 | begin: 0,//选择开始日期时间戳 163 | over: 0,//选择结束日期时间戳 164 | touch: 0,//为单选模式时候选择的日期 165 | spacingNum: 0,//日历开头空格数量 166 | days: [],//当月日期数据 167 | nowDate: { 168 | text: "", 169 | Y: 0, 170 | M: 0 171 | }, 172 | activesChildType: null//单选模式下,actives传值子元素类型标记 173 | 174 | }, 175 | 176 | ready () { 177 | this.init(); 178 | }, 179 | 180 | methods: { 181 | 182 | /** 183 | * @description 初始化 184 | */ 185 | init () { 186 | //单选模式 187 | if(this.properties.useType === "touch"){ 188 | this.setData({type: "touch"}); 189 | this.initTouch(); 190 | } 191 | //范围选择模式 192 | if(this.properties.useType === "range"){ 193 | this.setData({ type: "range" }); 194 | this.initRange(); 195 | } 196 | }, 197 | 198 | /** 199 | * @description 单选初始化 200 | */ 201 | initTouch () { 202 | if(this.properties.date === ""){ 203 | this.setData({touch: ""}); 204 | this.setMonth(); 205 | }else{ 206 | if(!/^\d{4}-\d{2}-\d{2}$/.test(this.properties.date)){ 207 | console.warn("[日历组件警告] 要使date传参生效,其值必须为xxxx-xx-xx日期字符串"); 208 | this.setMonth(); 209 | this.getMonthData(); 210 | return; 211 | } 212 | const arr = this.properties.date.split("-"), 213 | date = new Date(arr[0], arr[1] - 1, arr[2]); 214 | this.setData({touch: date.getTime()}); 215 | this.setMonth(date.getFullYear(), date.getMonth()); 216 | } 217 | this.getMonthData(); 218 | }, 219 | 220 | /** 221 | * @description 范围选择初始化 222 | */ 223 | initRange () { 224 | //显示开始日期 225 | if(this.properties.start === ""){ 226 | this.setData({begin: 0}); 227 | this.setMonth(); 228 | }else{ 229 | if (!/^\d{4}-\d{2}-\d{2}$/.test(this.properties.start)) { 230 | throw new Error("[日历组件报错] start传参错误,必须为xxxx-xx-xx日期字符串"); 231 | } 232 | const arr = this.properties.start.split("-"), 233 | date = new Date(arr[0], arr[1] - 1, arr[2]); 234 | this.setData({begin: date.getTime()}); 235 | this.setMonth(date.getFullYear(), date.getMonth()); 236 | } 237 | //显示结束日期 238 | if(this.properties.stop === ""){ 239 | this.setData({over: 0}); 240 | }else{ 241 | if (!/^\d{4}-\d{2}-\d{2}$/.test(this.properties.stop)) { 242 | throw new Error("[日历组件报错] stop传参错误,必须为xxxx-xx-xx日期字符串"); 243 | } 244 | const arr = this.properties.stop.split("-"), 245 | date = new Date(arr[0], arr[1] - 1, arr[2]); 246 | if(date.getTime() <= this.data.begin){//结束小于等于开始 247 | this.setData({over: 0 }); 248 | }else{ 249 | this.setData({over: date.getTime() }); 250 | } 251 | } 252 | this.getMonthData(); 253 | }, 254 | 255 | /** 256 | * @description 设置当前显示月份 257 | * @param {Number} y 年份 258 | * @param {Number} m 月份 259 | */ 260 | setMonth (y, m) { 261 | if(y && m){ 262 | const 263 | obj = new Date(y, m, 1), 264 | Y = obj.getFullYear(), 265 | M = obj.getMonth() + 1 < 10 ? "0" + (obj.getMonth() + 1) : obj.getMonth() + 1; 266 | this.setData({ 267 | ["nowDate.text"]: `${Y}-${M}`, 268 | ["nowDate.Y"]: obj.getFullYear(), 269 | ["nowDate.M"]: obj.getMonth() + 1, 270 | }); 271 | }else{ 272 | const 273 | obj = new Date(), 274 | Y = obj.getFullYear(), 275 | M = obj.getMonth() + 1 < 10 ? "0" + (obj.getMonth() + 1) : obj.getMonth() + 1; 276 | this.setData({ 277 | ["nowDate.text"]: `${Y}-${M}`, 278 | ["nowDate.Y"]: obj.getFullYear(), 279 | ["nowDate.M"]: obj.getMonth() + 1, 280 | }); 281 | } 282 | }, 283 | 284 | /** 285 | * @description 月份切换 286 | */ 287 | addOrSubMonth ({target:{dataset:{status}}}) { 288 | const 289 | Y = this.data.nowDate.Y, 290 | M = this.data.nowDate.M; 291 | if(status === "+"){ 292 | if(M === 12){ 293 | this.setData({ 294 | ["nowDate.Y"]: Y + 1, 295 | ["nowDate.M"]: 1, 296 | ["nowDate.text"]: `${Y + 1}-${1}` 297 | }); 298 | }else{ 299 | this.setData({ 300 | ["nowDate.M"]: M + 1, 301 | ["nowDate.text"]: `${Y}-${M + 1}` 302 | }); 303 | } 304 | } 305 | if(status === "-"){ 306 | if(M === 1){ 307 | this.setData({ 308 | ["nowDate.Y"]: Y - 1, 309 | ["nowDate.M"]: 12, 310 | ["nowDate.text"]: `${Y - 1}-${12}` 311 | }); 312 | }else{ 313 | this.setData({ 314 | ["nowDate.M"]: M - 1, 315 | ["nowDate.text"]: `${Y}-${M - 1}` 316 | }); 317 | } 318 | } 319 | //执行获取天数的函数 320 | this.getMonthData(); 321 | }, 322 | 323 | /** 324 | * @description 年份切换 325 | */ 326 | addOrSubYear ({target:{dataset:{status}}}) { 327 | const 328 | Y = this.data.nowDate.Y, 329 | M = this.data.nowDate.M; 330 | if (status === "-"){ 331 | this.setData({ 332 | ["nowDate.Y"]: Y - 1, 333 | ["nowDate.text"]: `${Y - 1}-${M}` 334 | }); 335 | } 336 | if (status === "+"){ 337 | this.setData({ 338 | ["nowDate.Y"]: Y + 1, 339 | ["nowDate.text"]: `${Y + 1}-${M}` 340 | }); 341 | } 342 | //执行获取天数的函数 343 | this.getMonthData(); 344 | }, 345 | 346 | /** 347 | * @description 获取月份里数据 348 | */ 349 | getMonthData () { 350 | //获取当前选择的date对象 351 | const 352 | Y = this.data.nowDate.Y, 353 | M = this.data.nowDate.M, 354 | obj = new Date(Y, M - 1, 1); 355 | //获取并设置日历开头空格数量 356 | obj.setDate(1); 357 | const Day = obj.getDay(); 358 | if(Day > 6){ 359 | this.setData({spacingNum: 0}); 360 | }else{ 361 | this.setData({spacingNum: Day}); 362 | } 363 | //获取该月每天对象 364 | obj.setMonth( M );//这里的M已经加过1了 365 | obj.setDate(0); 366 | const 367 | dayNum = obj.getDate(), 368 | days = []; 369 | obj.setMonth(M - 1); 370 | for(let i = 0; i < dayNum; i++){ 371 | obj.setDate(i + 1); 372 | const day = { 373 | date: i + 1,//号数 374 | day: obj.getDay(),//星期几 375 | time: obj.getTime(),//毫秒时间戳 376 | type: "",//选中类型 377 | } 378 | days.push(day); 379 | } 380 | this.setData({days: days}); 381 | 382 | //执行设置min-max处理 383 | this.setMinMax(); 384 | //执行设置actives处理 385 | this.setActives(); 386 | //执行渲染样式 387 | this.renderStyle(); 388 | }, 389 | 390 | /** 391 | * @description 设置月份里mix-max选择范围 392 | */ 393 | setMinMax () { 394 | console.log(this.properties.actives); 395 | if (this.properties.actives && (this.properties.min || this.properties.max)) { 396 | this.throwErr("min、max属性不能跟actives属性同时使用"); 397 | return; 398 | } 399 | if(!this.properties.min && !this.properties.max){ 400 | return; 401 | } 402 | if(!/^\d{4}-\d{2}-\d{2}$/.test(this.properties.min) && this.properties.min != "now" && !this.properties.min != ""){ 403 | console.warn("min属性只能为日期字符串或'now'"); 404 | return; 405 | } 406 | if(!/^\d{4}-\d{2}-\d{2}$/.test(this.properties.max) && this.properties.max != ""){ 407 | console.warn("max属性只能为日期字符串"); 408 | return; 409 | } 410 | if(this.properties.min != "" && this.properties.max != ""){ 411 | let minArr = this.properties.min.split("-"), maxArr = this.properties.max.split("-"); 412 | if(new Date(minArr[0],minArr[1]-1, minArr[2]).getTime() >= new Date(maxArr[0], maxArr[1]-1, maxArr[2]).getTime() ){ 413 | console.warn("max不能小于或等于min"); 414 | return; 415 | } 416 | } 417 | let days = this.data.days; 418 | if(this.properties.min == "now"){ 419 | let nowDate = new Date(); 420 | nowDate.setHours(0); 421 | nowDate.setMinutes(0); 422 | nowDate.setSeconds(0); 423 | nowDate.setMilliseconds(0); 424 | let minTime = nowDate.getTime(), maxTime = ""; 425 | if(this.properties.max != ""){ 426 | let arr = this.properties.max.split("-"); 427 | maxTime = new Date(arr[0], arr[1] - 1, arr[2]).getTime(); 428 | } 429 | days.forEach(day=>{ 430 | if(day.time < minTime){ 431 | day.hide = true; 432 | } 433 | if(maxTime != ""){ 434 | if(day.time > maxTime){ 435 | day.hide = true; 436 | } 437 | } 438 | }); 439 | this.setData({days: days}); 440 | }else{ 441 | let minTime = "", maxTime = ""; 442 | if(this.properties.min != ""){ 443 | let arr = this.properties.min.split("-"); 444 | minTime = new Date(arr[0], arr[1] - 1, arr[2]).getTime(); 445 | } 446 | if(this.properties.max != ""){ 447 | let arr = this.properties.max.split("-"); 448 | maxTime = new Date(arr[0], arr[1] - 1, arr[2]).getTime(); 449 | } 450 | days.forEach(day=>{ 451 | if(minTime != ""){ 452 | if(day.time < minTime){ 453 | day.hide = true; 454 | } 455 | } 456 | if(maxTime != ""){ 457 | if(day.time > maxTime){ 458 | day.hide = true; 459 | } 460 | } 461 | }); 462 | this.setData({days: days});//更新days 463 | } 464 | }, 465 | 466 | /** 467 | * @description 设置月份里actives选择范围 468 | */ 469 | setActives () { 470 | if (this.properties.useType === "range" && this.properties.actives) { 471 | this.throwErr("actives属性只能用于日期单选模式"); 472 | return; 473 | } 474 | 475 | let actives = this.properties.actives; 476 | 477 | //检查参数,类型不对则退出执行,如果数组为空则全部不允许选择 478 | if (!(actives instanceof Array)) return; 479 | if (actives.length === 0) { 480 | let days = this.data.days; 481 | days.forEach(day=>{ 482 | day.hide = true; 483 | }); 484 | return; 485 | } 486 | 487 | //判断actives参数元素类型,并设置data中的标记; ‘xxxx-xx-xx’ or {date: xxxx-xx-xx, price: 123.00} 两种类型 488 | { 489 | let isString = true, isObj = true; 490 | for(let i of actives){ 491 | if(typeof i === "string"){ 492 | isObj = false; 493 | } 494 | if(typeof i === "object"){ 495 | isString = false; 496 | } 497 | } 498 | if(!isString && !isObj) { 499 | this.throwErr("actives传参子元素只能为日期字符串或对象,请参阅相关说明"); 500 | return; 501 | } 502 | if(isString) this.setData({activesChildType: "string"}); 503 | if(isObj) this.setData({activesChildType: "object"}); 504 | } 505 | 506 | //actives可能横跨多个月,截取当前所选择月份的actives元素,为后面的算法省时间 507 | let _actives = []; 508 | actives.forEach(date => { 509 | let _arr = [], _Y, _M, _D; 510 | if(this.data.activesChildType === "string"){ 511 | _arr = date.split("-"), _Y = _arr[0], _M = _arr[1], _D = _arr[2]; 512 | } 513 | if(this.data.activesChildType === "object"){ 514 | _arr = date.date.split("-"), _Y = _arr[0], _M = _arr[1], _D = _arr[2]; 515 | } 516 | if( (_Y == this.data.nowDate.Y) && (_M == this.data.nowDate.M) ){ 517 | _actives.push({dayNum: _D, text: date.text || ""}); 518 | } 519 | }); 520 | 521 | //设置当月actives 设置当月那些天与actives里的数据匹配,则可以选择,反之不可以选择 522 | let days = this.data.days, daysClone = JSON.parse(JSON.stringify(days)); 523 | days.forEach(day=>{day.hide = true});//当月所有天都先初始化为不可选择 524 | for (let i = 0; i < daysClone.length; i++) { // !!! 这个循环时间复杂度还可以优化,后面再考虑 525 | 526 | for (let j = 0; j < _actives.length; j++) { 527 | if (daysClone[i].date == _actives[j].dayNum) {//如果当月某天与_actives中的某天匹配,则将当月某天设置为可以选择,后续循环将不再匹配当月的这一天 528 | days[i].hide = false; 529 | this.data.activesChildType === "object" && (days[i].text = _actives[j].text); 530 | daysClone.splice(i, 1, null); 531 | break; 532 | } 533 | } 534 | 535 | } 536 | 537 | //更新days 538 | this.setData({days: days}); 539 | }, 540 | 541 | /** 542 | * @description 范围选择回调 543 | */ 544 | select ({target:{dataset:{index}}}) { 545 | //选择起点 546 | if(this.data.begin == 0 || this.data.over != 0){ 547 | this.setData({ 548 | begin: this.data.days[index].time, 549 | over: 0 550 | }); 551 | this.renderStyle(); 552 | } 553 | //选择结束点 554 | else{ 555 | //当选择的结束日期小于等于开始日期时,则重置开始日期为当前选择 556 | if(this.data.days[index].time <= this.data.begin){ 557 | this.setData({ 558 | begin: this.data.days[index].time, 559 | over: 0 560 | }); 561 | this.renderStyle(); 562 | return; 563 | } 564 | this.setData({over: this.data.days[index].time}); 565 | this.renderStyle(); 566 | 567 | //confirmType为end时触发事件流程处理 568 | if(this.properties.confirmType == "end"){ 569 | this.triggerEvent("confirm", { 570 | begin:{ 571 | text: this.timeToString(this.data.begin), 572 | time: this.data.begin 573 | }, 574 | over: { 575 | text: this.timeToString(this.data.over), 576 | time: this.data.over 577 | } 578 | }); 579 | } 580 | } 581 | }, 582 | 583 | /** 584 | * @description 单选选择回调 585 | */ 586 | touch ({ currentTarget: {dataset: {index}} }) { 587 | const time = this.data.days[index].time; 588 | this.setData({touch: time}); 589 | this.renderStyle(); 590 | 591 | //confirmType为end时触发confirm事件 592 | if(this.properties.confirmType == "end"){ 593 | this.triggerEvent("confirm", { 594 | text: this.timeToString(this.data.touch), 595 | time: this.data.touch 596 | }); 597 | } 598 | }, 599 | 600 | /** 601 | * @description confirm按钮回调 602 | */ 603 | confirm () { 604 | if(this.properties.type == "range"){ 605 | if(this.data.begin != 0 && this.data.over != 0){ 606 | this.triggerEvent("confirm", { 607 | begin: { 608 | text: this.timeToString(this.data.begin), 609 | time: this.data.begin 610 | }, 611 | over: { 612 | text: this.timeToString(this.data.over), 613 | time: this.data.over 614 | } 615 | }); 616 | } 617 | } 618 | if(this.properties.type == "touch"){ 619 | if(this.data.touch != 0){ 620 | this.triggerEvent("confirm", { 621 | text: this.timeToString(this.data.touch), 622 | time: this.data.touch 623 | }); 624 | } 625 | } 626 | }, 627 | 628 | /** 629 | * @description cancel按钮回调 630 | */ 631 | cancel () { 632 | //防止重新选择后,取消,造成选中不跟随数据 633 | if(this.properties.useType == "touch"){ 634 | this.initTouch(); 635 | } 636 | if(this.properties.useType == "range"){ 637 | this.initRange(); 638 | } 639 | this.triggerEvent("cancel"); 640 | }, 641 | 642 | /** 643 | * @description 渲染日历选择后样式 644 | */ 645 | renderStyle () { 646 | const 647 | begin = this.data.begin, 648 | over = this.data.over, 649 | arr = this.data.days; 650 | 651 | //范围选择模式时 652 | if (this.properties.type == "range") { 653 | /*仅选择开始的时候*/ 654 | if (begin != 0 && over == 0) { 655 | for (let i of arr) { 656 | i.type = ""; 657 | if (i.time == begin) { 658 | i.type = "start-only"; 659 | } 660 | } 661 | this.setData({ days: arr }); 662 | } 663 | /*都选择的时候*/ 664 | if (begin != 0 && over != 0) { 665 | for (let i of arr) { 666 | //每个日期在开始与结束范围之间的样式 667 | if (i.time < this.data.over && i.time > this.data.begin) { 668 | //日期框为星期6时(位置在最右侧) 669 | if (i.day === 6) { 670 | if (i.date === 1) { 671 | i.type = "range-center"; 672 | } else { 673 | i.type = "range-right"; 674 | } 675 | } 676 | //日期框为星期天时(位置在最左侧) 677 | else if (i.day === 0) { 678 | if(i.date === arr.length){ 679 | i.type = "range-center"; 680 | }else{ 681 | i.type = "range-left"; 682 | } 683 | } 684 | //日期为1号时 685 | else if(i.date === 1){ 686 | i.type = "range-left"; 687 | } 688 | //日期为该月随后一天时 689 | else if(i.date === arr.length){ 690 | i.type = "range-right"; 691 | } 692 | //以上都不是,则设置为range 693 | else{ 694 | i.type = "range"; 695 | } 696 | } 697 | //设置开头样式 698 | if (i.time == this.data.begin) { 699 | if(i.day === 6){//如果开始处于星期六(最后一个) 700 | i.type = "start-only"; 701 | } 702 | else if (i.date == this.data.days.length) {//如果开始处于月末(月最后一个) 703 | i.type = "start-only"; 704 | }else{ 705 | i.type = "start"; 706 | } 707 | } 708 | //设置结束样式 709 | if (i.time == this.data.over) { 710 | if(i.day === 0){//如果结束为星期天(第一个) 711 | i.type = "stop-only"; 712 | } 713 | else if (i.day === 6 && i.date == 1) {//如果1号为星期六时 714 | i.type = "stop-only"; 715 | }else{ 716 | i.type = "stop"; 717 | } 718 | } 719 | } 720 | this.setData({days: arr}); 721 | } 722 | } 723 | //单选模式时候 724 | if (this.properties.type == "touch") { 725 | arr.forEach(day=>{ 726 | day.type = ""; 727 | if(day.time == this.data.touch){ 728 | //actives传参子元素为object的时候,就显示成方形样式(因为要显示价格参数) 729 | if(this.data.activesChildType === "object"){ 730 | day.type = "actives-point"; 731 | } 732 | //否则按照正常的单选选中样式处理 733 | else{ 734 | day.type = "point"; 735 | } 736 | } 737 | }); 738 | this.setData({days: arr}); 739 | } 740 | }, 741 | 742 | /** 743 | * @description 时间戳转日期字符串 744 | * @param {String|Number} 时间戳 745 | * @return {String} 日期时间字符串;如:xxxx-xx-xx 746 | */ 747 | timeToString (time) { 748 | const 749 | date = new Date(Number(time)), 750 | Y = date.getFullYear(), 751 | M = date.getMonth()+1 < 10 ? "0"+(date.getMonth()+1) : date.getMonth()+1, 752 | D = date.getDate()<10 ? "0"+date.getDate() : date.getDate(); 753 | return `${Y}-${M}-${D}`; 754 | }, 755 | 756 | /** 757 | * @desciption 抛错函数 758 | * @param {String} msg 错误信息 759 | */ 760 | throwErr (msg) { 761 | if (!msg) return; 762 | console.error("[my-calendar组件报错] " + msg); 763 | } 764 | 765 | } 766 | 767 | }); --------------------------------------------------------------------------------