├── 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 |
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 | 
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 | 
5 |
6 | ## 应用场景展示
7 |
8 | ### 1.基本日期选择
9 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | });
--------------------------------------------------------------------------------