├── 日历运行效果.gif
├── 项目运行效果.gif
├── App.vue
├── static
└── zsy-calendar
│ └── arrow.png
├── .gitignore
├── main.js
├── pages.json
├── index.html
├── .hbuilderx
└── launch.json
├── pages
└── index
│ └── calendar.vue
├── uni.scss
├── components
└── zsy-calendar
│ ├── js
│ └── utils.js
│ ├── dateBox.vue
│ ├── zsy-calendar.vue
│ └── zsy-calendar v1.0.vue
├── 使用说明.md
└── manifest.json
/日历运行效果.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhengsenyi/zsy-calendar/HEAD/日历运行效果.gif
--------------------------------------------------------------------------------
/项目运行效果.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhengsenyi/zsy-calendar/HEAD/项目运行效果.gif
--------------------------------------------------------------------------------
/App.vue:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/static/zsy-calendar/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhengsenyi/zsy-calendar/HEAD/static/zsy-calendar/arrow.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | unpackage/release
4 | dist/
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 |
15 | # Editor directories and files
16 | .project
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw*
24 | *.zip
25 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | import App from './App'
2 |
3 | // #ifndef VUE3
4 | import Vue from 'vue'
5 | Vue.config.productionTip = false
6 | App.mpType = 'app'
7 | const app = new Vue({
8 | ...App
9 | })
10 | app.$mount()
11 | // #endif
12 |
13 | // #ifdef VUE3
14 | import { createSSRApp } from 'vue'
15 | export function createApp() {
16 | const app = createSSRApp(App)
17 | return {
18 | app
19 | }
20 | }
21 | // #endif
--------------------------------------------------------------------------------
/pages.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
3 | {
4 | "path": "pages/index/calendar",
5 | "style": {
6 | "navigationBarTitleText": "仿钉钉打卡日历"
7 | }
8 | }
9 | ],
10 | "globalStyle": {
11 | "navigationBarTextStyle": "black",
12 | "navigationBarTitleText": "uni-app",
13 | "navigationBarBackgroundColor": "#F8F8F8",
14 | "backgroundColor": "#F8F8F8"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.hbuilderx/launch.json:
--------------------------------------------------------------------------------
1 | { // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
2 | // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
3 | "version": "0.0",
4 | "configurations": [{
5 | "app-plus" :
6 | {
7 | "launchtype" : "local"
8 | },
9 | "default" :
10 | {
11 | "launchtype" : "local"
12 | },
13 | "h5" :
14 | {
15 | "launchtype" : "local"
16 | },
17 | "mp-weixin" :
18 | {
19 | "launchtype" : "local"
20 | },
21 | "type" : "uniCloud"
22 | }
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/pages/index/calendar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
25 |
26 |
34 |
--------------------------------------------------------------------------------
/uni.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * 这里是uni-app内置的常用样式变量
3 | *
4 | * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
5 | * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
6 | *
7 | */
8 |
9 | /**
10 | * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
11 | *
12 | * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
13 | */
14 |
15 | /* 颜色变量 */
16 |
17 | /* 行为相关颜色 */
18 | $uni-color-primary: #007aff;
19 | $uni-color-success: #4cd964;
20 | $uni-color-warning: #f0ad4e;
21 | $uni-color-error: #dd524d;
22 |
23 | /* 文字基本颜色 */
24 | $uni-text-color:#333;//基本色
25 | $uni-text-color-inverse:#fff;//反色
26 | $uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
27 | $uni-text-color-placeholder: #808080;
28 | $uni-text-color-disable:#c0c0c0;
29 |
30 | /* 背景颜色 */
31 | $uni-bg-color:#ffffff;
32 | $uni-bg-color-grey:#f8f8f8;
33 | $uni-bg-color-hover:#f1f1f1;//点击状态颜色
34 | $uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
35 |
36 | /* 边框颜色 */
37 | $uni-border-color:#c8c7cc;
38 |
39 | /* 尺寸变量 */
40 |
41 | /* 文字尺寸 */
42 | $uni-font-size-sm:12px;
43 | $uni-font-size-base:14px;
44 | $uni-font-size-lg:16;
45 |
46 | /* 图片尺寸 */
47 | $uni-img-size-sm:20px;
48 | $uni-img-size-base:26px;
49 | $uni-img-size-lg:40px;
50 |
51 | /* Border Radius */
52 | $uni-border-radius-sm: 2px;
53 | $uni-border-radius-base: 3px;
54 | $uni-border-radius-lg: 6px;
55 | $uni-border-radius-circle: 50%;
56 |
57 | /* 水平间距 */
58 | $uni-spacing-row-sm: 5px;
59 | $uni-spacing-row-base: 10px;
60 | $uni-spacing-row-lg: 15px;
61 |
62 | /* 垂直间距 */
63 | $uni-spacing-col-sm: 4px;
64 | $uni-spacing-col-base: 8px;
65 | $uni-spacing-col-lg: 12px;
66 |
67 | /* 透明度 */
68 | $uni-opacity-disabled: 0.3; // 组件禁用态的透明度
69 |
70 | /* 文章场景相关 */
71 | $uni-color-title: #2C405A; // 文章标题颜色
72 | $uni-font-size-title:20px;
73 | $uni-color-subtitle: #555555; // 二级标题颜色
74 | $uni-font-size-subtitle:26px;
75 | $uni-color-paragraph: #3F536E; // 文章段落颜色
76 | $uni-font-size-paragraph:15px;
77 |
--------------------------------------------------------------------------------
/components/zsy-calendar/js/utils.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 时间格式化
3 | * @param {String} time
4 | * @param {String} cFormat
5 | */
6 | export function parseTime(time, cFormat) {
7 | if (arguments.length === 0) {
8 | return null
9 | }
10 | if (!time) return ''
11 | /* 修复IOS系统上面的时间不兼容*/
12 | if (time.toString().indexOf('-') > 0) {
13 | time = time.replace(/-/g, '/')
14 | }
15 | const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
16 | let date
17 | if (typeof time === 'object') {
18 | date = time
19 | } else {
20 | if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
21 | time = parseInt(time)
22 | }
23 | if ((typeof time === 'number') && (time.toString().length === 10)) {
24 | time = time * 1000
25 | }
26 | date = new Date(time)
27 | }
28 | const formatObj = {
29 | y: date.getFullYear(),
30 | m: date.getMonth() + 1,
31 | d: date.getDate(),
32 | h: date.getHours(),
33 | i: date.getMinutes(),
34 | s: date.getSeconds(),
35 | a: date.getDay()
36 | }
37 | const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
38 | const value = formatObj[key]
39 | // Note: getDay() returns 0 on Sunday
40 | if (key === 'a') {
41 | return ['日', '一', '二', '三', '四', '五', '六'][value]
42 | }
43 | return value.toString().padStart(2, '0')
44 | })
45 | return time_str
46 | }
47 |
48 | /**
49 | * This is just a simple version of deep copy
50 | * Has a lot of edge cases bug
51 | * If you want to use a perfect deep copy, use lodash's _.cloneDeep
52 | * @param {Object} source
53 | * @returns {Object}
54 | */
55 | export function deepClone(source) {
56 | if (!source && typeof source !== 'object') {
57 | throw new Error('error arguments', 'deepClone')
58 | }
59 | const targetObj = Object.prototype.toString.call(source) === "[object Array]" ? [] : {}
60 | Object.keys(source).forEach(keys => {
61 | if (source[keys] && typeof source[keys] === 'object') {
62 | targetObj[keys] = deepClone(source[keys])
63 | } else {
64 | targetObj[keys] = source[keys]
65 | }
66 | })
67 | return targetObj
68 | }
--------------------------------------------------------------------------------
/使用说明.md:
--------------------------------------------------------------------------------
1 | # 仿钉钉日历组件 支持月与周两种模式的左右滑动切换 支持在APP、小程序、H5运行
2 |
3 | ```javascript
4 |
5 |
6 |
10 |
11 |
12 |
13 |
28 |
36 | // Vue
37 | ```
38 | ***
39 | ##### 通用日历,可标记,支持自定义主题颜色,列高度的自定义
40 |
41 | 1. 日历展开模式显示的是月历,上月份跟下月份的日期呈灰色显示,点击对应的日期可滑动到相应的月份并且高亮显示;
42 | 2. 日历收缩时显示的是周历,可以进行周之间滑动的切换,且点击上月份的日期时自动切换到上月,具体请看效果演示图或自行尝试;
43 | 3. 因本人工作项目需求暂没有做日期选择器,但我在里面增加了一个goToDate方法可以切换到某一天,并且加了一个回到今天的功能,如果你们有这个需求可以自行二次开发;
44 | 4. 该日历组件共使用了两个swiper组件分别对应月历跟周历,使用三个swiper-item并且显示相邻的数据,即可以达到无限循环的效果又可以节省性能,并且当组件滑动完毕后才进行数据的预生成,避免滑动过程中计算数据造成页面不流畅卡顿;
45 | 5. 项目源码注释清晰且不难理解,可自行根据实际需求进行二次开发;
46 | 6. 本插件本人还未进行深度测试,可能还有些隐藏BUG暂未发现,若有小伙伴发现可进行评论留言;
47 | 7. 本人刚入行时间也不长,可能一些思路大佬看了会觉得比较简单低级,如果大佬有更好的思路,欢迎在评论区指出留言,我后续也会出一篇关于源码解析的文章;
48 | ***
49 | ##### 组件属性说明:
50 | |属性名|类型|默认值|说明|
51 | |:--:|:--:|:--:|:--:|
52 | |duration|Number|300|动画时长|
53 | |cellHeight|Number|75|日历每一列的高度,单位为rpx|
54 | |dateActiveColor|String|#FE6601|日期选中颜色|
55 | |sundayIndex|Number|6|星期天所在位置,范围为0~6|
56 | |mode|String|'open'|日历模式 'open'为月历 'close'为周历|
57 | |changeSetDefault|Boolean|true|月历切换是否默认选中1号|
58 | |defaultSelectedDate|String Null|null|选中日期,默认为当天|
59 | ***
60 | ##### 方法说明:
61 | |属性名|说明|
62 | |:--:|:--:|
63 | |goToDate|切换到某一天日期 格式 YYYY-MM 或者 YYYY-MM-DD|
64 | ***
65 | ##### 事件说明:
66 | |属性名|说明|
67 | |:--:|:--:|
68 | |change|日历选中日期改变事件回调|
69 | ***
70 | ##### 插件实际运行效果预览:
71 | 
72 | ##### 项目实际运行效果预览:
73 | 
74 | ##### 线上预览地址:
75 | [点击访问](https://static-ffcb1110-1b39-410a-b1f6-c2e57fd34cd4.bspapp.com/zsy-calendar)
--------------------------------------------------------------------------------
/components/zsy-calendar/dateBox.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
20 | {{ dateInfo.date }}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
68 |
69 |
114 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "仿钉钉打卡日历",
3 | "appid" : "__UNI__AD5A07B",
4 | "description" : "",
5 | "versionName" : "1.0.0",
6 | "versionCode" : "100",
7 | "transformPx" : false,
8 | /* 5+App特有相关 */
9 | "app-plus" : {
10 | "usingComponents" : true,
11 | "nvueStyleCompiler" : "uni-app",
12 | "compilerVersion" : 3,
13 | "splashscreen" : {
14 | "alwaysShowBeforeRender" : true,
15 | "waiting" : true,
16 | "autoclose" : true,
17 | "delay" : 0
18 | },
19 | /* 模块配置 */
20 | "modules" : {},
21 | /* 应用发布信息 */
22 | "distribute" : {
23 | /* android打包配置 */
24 | "android" : {
25 | "permissions" : [
26 | "",
27 | "",
28 | "",
29 | "",
30 | "",
31 | "",
32 | "",
33 | "",
34 | "",
35 | "",
36 | "",
37 | "",
38 | "",
39 | "",
40 | ""
41 | ]
42 | },
43 | /* ios打包配置 */
44 | "ios" : {},
45 | /* SDK配置 */
46 | "sdkConfigs" : {}
47 | }
48 | },
49 | /* 快应用特有相关 */
50 | "quickapp" : {},
51 | /* 小程序特有相关 */
52 | "mp-weixin" : {
53 | "appid" : "",
54 | "setting" : {
55 | "urlCheck" : false
56 | },
57 | "usingComponents" : true
58 | },
59 | "mp-alipay" : {
60 | "usingComponents" : true
61 | },
62 | "mp-baidu" : {
63 | "usingComponents" : true
64 | },
65 | "mp-toutiao" : {
66 | "usingComponents" : true
67 | },
68 | "uniStatistics" : {
69 | "enable" : false
70 | },
71 | "vueVersion" : "2",
72 | "h5" : {
73 | "router" : {
74 | "mode" : "hash",
75 | "base" : "/zsy-calendar"
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/components/zsy-calendar/zsy-calendar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 每日记录
7 |
8 | ({{ getAssignDateInfo(false, 0) === getAssignDateInfo(true, 0) ? '' : getAssignDateInfo(false, 0) + '年' }}{{ getAssignDateInfo(false, 1) }}月)
9 |
10 | 回到今天
11 |
12 |
13 |
14 |
15 | {{ item }}
16 |
17 |
18 |
19 |
20 | current = e.detail.current"
28 | >
29 |
30 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
427 |
428 |
512 |
--------------------------------------------------------------------------------
/components/zsy-calendar/zsy-calendar v1.0.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 每日记录
7 |
8 | ({{ getAssignDateInfo(false, 0) === getAssignDateInfo(true, 0) ? '' : getAssignDateInfo(false, 0) + '年' }}{{ getAssignDateInfo(false, 1) }}月)
9 |
10 | 回到今天
11 |
12 |
13 |
14 |
15 | {{ item }}
16 |
17 |
18 |
19 |
20 |
21 | current = e.detail.current"
30 | >
31 |
32 |
39 |
40 |
41 |
42 |
43 | shrinkCurrent = e.detail.current"
52 | >
53 |
54 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
558 |
559 |
642 |
--------------------------------------------------------------------------------