web
14 小时以前 49fa0d82a40345342966e810b44429aec0480ef3
fix:修改.gitgnore文件,移除打包文件
已删除62个文件
已添加404个文件
已修改1个文件
60045 ■■■■ 文件已修改
.gitignore 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/changelog.md 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.uvue 235 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.vue 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/components/l-qrcode/props.ts 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/components/l-qrcode/qrcode.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/components/l-qrcode/type.ts 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/components/l-qrcode/useCanvas.ts 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/components/l-qrcode/utils.uts 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/components/lime-qrcode/lime-qrcode.uvue 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/components/lime-qrcode/lime-qrcode.vue 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/hybrid/html/index.html 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/hybrid/html/qrcode.min.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/hybrid/html/uni.webview.1.5.3.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/package.json 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-qrcode/readme.md 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/addUnit/index.ts 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/animation/bezier.ts 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/animation/ease.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/animation/index.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/animation/useTransition.ts 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/animation/uvue.uts 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/animation/vue.ts 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/arrayBufferToFile/index.ts 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/arrayBufferToFile/uvue.uts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/arrayBufferToFile/vue.ts 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/base64ToArrayBuffer/index.ts 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/base64ToPath/index.ts 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/base64ToPath/uvue.uts 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/base64ToPath/vue.ts 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/camelCase/index.ts 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/canIUseCanvas2d/index.ts 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/capitalizedAmount/index.ts 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/changelog.md 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/clamp/index.ts 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/cloneDeep/index.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/cloneDeep/uvue.ts 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/cloneDeep/vue.ts 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/closest/index.ts 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/components/lime-shared/lime-shared.vue 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/createAnimation/index.ts 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/createAnimation/type.ts 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/createAnimation/uvue.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/createAnimation/vue.ts 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/createCanvas/index.ts 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/createImage/index.ts 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/debounce/index.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/debounce/uvue.ts 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/debounce/vue.ts 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/exif/index.ts 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/exif/uvue.ts 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/exif/vue.ts 1057 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/fillZero/index.ts 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/floatAdd/index.ts 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/floatDiv/index.ts 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/floatMul/index.ts 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/floatSub/index.ts 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/getClassStr/index.ts 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/getCurrentPage/index.ts 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/getCurrentPage/uvue.uts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/getCurrentPage/vue.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/getLocalFilePath/index.ts 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/getRect/index.ts 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/getRect/uvue.uts 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/getRect/vue.ts 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/getStyleStr/index.ts 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/getStyleStr/index_.uts 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/hasOwn/index.ts 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/hasOwn/uvue.ts 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/hasOwn/vue.ts 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/index.ts 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/isBase64/index.ts 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/isBrowser/index.ts 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/isDef/index.ts 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/isEmpty/index.ts 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/isFunction/index.ts 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/isNumber/index.ts 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/isNumeric/index.ts 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/isObject/index.ts 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/isPromise/index.ts 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/isString/index.ts 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/kebabCase/index.ts 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/package.json 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/pathToBase64/index.ts 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/pathToBase64/uvue.uts 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/pathToBase64/vue.ts 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/platform/index.ts 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/raf/index.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/raf/uvue.ts 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/raf/vue.ts 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/random/index.ts 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/range/index.ts 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/readme.md 445 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/selectAllComponent/index.ts 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/selectAllComponent/uvue.uts 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/selectAllComponent/vue.ts 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/selectComponent/index.ts 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/selectComponent/uvue.uts 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/selectComponent/vue.ts 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/selectElement/index.uts 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/sleep/index.ts 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/throttle/index.ts 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/toArray/index.ts 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/toBoolean/index.ts 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/toNumber/index.ts 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/unitConvert/index.ts 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/lime-shared/vue/index.ts 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-badge/changelog.md 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-badge/components/uni-badge/uni-badge.vue 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-badge/package.json 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-badge/readme.md 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-calendar/changelog.md 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-calendar/components/uni-calendar/calendar.js 544 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-calendar/components/uni-calendar/i18n/en.json 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-calendar/components/uni-calendar/i18n/index.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue 187 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue 567 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-calendar/components/uni-calendar/util.js 360 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-calendar/package.json 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-calendar/readme.md 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-card/changelog.md 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-card/components/uni-card/uni-card.vue 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-card/package.json 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-card/readme.md 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-collapse/changelog.md 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue 402 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-collapse/package.json 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-collapse/readme.md 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-combox/changelog.md 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-combox/components/uni-combox/uni-combox.vue 284 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-combox/package.json 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-combox/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-countdown/changelog.md 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-countdown/components/uni-countdown/i18n/en.json 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-countdown/components/uni-countdown/i18n/index.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue 276 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-countdown/package.json 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-countdown/readme.md 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-checkbox/changelog.md 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue 849 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-checkbox/package.json 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-checkbox/readme.md 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-picker/changelog.md 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-picker/components/uni-data-picker/keypress.js 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.uvue 381 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue 551 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js 622 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts 692 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.css 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.uvue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue 323 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-picker/package.json 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-picker/readme.md 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-select/changelog.md 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue 562 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-select/package.json 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-data-select/readme.md 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-dateformat/changelog.md 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-dateformat/components/uni-dateformat/date-format.js 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-dateformat/package.json 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-dateformat/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-datetime-picker/changelog.md 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue 947 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue 940 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue 1064 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js 421 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-datetime-picker/package.json 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-datetime-picker/readme.md 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-drawer/changelog.md 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-drawer/components/uni-drawer/keypress.js 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue 183 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-drawer/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-drawer/readme.md 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-easyinput/changelog.md 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-easyinput/components/uni-easyinput/common.js 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue 676 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-easyinput/package.json 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-easyinput/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-fab/changelog.md 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-fab/components/uni-fab/uni-fab.vue 491 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-fab/package.json 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-fab/readme.md 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-fav/changelog.md 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-fav/components/uni-fav/i18n/en.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-fav/components/uni-fav/i18n/index.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-fav/components/uni-fav/uni-fav.vue 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-fav/package.json 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-fav/readme.md 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-file-picker/changelog.md 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js 287 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue 668 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue 325 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue 292 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-file-picker/components/uni-file-picker/utils.js 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-file-picker/package.json 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-file-picker/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-forms/changelog.md 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue 632 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-forms/components/uni-forms/uni-forms.vue 404 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-forms/components/uni-forms/utils.js 293 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-forms/components/uni-forms/validate.js 486 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-forms/package.json 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-forms/readme.md 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-goods-nav/changelog.md 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/en.json 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/index.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hans.json 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hant.json 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue 229 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-goods-nav/package.json 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-goods-nav/readme.md 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-grid/changelog.md 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-grid/components/uni-grid/uni-grid.vue 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-grid/package.json 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-grid/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-group/changelog.md 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-group/components/uni-group/uni-group.vue 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-group/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-group/readme.md 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-icons/changelog.md 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-icons/components/uni-icons/uni-icons.uvue 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-icons/components/uni-icons/uni-icons.vue 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-icons/components/uni-icons/uniicons.css 664 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-icons/components/uni-icons/uniicons.ttf 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-icons/components/uni-icons/uniicons_file.ts 664 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js 649 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-icons/package.json 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-icons/readme.md 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-indexed-list/changelog.md 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue 367 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-indexed-list/package.json 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-indexed-list/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-link/changelog.md 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-link/components/uni-link/uni-link.vue 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-link/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-link/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-list/changelog.md 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue 593 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-list/components/uni-list-item/uni-list-item.vue 534 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-list/components/uni-list/uni-list.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-list/components/uni-list/uni-refresh.vue 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-list/components/uni-list/uni-refresh.wxs 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-list/package.json 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-list/readme.md 346 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-load-more/changelog.md 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-load-more/components/uni-load-more/i18n/en.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-load-more/components/uni-load-more/i18n/index.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue 404 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-load-more/package.json 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-load-more/readme.md 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-nav-bar/changelog.md 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue 357 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-nav-bar/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-nav-bar/readme.md 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-notice-bar/changelog.md 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue 431 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-notice-bar/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-notice-bar/readme.md 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-number-box/changelog.md 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue 232 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-number-box/package.json 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-number-box/readme.md 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-pagination/changelog.md 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-pagination/components/uni-pagination/i18n/en.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-pagination/components/uni-pagination/i18n/es.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-pagination/components/uni-pagination/i18n/index.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue 465 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-pagination/package.json 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-pagination/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/changelog.md 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup-dialog/keypress.js 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue 316 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue 187 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup/i18n/en.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup/i18n/index.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup/keypress.js 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup/popup.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup/uni-popup.uvue 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/components/uni-popup/uni-popup.vue 518 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/package.json 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-popup/readme.md 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-rate/changelog.md 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-rate/components/uni-rate/uni-rate.vue 361 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-rate/package.json 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-rate/readme.md 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-row/changelog.md 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-row/components/uni-col/uni-col.vue 317 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-row/components/uni-row/uni-row.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-row/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-row/readme.md 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/changelog.md 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/index.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/package.json 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/readme.md 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/styles/index.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/styles/setting/_border.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/styles/setting/_color.scss 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/styles/setting/_radius.scss 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/styles/setting/_space.scss 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/styles/setting/_styles.scss 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/styles/setting/_text.scss 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/styles/setting/_variables.scss 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/styles/tools/functions.scss 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/theme.scss 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-scss/variables.scss 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-search-bar/changelog.md 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue 309 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-search-bar/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-search-bar/readme.md 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-section/changelog.md 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-section/components/uni-section/uni-section.vue 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-section/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-section/readme.md 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-segmented-control/changelog.md 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-segmented-control/package.json 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-segmented-control/readme.md 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-steps/changelog.md 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-steps/components/uni-steps/uni-steps.vue 280 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-steps/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-steps/readme.md 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swipe-action/changelog.md 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js 302 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js 195 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js 260 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue 348 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs 341 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swipe-action/package.json 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swipe-action/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swiper-dot/changelog.md 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue 218 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swiper-dot/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-swiper-dot/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/changelog.md 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/components/uni-table/uni-table.vue 460 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/components/uni-tbody/uni-tbody.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/components/uni-td/uni-td.vue 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/components/uni-th/filter-dropdown.vue 511 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/components/uni-th/uni-th.vue 295 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/components/uni-thead/uni-thead.vue 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/components/uni-tr/table-checkbox.vue 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/components/uni-tr/uni-tr.vue 184 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/i18n/en.json 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/i18n/es.json 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/i18n/fr.json 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/i18n/index.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/i18n/zh-Hans.json 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/i18n/zh-Hant.json 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/package.json 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-table/readme.md 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-tag/changelog.md 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-tag/components/uni-tag/uni-tag.vue 252 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-tag/package.json 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-tag/readme.md 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-title/changelog.md 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-title/components/uni-title/uni-title.vue 171 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-title/package.json 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-title/readme.md 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-tooltip/changelog.md 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-tooltip/package.json 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-tooltip/readme.md 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-transition/changelog.md 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-transition/components/uni-transition/createAnimation.js 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-transition/components/uni-transition/uni-transition.vue 286 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-transition/package.json 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-transition/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-ui/changelog.md 578 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-ui/components/uni-ui/uni-ui.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-ui/package.json 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-ui/readme.md 247 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/cache/.vite/deps/_metadata.json 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/cache/.vite/deps/package.json 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/api/index.js 222 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/app.js 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/app.json 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/app.wxss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/common/assets.js 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/common/vendor.js 10953 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/components/navbar/navbar.js 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/components/navbar/navbar.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/components/navbar/navbar.wxml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/components/navbar/navbar.wxss 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/config/baseUrl.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/addCard/index.js 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/addCard/index.json 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/addCard/index.wxml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/addCard/index.wxss 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/address/index.js 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/address/index.json 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/address/index.wxml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/address/index.wxss 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/index/index.js 344 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/index/index.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/index/index.wxml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/index/index.wxss 467 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/preSendWater/index.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/preSendWater/index.json 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/preSendWater/index.wxml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/preSendWater/index.wxss 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/recharge/index.js 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/recharge/index.json 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/recharge/index.wxml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/recharge/index.wxss 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/sendWater/index.js 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/sendWater/index.json 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/sendWater/index.wxml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/pages/sendWater/index.wxss 162 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/project.config.json 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/project.private.config.json 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/addCard/back.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/back.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/bottom-line.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/code1.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/icon23.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/icon31.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/icon32.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/icon33.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/icon34.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/icon35.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/icon36.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/icon37.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/icon38.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/more-info5.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/vip-add.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/index/vip1.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/login/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/login/wechat.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/recharge/balance.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/recharge/pay.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/images/recharge/wx.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/static/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
unpackage/dist/dev/mp-weixin/util/request.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -1 +1,2 @@
node_modules
unpackage/*
uni_modules/lime-qrcode/changelog.md
对比新文件
@@ -0,0 +1,37 @@
## 0.1.8(2024-08-05)
- fix: 修复因shared升级导致微信小程序可能不生效的问题
## 0.1.7(2024-05-15)
- fix: 修复uvue因缺少依赖无法使用
## 0.1.6(2024-05-09)
- fix: 修复vue2因type问题导致无法使用
## 0.1.5(2024-04-14)
- fix: 修复缺少依赖
## 0.1.4(2024-04-10)
- chore: 更新文档
## 0.1.3(2024-04-01)
- chore: 兼容uniapp x ios(app-js)
## 0.1.2(2023-12-14)
- fix: uvue 引入 API 自定义包出错
## 0.1.1(2023-12-11)
- chore: uvue的二维码API独立,需要单独下载
## 0.1.0(2023-12-07)
- fix: 修复因utssdk目录导致无法运行
## 0.0.9(2023-12-06)
- feat: 支持uvue
## 0.0.8(2023-12-06)
- feat: 支持uvue
## 0.0.7(2023-12-06)
- feat: 支持uvue
## 0.0.6(2023-12-06)
- feat: 支持uvue
## 0.0.5(2023-07-30)
- fix: 修复再次生成前没有清空,导致图形叠加
## 0.0.4(2023-07-27)
- fix: 修复相同尺寸无法再次生成
## 0.0.3(2023-06-09)
- feat: 支持通过`@vue/composition-api`在`vue2`上使用
- chore: 更新文档
## 0.0.2(2023-06-08)
- chore: 更新文档
## 0.0.1(2023-06-08)
- 首次
uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.uvue
对比新文件
@@ -0,0 +1,235 @@
<template>
    <!-- #ifdef MP -->
    <canvas :style="styles" type="2d" :canvas-id="canvasId" :id="canvasId"></canvas>
    <!-- #endif  -->
    <!-- #ifdef APP -->
    <view class="l-qrcode" ref="drawableRef" :style="[styles]">
        <image class="l-qrcode__icon" v-if="icon" :src="icon" :style="[iconStyle]"></image>
    </view>
    <!-- #endif  -->
    <!-- #ifdef WEB -->
    <view class="l-qrcode" ref="drawableRef" :style="[styles]">
    </view>
    <!-- #endif  -->
</template>
<script lang="uts" setup>
    import { type PropType, nextTick } from 'vue'
    // #ifndef APP
    import { QRCodeCanvas } from './qrcode.js';
    import { QRCodePropsTypes , ImageSettings } from './type'
    // #endif
    // #ifdef APP
    import { QRCodeCanvas, QRCodePropsTypes , ImageSettings } from '@/uni_modules/lime-qrcodegen'
    // #endif
    // import { addUnit } from '@/uni_modules/lime-shared/addUnit'
    // import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
    // import { toBoolean } from '@/uni_modules/lime-shared/toBoolean'
    import { addUnit, unitConvert } from './utils'
    import { LQrcodeFailCallback, LQrcodeCompleteCallback, LQrcodeSuccessCallback} from './type'
    const name = 'l-qrcode'
    const props = defineProps({
        value: {
            type: String
        },
        icon: {
            type: String
        },
        // #ifdef APP-ANDROID
        size: {
            type: Object,
            default: 160
        },
        iconSize: {
            type: Object,
            default: 40
        },
        // #endif
        // #ifndef APP-ANDROID
        size: {
            type: [Number, String],
            default: 160
        },
        iconSize: {
            type: [Number, String],
            default: 40
        },
        // #endif
        marginSize: {
            type: Number,
            default: 0
        },
        color: {
            type: String,
            default: '#000'
        },
        bgColor: {
            type: String,
            default: 'transparent'
        },
        bordered: {
            type: Boolean,
            default: true
        },
        errorLevel: {
            type: String as PropType<'L' | 'M' | 'Q' | 'H'>,
            default: 'M' // 'L' | 'M' | 'Q' | 'H'
        },
        useCanvasToTempFilePath: {
            type: Boolean,
            default: false
        }
        // status: {
        //     type: String as PropType<'active'|'expired'|'loading'>,
        //     default: 'active' // active | expired | loading
        // }
    })
    const emits = defineEmits(['success'])
    const context = getCurrentInstance();
    const canvasId = `l-qrcode${context!.uid}`
    const styles = computed<Map<string, any>>(():Map<string, any>=>{
        const style = new Map<string, any>()
        const size = addUnit(props.size);
        if(size!=null){
            style.set('width', size)
            style.set('height', size)
        }
        style.set('background', props.bgColor)
        return style
    })
    // #ifdef APP
    const iconStyle = computed<Map<string, any>>(():Map<string, any>=>{
        const style = new Map<string, any>()
        const size = addUnit(props.iconSize);
        if(size!=null){
            style.set('width', size)
            style.set('height', size)
        }
        return style
    })
    // #endif
    const drawableRef = ref<UniElement|null>(null);
    // #ifdef WEB
    let canvas:HTMLCanvasElement|null = null
    // #endif
    let qrcode:QRCodeCanvas|null = null
    const canvasToTempFilePath = (options: UTSJSONObject)=>{
        const format =   options.getString('format') ?? 'png';
        const fail =     options.get('fail') as LQrcodeFailCallback | null;
        const complete = options.get('complete') as LQrcodeCompleteCallback | null;
        const success =  options.get('success') as LQrcodeSuccessCallback | null;
        // #ifdef APP
        const newOptions = {
            format,
            fail,
            complete,
            success,
        } as TakeSnapshotOptions
        drawableRef.value!.takeSnapshot(newOptions)
        // #endif
        // #ifdef WEB
        success?.({
            tempFilePath: canvas?.toDataURL('image/'+format)
        })
        // #endif
    }
    const render = ()=>{
        const param:QRCodePropsTypes = {
            value: props.value,
            size:  unitConvert(props.size),
            fgColor: props.color,
            level: ['L', 'M', 'Q', 'H'].includes(props.errorLevel) ? props.errorLevel : 'M',
            marginSize: props.marginSize,
            includeMargin: props.bordered,
            imageSettings: null,
        } as QRCodePropsTypes
        if(props.icon != null){
        // if(toBoolean(props.iconSize) && toBoolean(props.icon)){
            const size = unitConvert(props.iconSize)
            param.imageSettings = {
                src: props.icon,
                width: size,
                height: size,
                excavate: true
            } as ImageSettings
        }
        qrcode?.render(param)
        if(props.useCanvasToTempFilePath){
            setTimeout(()=>{
                canvasToTempFilePath({
                    success: (res: TakeSnapshotSuccess)=>{
                        emits('success', res.tempFilePath)
                    }
                })
            },100)
        }
    }
    defineExpose({
        canvasToTempFilePath
    })
    onMounted(()=>{
        nextTick(()=>{
            // #ifdef APP
            const ctx = drawableRef.value!.getDrawableContext();
            qrcode = new QRCodeCanvas(ctx!)
            // #endif
            // #ifdef WEB
            canvas = document.createElement('canvas')
            canvas.style.width = '100%'
            canvas.style.height = '100%'
            drawableRef.value!.appendChild(canvas)
            qrcode = new QRCodeCanvas(canvas, {
                pixelRatio: uni.getSystemInfoSync().pixelRatio,
                createImage: () => {
                    const image = new Image();
                    image.crossOrigin = 'anonymous';
                    return image;
                }
            })
            // #endif
            watchEffect(()=>{
                render()
            })
        })
    })
    onUnmounted(()=>{
        // #ifdef WEB
        canvas?.remove();
        // #endif
        qrcode = null;
    })
</script>
<style lang="scss">
    .l-qrcode {
        position: relative;
        background-color: aqua;
        justify-content: center;
        align-items: center;
        &-mask {
            position: absolute;
            // inset: 0;
            // inset-block-start: 0;
            // inset-inline-start: 0;
            z-index: 10;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            // width: 100%;
            // height: 100%;
            color: rgba(0, 0, 0, 0.88);
            line-height: 1.5714285714285714;
            background: rgba(255, 255, 255, 0.96);
            text-align: center;
        }
    }
</style>
uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.vue
对比新文件
@@ -0,0 +1,223 @@
<template>
    <view class="l-qrcode" :style="[styles]">
        <!-- #ifndef APP-NVUE -->
        <canvas :style="styles" type="2d" :canvas-id="canvasId" :id="canvasId"></canvas>
        <!-- #endif  -->
        <!-- #ifdef APP-NVUE  -->
        <web-view
        ref="qrcodeRef"
        @pagefinish="onFinished"
        @error="onError"
        @onPostMessage="onMessage"
        :style="styles" src="/uni_modules/lime-qrcode/hybrid/html/index.html?v=1"></web-view>
        <!-- #endif  -->
        <!-- <view class="l-qrcode-mask" v-if="['loading', 'expired'].includes(props.status)">
            <l-loading v-if="props.status == 'loading'"></l-loading>
            <view class="l-qrcode-expired" v-if="props.status == 'expired'">
                <slot></slot>
            </view>
        </view> -->
    </view>
</template>
<script lang="ts">
    // @ts-nocheck
    import { computed, defineComponent, getCurrentInstance, watch, onUnmounted, onMounted } from '@/uni_modules/lime-shared/vue';
    import QRCodeProps from './props'
    // #ifndef APP-NVUE
    import { getCanvas, isCanvas2d } from './useCanvas'
    import { QRCodeCanvas } from './qrcode.js';
    // #endif
    import { addUnit } from '@/uni_modules/lime-shared/addUnit'
    import { createImage } from '@/uni_modules/lime-shared/createImage'
    import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
    import { isBase64 } from '@/uni_modules/lime-shared/isBase64'
    import { pathToBase64 } from '@/uni_modules/lime-shared/pathToBase64'
    import { debounce } from '@/uni_modules/lime-shared/debounce'
    const name = 'l-qrcode'
    export default defineComponent({
        name,
        props: QRCodeProps,
        emits: ['success'],
        setup(props, {emit}) {
            const context = getCurrentInstance();
            const canvasId = `l-qrcode${context.uid}`
            const styles = computed(() => `width: ${addUnit(props.size)}; height: ${addUnit(props.size)};`)
            let qrcode = null
            let canvas = null
            const qrCodeProps = computed(() => {
                const { value, icon, size, color, bgColor, bordered, iconSize, errorLevel, marginSize } = props
                const imageSettings = {
                    src: icon,
                    x: undefined,
                    y: undefined,
                    height: unitConvert(iconSize),
                    width: unitConvert(iconSize),
                    excavate: true,
                }
                return {
                    value,
                    size: unitConvert(size),
                    level: errorLevel,
                    bgColor,
                    fgColor: color,
                    imageSettings: icon ? imageSettings : undefined,
                    includeMargin: bordered,
                    marginSize: marginSize ?? 0
                }
            })
            // #ifdef APP-NVUE
            const stacks = new Map()
            // #endif
            const canvasToTempFilePath = debounce((args: UniNamespace.CanvasToTempFilePathRes) => {
                if(!canvas) return
                // #ifndef APP-NVUE
                const copyArgs = Object.assign({
                    canvasId,
                    canvas: null
                }, args)
                if (isCanvas2d) {
                    copyArgs.canvas = canvas
                }
                if ('toTempFilePath' in canvas) {
                    canvas.toTempFilePath(copyArgs)
                } else {
                    uni.canvasToTempFilePath(copyArgs, context);
                }
                // #endif
                // #ifdef APP-NVUE
                if(!stacks.size) {
                    const flie = 'file-' + Math.random();
                    const stack = {args, time: +new Date()}
                    stacks.set(`${flie}`, stack)
                    canvas.toDataURL(flie)
                    setTimeout(() => {
                        const stack = stacks.get(flie)
                        if(stack && 'fail' in stack.args) {
                            stack.args.fail({
                                error: '超时'
                            })
                            stacks.delete(flie)
                        }
                    },5000)
                }
                // #endif
            })
            const useCanvasToTempFilePath = () => {
                if(props.useCanvasToTempFilePath) {
                    canvasToTempFilePath({
                        success(res: UniNamespace.CanvasToTempFilePathRes) {
                            emit('success', res.tempFilePath)
                        }
                    })
                }
            }
            // #ifdef APP-NVUE
            const onFinished = () => {
                const { pixelRatio } = uni.getSystemInfoSync()
                canvas = {
                    toDataURL(flie: string) {
                        const ref: any = context.refs['qrcodeRef'];
                        if(ref) {
                            ref?.evalJS(`toDataURL('${flie}')`)
                        }
                    }
                };
                qrcode = {
                    async render(props: any) {
                        const ref: any = context.refs['qrcodeRef'];
                        const { src } = props.imageSettings || { };
                        if(!ref) return
                        if(src && !isBase64(src) && !/^http/.test(src) && /^\/static/.test(src)) {
                            props.imageSettings.src = await pathToBase64(src)
                        }
                        const _props = JSON.stringify(Object.assign({}, props, {pixelRatio}));
                        ref?.evalJS(`render(${_props})`);
                    }
                }
                qrcode.render(qrCodeProps.value)
                useCanvasToTempFilePath()
            }
            const onError = () => {
                console.warn('lime-qrcode 加载失败')
            }
            const onMessage = (e: any) => {
                const {detail:{data: [res]}} = e
                if(res.event == 'toDataURL') {
                    const {file, image, msg} = res.data;
                    const stack = stacks.get(file)
                    if(stack && image && 'success' in stack.args) {
                        stack.args.success({tempFilePath: image})
                        stacks.delete(file)
                    } else if(stack && 'fails' in stack.args) {
                        stack.args.fail({error: msg})
                        stacks.delete(file)
                    }
                }
            }
            // #endif
            const propsWatch = watch(props, () => {
                if (qrcode) {
                    qrcode.render(qrCodeProps.value)
                    useCanvasToTempFilePath()
                }
            })
            onMounted(() => {
                // #ifndef APP-NVUE
                getCanvas(canvasId, { context }).then(res => {
                    canvas = res
                    qrcode = new QRCodeCanvas(res, {
                        // #ifdef H5
                        path2D: false,
                        // #endif
                        pixelRatio: isCanvas2d ? uni.getSystemInfoSync().pixelRatio : 1,
                        createImage
                    })
                    qrcode.render(qrCodeProps.value)
                    useCanvasToTempFilePath()
                })
                // #endif
            })
            onUnmounted(() => {
                propsWatch && propsWatch()
            })
            return {
                canvasId,
                styles,
                props,
                canvasToTempFilePath,
                // #ifdef APP-NVUE
                onFinished,
                onError,
                onMessage
                // #endif
            }
        }
    })
</script>
<style lang="scss">
    .l-qrcode {
        position: relative;
        &-mask {
            position: absolute;
            inset: 0;
            // inset-block-start: 0;
            // inset-inline-start: 0;
            z-index: 10;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            // width: 100%;
            // height: 100%;
            color: rgba(0, 0, 0, 0.88);
            line-height: 1.5714285714285714;
            background: rgba(255, 255, 255, 0.96);
            text-align: center;
        }
    }
</style>
uni_modules/lime-qrcode/components/l-qrcode/props.ts
对比新文件
@@ -0,0 +1,36 @@
// @ts-nocheck
// import type { PropType } from './vue'
export default {
    value: String,
    icon: String,
    size: {
        type: [Number, String],
        default: 160
    },
    iconSize: {
        type: [Number, String],
        default: 40
    },
    marginSize: Number,
    color: {
        type: String,
        default: '#000'
    },
    bgColor: {
        type: String,
        default: 'transparent'
    },
    bordered: {
        type: Boolean,
        default: true
    },
    errorLevel: {
        type: String as PropType<'L'|'M'|'Q'|'H'>,
        default: 'M' // 'L' | 'M' | 'Q' | 'H'
    },
    useCanvasToTempFilePath: Boolean
    // status: {
    //     type: String as PropType<'active'|'expired'|'loading'>,
    //     default: 'active' // active | expired | loading
    // }
}
uni_modules/lime-qrcode/components/l-qrcode/qrcode.js
对比新文件
@@ -0,0 +1,6 @@
function e(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function t(e,t){for(var n=0;t.length>n;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}function n(e,n,r){return n&&t(e.prototype,n),r&&t(e,r),Object.defineProperty(e,"prototype",{writable:!1}),e}function r(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;o.length>r;r++)0>t.indexOf(n=o[r])&&(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;o.length>r;r++)0>t.indexOf(n=o[r])&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);t>n;n++)r[n]=e[n];return r}function o(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(e){if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?i(e,t):void 0}}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,o=function(){};return{s:o,n:function(){return e.length>r?{done:!1,value:e[r++]}:{done:!0}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,s=!0,u=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return s=e.done,e},e:function(e){u=!0,a=e},f:function(){try{s||null==n.return||n.return()}finally{if(u)throw a}}}}
/**
 * @license QR Code generator library (TypeScript)
 * Copyright (c) Project Nayuki.
 * SPDX-License-Identifier: MIT
 */var a;!function(t){var r=function(){function r(t,n,i,o){if(e(this,r),this.version=void 0,this.errorCorrectionLevel=void 0,this.size=void 0,this.mask=void 0,this.modules=[],this.isFunction=[],this.version=t,this.errorCorrectionLevel=n,r.MIN_VERSION>t||t>r.MAX_VERSION)throw new RangeError("Version value out of range");if(-1>o||o>7)throw new RangeError("Mask value out of range");this.size=4*t+17;for(var a=[],u=0;this.size>u;u++)a.push(!1);for(var l=0;this.size>l;l++)this.modules.push(a.slice()),this.isFunction.push(a.slice());this.drawFunctionPatterns();var h=this.addEccAndInterleave(i);if(this.drawCodewords(h),-1==o)for(var c=1e9,f=0;8>f;f++){this.applyMask(f),this.drawFormatBits(f);var v=this.getPenaltyScore();c>v&&(o=f,c=v),this.applyMask(f)}s(o>=0&&7>=o),this.mask=o,this.applyMask(o),this.drawFormatBits(o),this.isFunction=[]}return n(r,[{key:"getModule",value:function(e,t){return e>=0&&this.size>e&&t>=0&&this.size>t&&this.modules[t][e]}},{key:"getModules",value:function(){return this.modules}},{key:"drawFunctionPatterns",value:function(){for(var e=0;this.size>e;e++)this.setFunctionModule(6,e,e%2==0),this.setFunctionModule(e,6,e%2==0);this.drawFinderPattern(3,3),this.drawFinderPattern(this.size-4,3),this.drawFinderPattern(3,this.size-4);for(var t=this.getAlignmentPatternPositions(),n=t.length,r=0;n>r;r++)for(var i=0;n>i;i++)0==r&&0==i||0==r&&i==n-1||r==n-1&&0==i||this.drawAlignmentPattern(t[r],t[i]);this.drawFormatBits(0),this.drawVersion()}},{key:"drawFormatBits",value:function(e){for(var t=this.errorCorrectionLevel.formatBits<<3|e,n=t,r=0;10>r;r++)n=n<<1^1335*(n>>>9);var i=21522^(t<<10|n);s(i>>>15==0);for(var o=0;5>=o;o++)this.setFunctionModule(8,o,a(i,o));this.setFunctionModule(8,7,a(i,6)),this.setFunctionModule(8,8,a(i,7)),this.setFunctionModule(7,8,a(i,8));for(var u=9;15>u;u++)this.setFunctionModule(14-u,8,a(i,u));for(var l=0;8>l;l++)this.setFunctionModule(this.size-1-l,8,a(i,l));for(var h=8;15>h;h++)this.setFunctionModule(8,this.size-15+h,a(i,h));this.setFunctionModule(8,this.size-8,!0)}},{key:"drawVersion",value:function(){if(this.version>=7){for(var e=this.version,t=0;12>t;t++)e=e<<1^7973*(e>>>11);var n=this.version<<12|e;s(n>>>18==0);for(var r=0;18>r;r++){var i=a(n,r),o=this.size-11+r%3,u=Math.floor(r/3);this.setFunctionModule(o,u,i),this.setFunctionModule(u,o,i)}}}},{key:"drawFinderPattern",value:function(e,t){for(var n=-4;4>=n;n++)for(var r=-4;4>=r;r++){var i=Math.max(Math.abs(r),Math.abs(n)),o=e+r,a=t+n;o>=0&&this.size>o&&a>=0&&this.size>a&&this.setFunctionModule(o,a,2!=i&&4!=i)}}},{key:"drawAlignmentPattern",value:function(e,t){for(var n=-2;2>=n;n++)for(var r=-2;2>=r;r++)this.setFunctionModule(e+r,t+n,1!=Math.max(Math.abs(r),Math.abs(n)))}},{key:"setFunctionModule",value:function(e,t,n){this.modules[t][e]=n,this.isFunction[t][e]=!0}},{key:"addEccAndInterleave",value:function(e){var t=this.version,n=this.errorCorrectionLevel;if(e.length!=r.getNumDataCodewords(t,n))throw new RangeError("Invalid argument");for(var i=r.NUM_ERROR_CORRECTION_BLOCKS[n.ordinal][t],o=r.ECC_CODEWORDS_PER_BLOCK[n.ordinal][t],a=Math.floor(r.getNumRawDataModules(t)/8),u=i-a%i,l=Math.floor(a/i),h=[],c=r.reedSolomonComputeDivisor(o),f=0,v=0;i>f;f++){var d=e.slice(v,v+l-o+(u>f?0:1));v+=d.length;var m=r.reedSolomonComputeRemainder(d,c);u>f&&d.push(0),h.push(d.concat(m))}for(var g=[],y=function(e){h.forEach((function(t,n){e==l-o&&u>n||g.push(t[e])}))},E=0;h[0].length>E;E++)y(E);return s(g.length==a),g}},{key:"drawCodewords",value:function(e){if(e.length!=Math.floor(r.getNumRawDataModules(this.version)/8))throw new RangeError("Invalid argument");for(var t=0,n=this.size-1;n>=1;n-=2){6==n&&(n=5);for(var i=0;this.size>i;i++)for(var o=0;2>o;o++){var u=n-o,l=0==(n+1&2)?this.size-1-i:i;!this.isFunction[l][u]&&8*e.length>t&&(this.modules[l][u]=a(e[t>>>3],7-(7&t)),t++)}}s(t==8*e.length)}},{key:"applyMask",value:function(e){if(0>e||e>7)throw new RangeError("Mask value out of range");for(var t=0;this.size>t;t++)for(var n=0;this.size>n;n++){var r=void 0;switch(e){case 0:r=(n+t)%2==0;break;case 1:r=t%2==0;break;case 2:r=n%3==0;break;case 3:r=(n+t)%3==0;break;case 4:r=(Math.floor(n/3)+Math.floor(t/2))%2==0;break;case 5:r=n*t%2+n*t%3==0;break;case 6:r=(n*t%2+n*t%3)%2==0;break;case 7:r=((n+t)%2+n*t%3)%2==0;break;default:throw Error("Unreachable")}!this.isFunction[t][n]&&r&&(this.modules[t][n]=!this.modules[t][n])}}},{key:"getPenaltyScore",value:function(){for(var e=0,t=0;this.size>t;t++){for(var n=!1,i=0,a=[0,0,0,0,0,0,0],u=0;this.size>u;u++)this.modules[t][u]==n?5==++i?e+=r.PENALTY_N1:i>5&&e++:(this.finderPenaltyAddHistory(i,a),n||(e+=this.finderPenaltyCountPatterns(a)*r.PENALTY_N3),n=this.modules[t][u],i=1);e+=this.finderPenaltyTerminateAndCount(n,i,a)*r.PENALTY_N3}for(var l=0;this.size>l;l++){for(var h=!1,c=0,f=[0,0,0,0,0,0,0],v=0;this.size>v;v++)this.modules[v][l]==h?5==++c?e+=r.PENALTY_N1:c>5&&e++:(this.finderPenaltyAddHistory(c,f),h||(e+=this.finderPenaltyCountPatterns(f)*r.PENALTY_N3),h=this.modules[v][l],c=1);e+=this.finderPenaltyTerminateAndCount(h,c,f)*r.PENALTY_N3}for(var d=0;this.size-1>d;d++)for(var m=0;this.size-1>m;m++){var g=this.modules[d][m];g==this.modules[d][m+1]&&g==this.modules[d+1][m]&&g==this.modules[d+1][m+1]&&(e+=r.PENALTY_N2)}var y,E=0,w=o(this.modules);try{for(w.s();!(y=w.n()).done;){E=y.value.reduce((function(e,t){return e+(t?1:0)}),E)}}catch(e){w.e(e)}finally{w.f()}var M=this.size*this.size,C=Math.ceil(Math.abs(20*E-10*M)/M)-1;return s(C>=0&&9>=C),s((e+=C*r.PENALTY_N4)>=0&&2568888>=e),e}},{key:"getAlignmentPatternPositions",value:function(){if(1==this.version)return[];for(var e=Math.floor(this.version/7)+2,t=32==this.version?26:2*Math.ceil((4*this.version+4)/(2*e-2)),n=[6],r=this.size-7;e>n.length;r-=t)n.splice(1,0,r);return n}},{key:"finderPenaltyCountPatterns",value:function(e){var t=e[1];s(3*this.size>=t);var n=t>0&&e[2]==t&&e[3]==3*t&&e[4]==t&&e[5]==t;return(!n||4*t>e[0]||t>e[6]?0:1)+(!n||4*t>e[6]||t>e[0]?0:1)}},{key:"finderPenaltyTerminateAndCount",value:function(e,t,n){return e&&(this.finderPenaltyAddHistory(t,n),t=0),this.finderPenaltyAddHistory(t+=this.size,n),this.finderPenaltyCountPatterns(n)}},{key:"finderPenaltyAddHistory",value:function(e,t){0==t[0]&&(e+=this.size),t.pop(),t.unshift(e)}}],[{key:"encodeText",value:function(e,n){var i=t.QrSegment.makeSegments(e);return r.encodeSegments(i,n)}},{key:"encodeBinary",value:function(e,n){var i=t.QrSegment.makeBytes(e);return r.encodeSegments([i],n)}},{key:"encodeSegments",value:function(e,t){var n,a,l=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1,h=arguments.length>3&&void 0!==arguments[3]?arguments[3]:40,c=arguments.length>4&&void 0!==arguments[4]?arguments[4]:-1,f=5>=arguments.length||void 0===arguments[5]||arguments[5];if(r.MIN_VERSION>l||l>h||h>r.MAX_VERSION||-1>c||c>7)throw new RangeError("Invalid value");for(n=l;;n++){var v=8*r.getNumDataCodewords(n,t),d=u.getTotalBits(e,n);if(v>=d){a=d;break}if(n>=h)throw new RangeError("Data too long")}for(var m=0,g=[r.Ecc.MEDIUM,r.Ecc.QUARTILE,r.Ecc.HIGH];g.length>m;m++){var y=g[m];f&&a<=8*r.getNumDataCodewords(n,y)&&(t=y)}var E,w=[],M=o(e);try{for(M.s();!(E=M.n()).done;){var C=E.value;i(C.mode.modeBits,4,w),i(C.numChars,C.mode.numCharCountBits(n),w);var R,A=o(C.getData());try{for(A.s();!(R=A.n()).done;){var p=R.value;w.push(p)}}catch(e){A.e(e)}finally{A.f()}}}catch(e){M.e(e)}finally{M.f()}s(w.length==a);var P=8*r.getNumDataCodewords(n,t);s(P>=w.length),i(0,Math.min(4,P-w.length),w),i(0,(8-w.length%8)%8,w),s(w.length%8==0);for(var N=236;P>w.length;N^=253)i(N,8,w);for(var k=[];w.length>8*k.length;)k.push(0);return w.forEach((function(e,t){return k[t>>>3]|=e<<7-(7&t)})),new r(n,t,k,c)}},{key:"getNumRawDataModules",value:function(e){if(r.MIN_VERSION>e||e>r.MAX_VERSION)throw new RangeError("Version number out of range");var t=(16*e+128)*e+64;if(e>=2){var n=Math.floor(e/7)+2;t-=(25*n-10)*n-55,7>e||(t-=36)}return s(t>=208&&29648>=t),t}},{key:"getNumDataCodewords",value:function(e,t){return Math.floor(r.getNumRawDataModules(e)/8)-r.ECC_CODEWORDS_PER_BLOCK[t.ordinal][e]*r.NUM_ERROR_CORRECTION_BLOCKS[t.ordinal][e]}},{key:"reedSolomonComputeDivisor",value:function(e){if(1>e||e>255)throw new RangeError("Degree out of range");for(var t=[],n=0;e-1>n;n++)t.push(0);t.push(1);for(var i=1,o=0;e>o;o++){for(var a=0;t.length>a;a++)t[a]=r.reedSolomonMultiply(t[a],i),t.length>a+1&&(t[a]^=t[a+1]);i=r.reedSolomonMultiply(i,2)}return t}},{key:"reedSolomonComputeRemainder",value:function(e,t){var n,i=t.map((function(e){return 0})),a=o(e);try{var s=function(){var e=n.value^i.shift();i.push(0),t.forEach((function(t,n){return i[n]^=r.reedSolomonMultiply(t,e)}))};for(a.s();!(n=a.n()).done;)s()}catch(e){a.e(e)}finally{a.f()}return i}},{key:"reedSolomonMultiply",value:function(e,t){if(e>>>8!=0||t>>>8!=0)throw new RangeError("Byte out of range");for(var n=0,r=7;r>=0;r--)n=n<<1^285*(n>>>7),n^=(t>>>r&1)*e;return s(n>>>8==0),n}}]),r}();function i(e,t,n){if(0>t||t>31||e>>>t!=0)throw new RangeError("Value out of range");for(var r=t-1;r>=0;r--)n.push(e>>>r&1)}function a(e,t){return 0!=(e>>>t&1)}function s(e){if(!e)throw Error("Assertion error")}r.MIN_VERSION=1,r.MAX_VERSION=40,r.PENALTY_N1=3,r.PENALTY_N2=3,r.PENALTY_N3=40,r.PENALTY_N4=10,r.ECC_CODEWORDS_PER_BLOCK=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],r.NUM_ERROR_CORRECTION_BLOCKS=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]],t.QrCode=r;var u=function(){function t(n,r,i){if(e(this,t),this.mode=void 0,this.numChars=void 0,this.bitData=void 0,this.mode=n,this.numChars=r,this.bitData=i,0>r)throw new RangeError("Invalid argument");this.bitData=i.slice()}return n(t,[{key:"getData",value:function(){return this.bitData.slice()}}],[{key:"makeBytes",value:function(e){var n,r=[],a=o(e);try{for(a.s();!(n=a.n()).done;){i(n.value,8,r)}}catch(e){a.e(e)}finally{a.f()}return new t(t.Mode.BYTE,e.length,r)}},{key:"makeNumeric",value:function(e){if(!t.isNumeric(e))throw new RangeError("String contains non-numeric characters");for(var n=[],r=0;e.length>r;){var o=Math.min(e.length-r,3);i(parseInt(e.substring(r,r+o),10),3*o+1,n),r+=o}return new t(t.Mode.NUMERIC,e.length,n)}},{key:"makeAlphanumeric",value:function(e){if(!t.isAlphanumeric(e))throw new RangeError("String contains unencodable characters in alphanumeric mode");var n,r=[];for(n=0;e.length>=n+2;n+=2){var o=45*t.ALPHANUMERIC_CHARSET.indexOf(e.charAt(n));i(o+=t.ALPHANUMERIC_CHARSET.indexOf(e.charAt(n+1)),11,r)}return e.length>n&&i(t.ALPHANUMERIC_CHARSET.indexOf(e.charAt(n)),6,r),new t(t.Mode.ALPHANUMERIC,e.length,r)}},{key:"makeSegments",value:function(e){return""==e?[]:t.isNumeric(e)?[t.makeNumeric(e)]:t.isAlphanumeric(e)?[t.makeAlphanumeric(e)]:[t.makeBytes(t.toUtf8ByteArray(e))]}},{key:"makeEci",value:function(e){var n=[];if(0>e)throw new RangeError("ECI assignment value out of range");if(128>e)i(e,8,n);else if(16384>e)i(2,2,n),i(e,14,n);else{if(e>=1e6)throw new RangeError("ECI assignment value out of range");i(6,3,n),i(e,21,n)}return new t(t.Mode.ECI,0,n)}},{key:"isNumeric",value:function(e){return t.NUMERIC_REGEX.test(e)}},{key:"isAlphanumeric",value:function(e){return t.ALPHANUMERIC_REGEX.test(e)}},{key:"getTotalBits",value:function(e,t){var n,r=0,i=o(e);try{for(i.s();!(n=i.n()).done;){var a=n.value,s=a.mode.numCharCountBits(t);if(a.numChars>=1<<s)return 1/0;r+=4+s+a.bitData.length}}catch(e){i.e(e)}finally{i.f()}return r}},{key:"toUtf8ByteArray",value:function(e){e=encodeURI(e);for(var t=[],n=0;e.length>n;n++)"%"!=e.charAt(n)?t.push(e.charCodeAt(n)):(t.push(parseInt(e.substring(n+1,n+3),16)),n+=2);return t}}]),t}();u.NUMERIC_REGEX=/^[0-9]*$/,u.ALPHANUMERIC_REGEX=/^[A-Z0-9 $%*+.\/:-]*$/,u.ALPHANUMERIC_CHARSET="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:",t.QrSegment=u}(a||(a={})),function(t){!function(t){var r=n((function t(n,r){e(this,t),this.ordinal=void 0,this.formatBits=void 0,this.ordinal=n,this.formatBits=r}));r.LOW=new r(0,1),r.MEDIUM=new r(1,0),r.QUARTILE=new r(2,3),r.HIGH=new r(3,2),t.Ecc=r}(t.QrCode||(t.QrCode={}))}(a||(a={})),function(t){!function(t){var r=function(){function t(n,r){e(this,t),this.modeBits=void 0,this.numBitsCharCount=void 0,this.modeBits=n,this.numBitsCharCount=r}return n(t,[{key:"numCharCountBits",value:function(e){return this.numBitsCharCount[Math.floor((e+7)/17)]}}]),t}();r.NUMERIC=new r(1,[10,12,14]),r.ALPHANUMERIC=new r(2,[9,11,13]),r.BYTE=new r(4,[8,16,16]),r.KANJI=new r(8,[8,10,12]),r.ECI=new r(7,[0,0,0]),t.Mode=r}(t.QrSegment||(t.QrSegment={}))}(a||(a={}));var s=a,u=["value","size","level","bgColor","fgColor","includeMargin","marginSize","imageSettings"],l={L:s.QrCode.Ecc.LOW,M:s.QrCode.Ecc.MEDIUM,Q:s.QrCode.Ecc.QUARTILE,H:s.QrCode.Ecc.HIGH};function h(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=[];return e.forEach((function(e,r){var i=null;e.forEach((function(o,a){if(!o&&null!==i)return n.push("M".concat(i+t," ").concat(r+t,"h").concat(a-i,"v1H").concat(i+t,"z")),void(i=null);if(a!==e.length-1)o&&null===i&&(i=a);else{if(!o)return;n.push(null===i?"M".concat(a+t,",").concat(r+t," h1v1H").concat(a+t,"z"):"M".concat(i+t,",").concat(r+t," h").concat(a+1-i,"v1H").concat(i+t,"z"))}}))})),n.join("")}function c(e,t){return e.slice().map((function(e,n){return t.y>n||n>=t.y+t.h?e:e.map((function(e,n){return(t.x>n||n>=t.x+t.w)&&e}))}))}var f=function(){function t(n,r){var i=this;for(var o in e(this,t),this.canvas=void 0,this.pixelRatio="undefined"!=typeof window?window.devicePixelRatio:1,this.path2D=!0,this.SUPPORTS_PATH2D=void 0,this.createImage=function(){return new Image},this.createPath2D=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:void 0,t="createPath2D";return i.canvas&&t in i.canvas?i.canvas[t](e):new Path2D(e)},this.canvas=n,r)o in this&&(this[o]=r[o]);this.SUPPORTS_PATH2D=function(){try{i.createPath2D()}catch(e){return!1}return!0}()}return n(t,[{key:"render",value:function(e,t){var n=this,i=e.value,o=e.size,a=void 0===o?128:o,f=e.level,v=void 0===f?"L":f,d=e.bgColor,m=void 0===d?"#FFFFFF":d,g=e.fgColor,y=void 0===g?"#000000":g,E=e.includeMargin,w=void 0!==E&&E,M=e.marginSize,C=e.imageSettings,R=(r(e,u),null==C?void 0:C.src),A=this.canvas,p=A.getContext("2d");if(p&&i){var P=s.QrCode.encodeText(i,l[v]).getModules(),N=function(e,t){return null!=t?Math.floor(t):e?4:0}(w,M),k=P.length+2*N,S=function(e,t,n,r){if(null==r)return null;var i=e.length+2*n,o=Math.floor(.1*t),a=i/t,s=(r.width||o)*a,u=(r.height||o)*a,l=null==r.x?e.length/2-s/2:r.x*a,h=null==r.y?e.length/2-u/2:r.y*a,c=null;if(r.excavate){var f=Math.floor(l),v=Math.floor(h);c={x:f,y:v,w:Math.ceil(s+l-f),h:Math.ceil(u+h-v)}}return{x:l,y:h,h:u,w:s,excavation:c}}(P,a,N,C),I=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,r=null!=S&&null!==e&&e.complete&&0!==e.naturalHeight&&0!==e.naturalWidth;r&&null!=S.excavation&&(P=c(P,S.excavation)),t&&t(P);var i=n.pixelRatio;p.clearRect(0,0,A.width,A.height),p.setTransform(1,0,0,1,0,0),A.height=A.width=a*i;var o=a/k*i;if(p.scale(o,o),p.fillStyle=m,p.fillRect(0,0,k,k),p.fillStyle=y,n.SUPPORTS_PATH2D&&n.path2D){var s=n.createPath2D(h(P,N));p.fill(s)}else P.forEach((function(e,t){e.forEach((function(e,n){e&&p.fillRect(n+N,t+N,1,1)}))}));var u=(null==e?void 0:e.path)||e;r&&p.drawImage(u,S.x+N,S.y+N,S.w,S.h),"draw"in p&&p.draw()};if(R){var b=this.createImage(A);b.onload=function(){I(b)},b.onerror=function(e){I(),console.warn(e)},b.src=R}else I()}}}]),t}();export{f as QRCodeCanvas};
uni_modules/lime-qrcode/components/l-qrcode/type.ts
对比新文件
@@ -0,0 +1,48 @@
// @ts-nocheck
export type ImageSettings = {
    width: number
    height: number
    x?: number
    y?: number
    excavate: boolean
}
export type QRCodePropsTypes = {
    value?: string
    size?: number
    fgColor?: string
    level?: string
    marginSize: number
    includeMargin: boolean
    imageSettings?: ImageSettings
}
export type QRCodeCallback = (cells : boolean[][]) => void
export type Excavation = {
    x: number
    y: number
    h: number
    w: number
}
/**
 * 成功回调函数定义
 */
export type TakeSnapshotSuccessCallback = (res: TakeSnapshotSuccess) => void
/**
 * 失败回调函数定义
 */
export type TakeSnapshotFailCallback = (res: TakeSnapshotFail) => void
/**
 * 完成回调函数定义
 */
export type TakeSnapshotCompleteCallback = (res: any) => void
export type LQrcodeFailCallback = TakeSnapshotFailCallback
export type LQrcodeCompleteCallback = TakeSnapshotCompleteCallback
export type LQrcodeSuccessCallback  = TakeSnapshotSuccessCallback
uni_modules/lime-qrcode/components/l-qrcode/useCanvas.ts
对比新文件
@@ -0,0 +1,78 @@
// @ts-nocheck
import type { ComponentInternalInstance } from '@/uni_modules/lime-shared/vue'
import { getRect } from '@/uni_modules/lime-shared/getRect'
import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
export const isCanvas2d = canIUseCanvas2d()
export async function getCanvas(canvasId: string, options: {context: ComponentInternalInstance}) {
    let { context } = options
    // #ifdef MP || VUE2
    if (context.proxy) context = context.proxy
    // #endif
    return getRect('#' + canvasId, context, isCanvas2d).then(res => {
        if(res.node){
            return res.node
        } else {
            const ctx = uni.createCanvasContext(canvasId, context)
            return {
                getContext(type: string) {
                    if(type == '2d') {
                        return ctx
                    }
                },
                width: res.width,
                height: res.height,
            }
            // #ifdef H5
            // canvas.value = context.proxy.$el.querySelector('#'+ canvasId)
            // #endif
        }
    })
}
// #ifndef H5 || APP-NVUE
class Image {
    currentSrc: string | null = null
    naturalHeight: number = 0
    naturalWidth: number = 0
    width: number = 0
    height: number = 0
    tagName: string = 'IMG'
    path: any = ''
    crossOrigin: any = ''
    referrerPolicy: any = ''
    onload: () => void
    onerror: () => void
    constructor() {}
    set src(src) {
        this.currentSrc = src
        uni.getImageInfo({
            src,
            success: (res) => {
                this.path = res.path
                this.naturalWidth = this.width = res.width
                this.naturalHeight = this.height = res.height
                this.onload()
            },
            fail: () => {
                this.onerror()
            }
        })
    }
    get src() {
        return this.currentSrc
    }
}
// #endif
export function createImage(canvas: WechatMiniprogram.Canvas) {
    if(canvas && canvas.createImage) {
        return canvas.createImage()
    } else if(typeof window != 'undefined' && window.Image) {
        return new window.Image()
    }
    // #ifndef H5 || APP-NVUE
    return new Image()
    // #endif
}
uni_modules/lime-qrcode/components/l-qrcode/utils.uts
对比新文件
@@ -0,0 +1,35 @@
export function addUnit(value: any|null):string{
    if(value == null){
        return ''
    }
    value = `${value}`
    return /^(-)?\d+(\\.\d+)?$/.test(value) ?  `${value}px` : value
}
export function unitConvert(value: any|null): number{
    if(typeof value == 'number'){
        return value as number
    }
    if(typeof value == 'string'){
        value = `${value}`
        if(/^(-)?\d+(\\.\d+)?$/.test(value)){
            return parseFloat(value);
        }
        const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g;
        const results = reg.exec(value);
        if (results == null) {
            return 0;
        }
        const unit = results[3];
        const v = parseFloat(value);
        if (unit == 'rpx') {
            const { windowWidth } = uni.getWindowInfo()
            return windowWidth / 750 * v;
        }
        if (unit == 'px') {
            return v;
        }
    }
    return 0;
}
uni_modules/lime-qrcode/components/lime-qrcode/lime-qrcode.uvue
对比新文件
@@ -0,0 +1,140 @@
<template>
    <view class="demo-block">
        <text class="demo-block__title-text ultra">QRCode</text>
        <text class="demo-block__desc-text">能够将文本转换生成二维码的组件,支持自定义配色和 Logo 配置</text>
        <view class="demo-block__body">
            <view class="demo-block card">
                <text class="demo-block__title-text large">基础</text>
                <view class="demo-block__body">
                    <l-qrcode value="https://limeui.qcoon.cn" size="300rpx"></l-qrcode>
                </view>
            </view>
            <view class="demo-block card">
                <text class="demo-block__title-text large">icon</text>
                <view class="demo-block__body">
                    <image v-if="image !=''" :src="image" style="width: 300rpx;" mode="widthFix"></image>
                    <view style="flex-direction: row; justify-content: space-between">
                        <l-qrcode ref="qrcodeRef" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
                        <l-qrcode :useCanvasToTempFilePath="true" @success="success" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
                    </view>
                    <button type="primary" style="margin-top: 20rpx;" @click="onClick">生成图片</button>
                </view>
            </view>
            <view class="demo-block card">
                <text class="demo-block__title-text large">颜色</text>
                <view class="demo-block__body">
                    <view style="flex-direction: row; justify-content: space-between">
                        <l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(82,196,26)"></l-qrcode>
                        <l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(22,119,255)" bgColor="rgb(245,245,245)"></l-qrcode>
                    </view>
                </view>
            </view>
            <view class="demo-block card">
                <text class="demo-block__title-text large">纠错比例</text>
                <view class="demo-block__body">
                    <l-qrcode value="img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" size="300rpx" :errorLevel="levels[index]"></l-qrcode>
                    <button type="primary" style="margin-top: 20rpx;" @click="onToggle">切换纠错等级:{{levels[index]}}</button>
                </view>
            </view>
            <view class="demo-block card">
                <text class="demo-block__title-text large">动态</text>
                <view class="demo-block__body">
                    <l-qrcode :value="text" size="300rpx" :marginSize="1" bgColor="white"></l-qrcode>
                    <button type="primary" style="margin-top: 20rpx;"  @click="update">更新</button>
                </view>
            </view>
        </view>
    </view>
</template>
<script>
    // import {ComponentPublicInstance} from 'vue'
    export default {
        name: 'lime-qrcode',
        data() {
            return {
                text: 'qcoon.com.cn',
                image: '',
                index: 0,
                levels: ['L', 'M', 'Q', 'H']
            }
        },
        methods:{
            success(src: string) {
                console.log(`src`, src)
            },
            update() {
                this.text =  `qcoon.cn?v=${Math.random()}`
            },
            onToggle() {
                this.index++
                this.index = this.index % this.levels.length
            },
            onClick() {
                const el:LQrcodeComponentPublicInstance = this.$refs['qrcodeRef'] as LQrcodeComponentPublicInstance
                el.canvasToTempFilePath({
                    success:(res: TakeSnapshotSuccess)=>{
                        this.image = res.tempFilePath
                    }
                })
            }
        },
        mounted() {
        }
    }
</script>
<style lang="scss">
    .demo-block {
        margin: 32px 10px 0;
        overflow: visible;
        &.card{
            background-color: white;
            padding: 30rpx;
            margin-bottom: 20rpx;
        }
        &__title {
            margin: 0;
            margin-top: 8px;
            &-text {
                color: rgba(0, 0, 0, 0.6);
                font-weight: 400;
                font-size: 14px;
                line-height: 16px;
                &.large {
                    color: rgba(0, 0, 0, 0.9);
                    font-size: 18px;
                    font-weight: 700;
                    line-height: 26px;
                }
                &.ultra {
                    color: rgba(0, 0, 0, 0.9);
                    font-size: 24px;
                    font-weight: 700;
                    line-height: 32px;
                }
            }
        }
        &__desc-text {
            color: rgba(0, 0, 0, 0.6);
            margin: 8px 16px 0 0;
            font-size: 14px;
            line-height: 22px;
        }
        &__body {
            margin: 16px 0;
            overflow: visible;
            .demo-block {
                // margin-top: 0px;
                margin: 0;
            }
        }
    }
</style>
uni_modules/lime-qrcode/components/lime-qrcode/lime-qrcode.vue
对比新文件
@@ -0,0 +1,79 @@
<template>
    <demo-block title="QRCode" type="ultra">
        <demo-block title="基础">
            <l-qrcode value="https://limeui.qcoon.cn" size="300rpx"></l-qrcode>
        </demo-block>
         <demo-block title="icon">
            <view style="display: flex; gap: 10px">
                <image v-if="image" :src="image" style="width: 300rpx;" mode="widthFix"></image>
                <l-qrcode ref="qrcodeRef" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
                <l-qrcode useCanvasToTempFilePath @success="success" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
            </view>
            <button @click="onClick">生成图片</button>
        </demo-block>
        <demo-block title="颜色">
            <view style="display: flex; gap: 10px">
                <l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(82,196,26)"></l-qrcode>
                <l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(22,119,255)" bgColor="rgb(245,245,245)"></l-qrcode>
            </view>
        </demo-block>
        <demo-block title="纠错比例">
            <l-qrcode value="img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" size="300rpx" :errorLevel="levels[index]"></l-qrcode>
            <button @click="onToggle">切换纠错等级:{{levels[index]}}</button>
        </demo-block>
        <demo-block title="动态">
            <l-qrcode :value="text" size="300rpx" :marginSize="1" bgColor="white"></l-qrcode>
            <button @click="update">更新</button>
        </demo-block>
    </demo-block>
</template>
<script>
    import {ref, defineComponent} from '@/uni_modules/lime-shared/vue'
    export default defineComponent({
        setup() {
            const qrcodeRef = ref(null)
            const image = ref(null)
            const text = ref('qcoon.com.cn')
            const levels = ['L', 'M', 'Q', 'H']
            let index = ref(0)
            const onToggle = () => {
                index.value++
                index.value = index.value % levels.length
            }
            const onClick = () => {
                if(qrcodeRef.value) {
                    qrcodeRef.value.canvasToTempFilePath({
                        success(res) {
                            image.value = res.tempFilePath
                            console.log('success:::', res)
                        },
                        fail(err) {
                            console.log('err:::', err)
                        }
                    })
                }
            }
            const success = (res) => {
                console.log('res', res)
            }
            const update = () =>{
                text.value =  `qcoon.cn?v=${Math.random()}`
            }
            return {
                levels,
                index,
                image,
                text,
                qrcodeRef,
                onClick,
                update,
                success,
                onToggle,
            }
        }
    })
</script>
<style>
</style>
uni_modules/lime-qrcode/hybrid/html/index.html
对比新文件
@@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>lime-qrcode</title>
    <style>
        html,body,canvas {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            /* background-color: rgba(255,0,0,0.1) */
        }
    </style>
</head>
<body>
    <canvas id="lime-qrcode"></canvas>
    <script type="text/javascript" src="./uni.webview.1.5.3.js"></script>
    <script type="text/javascript" src="./qrcode.min.js"></script>
    <script>
        var canvas = document.querySelector('#lime-qrcode')
        var pixelRatio = window.devicePixelRatio || 1
        function appendWatermark(image) {
            emit('append', mark.toDataURL())
        }
        var qrcode = new lime.QRCodeCanvas(canvas, {
            pixelRatio,
        })
        function render(props) {
            if(props.pixelRatio) {
                pixelRatio = props.pixelRatio
            }
            if(qrcode) {
                qrcode.render(props)
            }
        }
        function toDataURL(file) {
            if(qrcode && canvas) {
                try{
                    const image = canvas.toDataURL()
                    emit('toDataURL', {
                        file,
                        image
                    })
                }catch(e){
                    emit('toDataURL', {
                        file,
                        msg: e
                    })
                }
            }
        }
        function emit(event, data) {
            postMessage({
                event,
                data
            });
        };
        function postMessage(data) {
            uni.postMessage({
                data
            });
        };
        // render({
        //     content: ['Lime UI'],
        //     // rotate: -22,
        //     // baseSize: 2,
        //     // fontGap: 3
        // })
    </script>
</body>
</html>
uni_modules/lime-qrcode/hybrid/html/qrcode.min.js
对比新文件
@@ -0,0 +1,6 @@
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).lime={})}(this,(function(e){"use strict";function t(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){for(var n=0;t.length>n;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}function r(e,t,r){return t&&n(e.prototype,t),r&&n(e,r),Object.defineProperty(e,"prototype",{writable:!1}),e}function i(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;o.length>r;r++)0>t.indexOf(n=o[r])&&(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;o.length>r;r++)0>t.indexOf(n=o[r])&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);t>n;n++)r[n]=e[n];return r}function a(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(e){if("string"==typeof e)return o(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?o(e,t):void 0}}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,i=function(){};return{s:i,n:function(){return e.length>r?{done:!1,value:e[r++]}:{done:!0}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,s=!0,u=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return s=e.done,e},e:function(e){u=!0,a=e},f:function(){try{s||null==n.return||n.return()}finally{if(u)throw a}}}}
/**
   * @license QR Code generator library (TypeScript)
   * Copyright (c) Project Nayuki.
   * SPDX-License-Identifier: MIT
   */var s;!function(e){var n=function(){function n(e,r,i,o){if(t(this,n),this.version=void 0,this.errorCorrectionLevel=void 0,this.size=void 0,this.mask=void 0,this.modules=[],this.isFunction=[],this.version=e,this.errorCorrectionLevel=r,n.MIN_VERSION>e||e>n.MAX_VERSION)throw new RangeError("Version value out of range");if(-1>o||o>7)throw new RangeError("Mask value out of range");this.size=4*e+17;for(var a=[],u=0;this.size>u;u++)a.push(!1);for(var l=0;this.size>l;l++)this.modules.push(a.slice()),this.isFunction.push(a.slice());this.drawFunctionPatterns();var h=this.addEccAndInterleave(i);if(this.drawCodewords(h),-1==o)for(var c=1e9,f=0;8>f;f++){this.applyMask(f),this.drawFormatBits(f);var d=this.getPenaltyScore();c>d&&(o=f,c=d),this.applyMask(f)}s(o>=0&&7>=o),this.mask=o,this.applyMask(o),this.drawFormatBits(o),this.isFunction=[]}return r(n,[{key:"getModule",value:function(e,t){return e>=0&&this.size>e&&t>=0&&this.size>t&&this.modules[t][e]}},{key:"getModules",value:function(){return this.modules}},{key:"drawFunctionPatterns",value:function(){for(var e=0;this.size>e;e++)this.setFunctionModule(6,e,e%2==0),this.setFunctionModule(e,6,e%2==0);this.drawFinderPattern(3,3),this.drawFinderPattern(this.size-4,3),this.drawFinderPattern(3,this.size-4);for(var t=this.getAlignmentPatternPositions(),n=t.length,r=0;n>r;r++)for(var i=0;n>i;i++)0==r&&0==i||0==r&&i==n-1||r==n-1&&0==i||this.drawAlignmentPattern(t[r],t[i]);this.drawFormatBits(0),this.drawVersion()}},{key:"drawFormatBits",value:function(e){for(var t=this.errorCorrectionLevel.formatBits<<3|e,n=t,r=0;10>r;r++)n=n<<1^1335*(n>>>9);var i=21522^(t<<10|n);s(i>>>15==0);for(var a=0;5>=a;a++)this.setFunctionModule(8,a,o(i,a));this.setFunctionModule(8,7,o(i,6)),this.setFunctionModule(8,8,o(i,7)),this.setFunctionModule(7,8,o(i,8));for(var u=9;15>u;u++)this.setFunctionModule(14-u,8,o(i,u));for(var l=0;8>l;l++)this.setFunctionModule(this.size-1-l,8,o(i,l));for(var h=8;15>h;h++)this.setFunctionModule(8,this.size-15+h,o(i,h));this.setFunctionModule(8,this.size-8,!0)}},{key:"drawVersion",value:function(){if(this.version>=7){for(var e=this.version,t=0;12>t;t++)e=e<<1^7973*(e>>>11);var n=this.version<<12|e;s(n>>>18==0);for(var r=0;18>r;r++){var i=o(n,r),a=this.size-11+r%3,u=Math.floor(r/3);this.setFunctionModule(a,u,i),this.setFunctionModule(u,a,i)}}}},{key:"drawFinderPattern",value:function(e,t){for(var n=-4;4>=n;n++)for(var r=-4;4>=r;r++){var i=Math.max(Math.abs(r),Math.abs(n)),o=e+r,a=t+n;o>=0&&this.size>o&&a>=0&&this.size>a&&this.setFunctionModule(o,a,2!=i&&4!=i)}}},{key:"drawAlignmentPattern",value:function(e,t){for(var n=-2;2>=n;n++)for(var r=-2;2>=r;r++)this.setFunctionModule(e+r,t+n,1!=Math.max(Math.abs(r),Math.abs(n)))}},{key:"setFunctionModule",value:function(e,t,n){this.modules[t][e]=n,this.isFunction[t][e]=!0}},{key:"addEccAndInterleave",value:function(e){var t=this.version,r=this.errorCorrectionLevel;if(e.length!=n.getNumDataCodewords(t,r))throw new RangeError("Invalid argument");for(var i=n.NUM_ERROR_CORRECTION_BLOCKS[r.ordinal][t],o=n.ECC_CODEWORDS_PER_BLOCK[r.ordinal][t],a=Math.floor(n.getNumRawDataModules(t)/8),u=i-a%i,l=Math.floor(a/i),h=[],c=n.reedSolomonComputeDivisor(o),f=0,d=0;i>f;f++){var v=e.slice(d,d+l-o+(u>f?0:1));d+=v.length;var m=n.reedSolomonComputeRemainder(v,c);u>f&&v.push(0),h.push(v.concat(m))}for(var g=[],y=function(e){h.forEach((function(t,n){e==l-o&&u>n||g.push(t[e])}))},E=0;h[0].length>E;E++)y(E);return s(g.length==a),g}},{key:"drawCodewords",value:function(e){if(e.length!=Math.floor(n.getNumRawDataModules(this.version)/8))throw new RangeError("Invalid argument");for(var t=0,r=this.size-1;r>=1;r-=2){6==r&&(r=5);for(var i=0;this.size>i;i++)for(var a=0;2>a;a++){var u=r-a,l=0==(r+1&2)?this.size-1-i:i;!this.isFunction[l][u]&&8*e.length>t&&(this.modules[l][u]=o(e[t>>>3],7-(7&t)),t++)}}s(t==8*e.length)}},{key:"applyMask",value:function(e){if(0>e||e>7)throw new RangeError("Mask value out of range");for(var t=0;this.size>t;t++)for(var n=0;this.size>n;n++){var r=void 0;switch(e){case 0:r=(n+t)%2==0;break;case 1:r=t%2==0;break;case 2:r=n%3==0;break;case 3:r=(n+t)%3==0;break;case 4:r=(Math.floor(n/3)+Math.floor(t/2))%2==0;break;case 5:r=n*t%2+n*t%3==0;break;case 6:r=(n*t%2+n*t%3)%2==0;break;case 7:r=((n+t)%2+n*t%3)%2==0;break;default:throw Error("Unreachable")}!this.isFunction[t][n]&&r&&(this.modules[t][n]=!this.modules[t][n])}}},{key:"getPenaltyScore",value:function(){for(var e=0,t=0;this.size>t;t++){for(var r=!1,i=0,o=[0,0,0,0,0,0,0],u=0;this.size>u;u++)this.modules[t][u]==r?5==++i?e+=n.PENALTY_N1:i>5&&e++:(this.finderPenaltyAddHistory(i,o),r||(e+=this.finderPenaltyCountPatterns(o)*n.PENALTY_N3),r=this.modules[t][u],i=1);e+=this.finderPenaltyTerminateAndCount(r,i,o)*n.PENALTY_N3}for(var l=0;this.size>l;l++){for(var h=!1,c=0,f=[0,0,0,0,0,0,0],d=0;this.size>d;d++)this.modules[d][l]==h?5==++c?e+=n.PENALTY_N1:c>5&&e++:(this.finderPenaltyAddHistory(c,f),h||(e+=this.finderPenaltyCountPatterns(f)*n.PENALTY_N3),h=this.modules[d][l],c=1);e+=this.finderPenaltyTerminateAndCount(h,c,f)*n.PENALTY_N3}for(var v=0;this.size-1>v;v++)for(var m=0;this.size-1>m;m++){var g=this.modules[v][m];g==this.modules[v][m+1]&&g==this.modules[v+1][m]&&g==this.modules[v+1][m+1]&&(e+=n.PENALTY_N2)}var y,E=0,w=a(this.modules);try{for(w.s();!(y=w.n()).done;){E=y.value.reduce((function(e,t){return e+(t?1:0)}),E)}}catch(e){w.e(e)}finally{w.f()}var M=this.size*this.size,C=Math.ceil(Math.abs(20*E-10*M)/M)-1;return s(C>=0&&9>=C),s((e+=C*n.PENALTY_N4)>=0&&2568888>=e),e}},{key:"getAlignmentPatternPositions",value:function(){if(1==this.version)return[];for(var e=Math.floor(this.version/7)+2,t=32==this.version?26:2*Math.ceil((4*this.version+4)/(2*e-2)),n=[6],r=this.size-7;e>n.length;r-=t)n.splice(1,0,r);return n}},{key:"finderPenaltyCountPatterns",value:function(e){var t=e[1];s(3*this.size>=t);var n=t>0&&e[2]==t&&e[3]==3*t&&e[4]==t&&e[5]==t;return(!n||4*t>e[0]||t>e[6]?0:1)+(!n||4*t>e[6]||t>e[0]?0:1)}},{key:"finderPenaltyTerminateAndCount",value:function(e,t,n){return e&&(this.finderPenaltyAddHistory(t,n),t=0),this.finderPenaltyAddHistory(t+=this.size,n),this.finderPenaltyCountPatterns(n)}},{key:"finderPenaltyAddHistory",value:function(e,t){0==t[0]&&(e+=this.size),t.pop(),t.unshift(e)}}],[{key:"encodeText",value:function(t,r){var i=e.QrSegment.makeSegments(t);return n.encodeSegments(i,r)}},{key:"encodeBinary",value:function(t,r){var i=e.QrSegment.makeBytes(t);return n.encodeSegments([i],r)}},{key:"encodeSegments",value:function(e,t){var r,o,l=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1,h=arguments.length>3&&void 0!==arguments[3]?arguments[3]:40,c=arguments.length>4&&void 0!==arguments[4]?arguments[4]:-1,f=5>=arguments.length||void 0===arguments[5]||arguments[5];if(n.MIN_VERSION>l||l>h||h>n.MAX_VERSION||-1>c||c>7)throw new RangeError("Invalid value");for(r=l;;r++){var d=8*n.getNumDataCodewords(r,t),v=u.getTotalBits(e,r);if(d>=v){o=v;break}if(r>=h)throw new RangeError("Data too long")}for(var m=0,g=[n.Ecc.MEDIUM,n.Ecc.QUARTILE,n.Ecc.HIGH];g.length>m;m++){var y=g[m];f&&o<=8*n.getNumDataCodewords(r,y)&&(t=y)}var E,w=[],M=a(e);try{for(M.s();!(E=M.n()).done;){var C=E.value;i(C.mode.modeBits,4,w),i(C.numChars,C.mode.numCharCountBits(r),w);var R,p=a(C.getData());try{for(p.s();!(R=p.n()).done;){var A=R.value;w.push(A)}}catch(e){p.e(e)}finally{p.f()}}}catch(e){M.e(e)}finally{M.f()}s(w.length==o);var P=8*n.getNumDataCodewords(r,t);s(P>=w.length),i(0,Math.min(4,P-w.length),w),i(0,(8-w.length%8)%8,w),s(w.length%8==0);for(var N=236;P>w.length;N^=253)i(N,8,w);for(var k=[];w.length>8*k.length;)k.push(0);return w.forEach((function(e,t){return k[t>>>3]|=e<<7-(7&t)})),new n(r,t,k,c)}},{key:"getNumRawDataModules",value:function(e){if(n.MIN_VERSION>e||e>n.MAX_VERSION)throw new RangeError("Version number out of range");var t=(16*e+128)*e+64;if(e>=2){var r=Math.floor(e/7)+2;t-=(25*r-10)*r-55,7>e||(t-=36)}return s(t>=208&&29648>=t),t}},{key:"getNumDataCodewords",value:function(e,t){return Math.floor(n.getNumRawDataModules(e)/8)-n.ECC_CODEWORDS_PER_BLOCK[t.ordinal][e]*n.NUM_ERROR_CORRECTION_BLOCKS[t.ordinal][e]}},{key:"reedSolomonComputeDivisor",value:function(e){if(1>e||e>255)throw new RangeError("Degree out of range");for(var t=[],r=0;e-1>r;r++)t.push(0);t.push(1);for(var i=1,o=0;e>o;o++){for(var a=0;t.length>a;a++)t[a]=n.reedSolomonMultiply(t[a],i),t.length>a+1&&(t[a]^=t[a+1]);i=n.reedSolomonMultiply(i,2)}return t}},{key:"reedSolomonComputeRemainder",value:function(e,t){var r,i=t.map((function(e){return 0})),o=a(e);try{var s=function(){var e=r.value^i.shift();i.push(0),t.forEach((function(t,r){return i[r]^=n.reedSolomonMultiply(t,e)}))};for(o.s();!(r=o.n()).done;)s()}catch(e){o.e(e)}finally{o.f()}return i}},{key:"reedSolomonMultiply",value:function(e,t){if(e>>>8!=0||t>>>8!=0)throw new RangeError("Byte out of range");for(var n=0,r=7;r>=0;r--)n=n<<1^285*(n>>>7),n^=(t>>>r&1)*e;return s(n>>>8==0),n}}]),n}();function i(e,t,n){if(0>t||t>31||e>>>t!=0)throw new RangeError("Value out of range");for(var r=t-1;r>=0;r--)n.push(e>>>r&1)}function o(e,t){return 0!=(e>>>t&1)}function s(e){if(!e)throw Error("Assertion error")}n.MIN_VERSION=1,n.MAX_VERSION=40,n.PENALTY_N1=3,n.PENALTY_N2=3,n.PENALTY_N3=40,n.PENALTY_N4=10,n.ECC_CODEWORDS_PER_BLOCK=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],n.NUM_ERROR_CORRECTION_BLOCKS=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]],e.QrCode=n;var u=function(){function e(n,r,i){if(t(this,e),this.mode=void 0,this.numChars=void 0,this.bitData=void 0,this.mode=n,this.numChars=r,this.bitData=i,0>r)throw new RangeError("Invalid argument");this.bitData=i.slice()}return r(e,[{key:"getData",value:function(){return this.bitData.slice()}}],[{key:"makeBytes",value:function(t){var n,r=[],o=a(t);try{for(o.s();!(n=o.n()).done;){i(n.value,8,r)}}catch(e){o.e(e)}finally{o.f()}return new e(e.Mode.BYTE,t.length,r)}},{key:"makeNumeric",value:function(t){if(!e.isNumeric(t))throw new RangeError("String contains non-numeric characters");for(var n=[],r=0;t.length>r;){var o=Math.min(t.length-r,3);i(parseInt(t.substring(r,r+o),10),3*o+1,n),r+=o}return new e(e.Mode.NUMERIC,t.length,n)}},{key:"makeAlphanumeric",value:function(t){if(!e.isAlphanumeric(t))throw new RangeError("String contains unencodable characters in alphanumeric mode");var n,r=[];for(n=0;t.length>=n+2;n+=2){var o=45*e.ALPHANUMERIC_CHARSET.indexOf(t.charAt(n));i(o+=e.ALPHANUMERIC_CHARSET.indexOf(t.charAt(n+1)),11,r)}return t.length>n&&i(e.ALPHANUMERIC_CHARSET.indexOf(t.charAt(n)),6,r),new e(e.Mode.ALPHANUMERIC,t.length,r)}},{key:"makeSegments",value:function(t){return""==t?[]:e.isNumeric(t)?[e.makeNumeric(t)]:e.isAlphanumeric(t)?[e.makeAlphanumeric(t)]:[e.makeBytes(e.toUtf8ByteArray(t))]}},{key:"makeEci",value:function(t){var n=[];if(0>t)throw new RangeError("ECI assignment value out of range");if(128>t)i(t,8,n);else if(16384>t)i(2,2,n),i(t,14,n);else{if(t>=1e6)throw new RangeError("ECI assignment value out of range");i(6,3,n),i(t,21,n)}return new e(e.Mode.ECI,0,n)}},{key:"isNumeric",value:function(t){return e.NUMERIC_REGEX.test(t)}},{key:"isAlphanumeric",value:function(t){return e.ALPHANUMERIC_REGEX.test(t)}},{key:"getTotalBits",value:function(e,t){var n,r=0,i=a(e);try{for(i.s();!(n=i.n()).done;){var o=n.value,s=o.mode.numCharCountBits(t);if(o.numChars>=1<<s)return 1/0;r+=4+s+o.bitData.length}}catch(e){i.e(e)}finally{i.f()}return r}},{key:"toUtf8ByteArray",value:function(e){e=encodeURI(e);for(var t=[],n=0;e.length>n;n++)"%"!=e.charAt(n)?t.push(e.charCodeAt(n)):(t.push(parseInt(e.substring(n+1,n+3),16)),n+=2);return t}}]),e}();u.NUMERIC_REGEX=/^[0-9]*$/,u.ALPHANUMERIC_REGEX=/^[A-Z0-9 $%*+.\/:-]*$/,u.ALPHANUMERIC_CHARSET="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:",e.QrSegment=u}(s||(s={})),function(e){!function(e){var n=r((function e(n,r){t(this,e),this.ordinal=void 0,this.formatBits=void 0,this.ordinal=n,this.formatBits=r}));n.LOW=new n(0,1),n.MEDIUM=new n(1,0),n.QUARTILE=new n(2,3),n.HIGH=new n(3,2),e.Ecc=n}(e.QrCode||(e.QrCode={}))}(s||(s={})),function(e){!function(e){var n=function(){function e(n,r){t(this,e),this.modeBits=void 0,this.numBitsCharCount=void 0,this.modeBits=n,this.numBitsCharCount=r}return r(e,[{key:"numCharCountBits",value:function(e){return this.numBitsCharCount[Math.floor((e+7)/17)]}}]),e}();n.NUMERIC=new n(1,[10,12,14]),n.ALPHANUMERIC=new n(2,[9,11,13]),n.BYTE=new n(4,[8,16,16]),n.KANJI=new n(8,[8,10,12]),n.ECI=new n(7,[0,0,0]),e.Mode=n}(e.QrSegment||(e.QrSegment={}))}(s||(s={}));var u=s,l=["value","size","level","bgColor","fgColor","includeMargin","marginSize","imageSettings"],h={L:u.QrCode.Ecc.LOW,M:u.QrCode.Ecc.MEDIUM,Q:u.QrCode.Ecc.QUARTILE,H:u.QrCode.Ecc.HIGH};function c(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=[];return e.forEach((function(e,r){var i=null;e.forEach((function(o,a){if(!o&&null!==i)return n.push("M".concat(i+t," ").concat(r+t,"h").concat(a-i,"v1H").concat(i+t,"z")),void(i=null);if(a!==e.length-1)o&&null===i&&(i=a);else{if(!o)return;n.push(null===i?"M".concat(a+t,",").concat(r+t," h1v1H").concat(a+t,"z"):"M".concat(i+t,",").concat(r+t," h").concat(a+1-i,"v1H").concat(i+t,"z"))}}))})),n.join("")}function f(e,t){return e.slice().map((function(e,n){return t.y>n||n>=t.y+t.h?e:e.map((function(e,n){return(t.x>n||n>=t.x+t.w)&&e}))}))}var d=function(){function e(n,r){var i=this;for(var o in t(this,e),this.canvas=void 0,this.pixelRatio="undefined"!=typeof window?window.devicePixelRatio:1,this.path2D=!0,this.SUPPORTS_PATH2D=void 0,this.createImage=function(){return new Image},this.createPath2D=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:void 0,t="createPath2D";return i.canvas&&t in i.canvas?i.canvas[t](e):new Path2D(e)},this.canvas=n,r)o in this&&(this[o]=r[o]);this.SUPPORTS_PATH2D=function(){try{i.createPath2D()}catch(e){return!1}return!0}()}return r(e,[{key:"render",value:function(e,t){var n=this,r=e.value,o=e.size,a=void 0===o?128:o,s=e.level,d=void 0===s?"L":s,v=e.bgColor,m=void 0===v?"#FFFFFF":v,g=e.fgColor,y=void 0===g?"#000000":g,E=e.includeMargin,w=void 0!==E&&E,M=e.marginSize,C=e.imageSettings,R=(i(e,l),null==C?void 0:C.src),p=this.canvas,A=p.getContext("2d");if(A&&r){var P=u.QrCode.encodeText(r,h[d]).getModules(),N=function(e,t){return null!=t?Math.floor(t):e?4:0}(w,M),k=P.length+2*N,S=function(e,t,n,r){if(null==r)return null;var i=e.length+2*n,o=Math.floor(.1*t),a=i/t,s=(r.width||o)*a,u=(r.height||o)*a,l=null==r.x?e.length/2-s/2:r.x*a,h=null==r.y?e.length/2-u/2:r.y*a,c=null;if(r.excavate){var f=Math.floor(l),d=Math.floor(h);c={x:f,y:d,w:Math.ceil(s+l-f),h:Math.ceil(u+h-d)}}return{x:l,y:h,h:u,w:s,excavation:c}}(P,a,N,C),I=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,r=null!=S&&null!==e&&e.complete&&0!==e.naturalHeight&&0!==e.naturalWidth;r&&null!=S.excavation&&(P=f(P,S.excavation)),t&&t(P);var i=n.pixelRatio;A.clearRect(0,0,p.width,p.height),A.setTransform(1,0,0,1,0,0),p.height=p.width=a*i;var o=a/k*i;if(A.scale(o,o),A.fillStyle=m,A.fillRect(0,0,k,k),A.fillStyle=y,n.SUPPORTS_PATH2D&&n.path2D){var s=n.createPath2D(c(P,N));A.fill(s)}else P.forEach((function(e,t){e.forEach((function(e,n){e&&A.fillRect(n+N,t+N,1,1)}))}));var u=(null==e?void 0:e.path)||e;r&&A.drawImage(u,S.x+N,S.y+N,S.w,S.h),"draw"in A&&A.draw()};if(R){var b=this.createImage(p);b.onload=function(){I(b)},b.onerror=function(e){I(),console.warn(e)},b.src=R}else I()}}}]),e}();e.QRCodeCanvas=d,Object.defineProperty(e,"__esModule",{value:!0})}));
uni_modules/lime-qrcode/hybrid/html/uni.webview.1.5.3.js
对比新文件
@@ -0,0 +1 @@
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).uni=n()}(this,(function(){"use strict";try{var e={};Object.defineProperty(e,"passive",{get:function(){!0}}),window.addEventListener("test-passive",null,e)}catch(e){}var n=Object.prototype.hasOwnProperty;function i(e,i){return n.call(e,i)}var t=[];function o(){return window.__dcloud_weex_postMessage||window.__dcloud_weex_}var r=function(e,n){var i={options:{timestamp:+new Date},name:e,arg:n};if(o()){if("postMessage"===e){var r={data:[n]};return window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessage(r):window.__dcloud_weex_.postMessage(JSON.stringify(r))}var a={type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}};window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessageToService(a):window.__dcloud_weex_.postMessageToService(JSON.stringify(a))}if(!window.plus)return window.parent.postMessage({type:"WEB_INVOKE_APPSERVICE",data:i,pageId:""},"*");if(0===t.length){var d=plus.webview.currentWebview();if(!d)throw new Error("plus.webview.currentWebview() is undefined");var s=d.parent(),w="";w=s?s.id:d.id,t.push(w)}if(plus.webview.getWebviewById("__uniapp__service"))plus.webview.postMessageToUniNView({type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}},"__uniapp__service");else{var u=JSON.stringify(i);plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat("WEB_INVOKE_APPSERVICE",'",').concat(u,",").concat(JSON.stringify(t),");"))}},a={navigateTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("navigateTo",{url:encodeURI(n)})},navigateBack:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.delta;r("navigateBack",{delta:parseInt(n)||1})},switchTab:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("switchTab",{url:encodeURI(n)})},reLaunch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("reLaunch",{url:encodeURI(n)})},redirectTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("redirectTo",{url:encodeURI(n)})},getEnv:function(e){o()?e({nvue:!0}):window.plus?e({plus:!0}):e({h5:!0})},postMessage:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};r("postMessage",e.data||{})}},d=/uni-app/i.test(navigator.userAgent),s=/Html5Plus/i.test(navigator.userAgent),w=/complete|loaded|interactive/;var u=window.my&&navigator.userAgent.indexOf("AlipayClient")>-1;var g=window.swan&&window.swan.webView&&/swan/i.test(navigator.userAgent);var c=window.qq&&window.qq.miniProgram&&/QQ/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var v=window.tt&&window.tt.miniProgram&&/toutiaomicroapp/i.test(navigator.userAgent);var m=window.wx&&window.wx.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var p=window.qa&&/quickapp/i.test(navigator.userAgent);var f=window.ks&&window.ks.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var l=window.tt&&window.tt.miniProgram&&/Lark|Feishu/i.test(navigator.userAgent);var _=window.jd&&window.jd.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);for(var E,b=function(){window.UniAppJSBridge=!0,document.dispatchEvent(new CustomEvent("UniAppJSBridgeReady",{bubbles:!0,cancelable:!0}))},h=[function(e){if(d||s)return window.__dcloud_weex_postMessage||window.__dcloud_weex_?document.addEventListener("DOMContentLoaded",e):window.plus&&w.test(document.readyState)?setTimeout(e,0):document.addEventListener("plusready",e),a},function(e){if(m)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.wx.miniProgram},function(e){if(c)return window.QQJSBridge&&window.QQJSBridge.invoke?setTimeout(e,0):document.addEventListener("QQJSBridgeReady",e),window.qq.miniProgram},function(e){if(u){document.addEventListener("DOMContentLoaded",e);var n=window.my;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(g)return document.addEventListener("DOMContentLoaded",e),window.swan.webView},function(e){if(v)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(p){window.QaJSBridge&&window.QaJSBridge.invoke?setTimeout(e,0):document.addEventListener("QaJSBridgeReady",e);var n=window.qa;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(f)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.ks.miniProgram},function(e){if(l)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(_)return window.JDJSBridgeReady&&window.JDJSBridgeReady.invoke?setTimeout(e,0):document.addEventListener("JDJSBridgeReady",e),window.jd.miniProgram},function(e){return document.addEventListener("DOMContentLoaded",e),a}],y=0;y<h.length&&!(E=h[y](b));y++);E||(E={});var B="undefined"!=typeof uni?uni:{};if(!B.navigateTo)for(var S in E)i(E,S)&&(B[S]=E[S]);return B.webView=E,B}));
uni_modules/lime-qrcode/package.json
对比新文件
@@ -0,0 +1,91 @@
{
    "id": "lime-qrcode",
    "displayName": "qrcode 二维码生成",
    "version": "0.1.8",
    "description": "一款全平台通用的二维码生成插件,支持uniapp/uniappx(web,ios,安卓)",
    "keywords": [
        "qrcode",
        "qr",
        "uvue",
        "生成图片",
        "二维码"
    ],
    "repository": "",
    "engines": {
    },
    "dcloudext": {
        "type": "component-vue",
        "sale": {
            "regular": {
                "price": "0.00"
            },
            "sourcecode": {
                "price": "0.00"
            }
        },
        "contact": {
            "qq": "305716444"
        },
        "declaration": {
            "ads": "无",
            "data": "无",
            "permissions": "无"
        },
        "npmurl": ""
    },
    "uni_modules": {
        "dependencies": [
            "lime-shared"
        ],
        "encrypt": [],
        "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y",
                "alipay": "n"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y",
                    "app-uvue": "y",
                    "app-android": {
                        "minVersion": "19"
                    }
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "u",
                    "Edge": "u",
                    "Firefox": "u",
                    "Safari": "u"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "u",
                    "百度": "u",
                    "字节跳动": "u",
                    "QQ": "u",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
    }
}
uni_modules/lime-qrcode/readme.md
对比新文件
@@ -0,0 +1,152 @@
# lime-qrcode 二维码
- 一款全平台通用的二维码生成插件,支持uniapp/uniappx(web,ios,安卓)
- uvue 需要导入[lime-qrcodegen](https://ext.dcloud.net.cn/plugin?id=15838)
## 使用
- 导入插件后直接使用
- uvue 需要导入**[lime-qrcodegen](https://ext.dcloud.net.cn/plugin?id=15838)**
#### 基础使用
```html
<l-qrcode value="http://lime.qcoon.cn" />
```
#### ICON
- 带 Icon 的二维码
```html
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" icon="/static/logo.png" iconSize="70rpx"></l-qrcode>
```
#### 颜色
- 通过设置 `color` 自定义二维码颜色,通过设置 `bgColor` 自定义背景颜色。
```html
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(82,196,26)"></l-qrcode>
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(22,119,255)" bgColor="rgb(245,245,245)"></l-qrcode>
```
#### 纠错比例
- 通过设置 `errorLevel` 调整不同的容错等级。
```html
<l-qrcode value="img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" size="300rpx" errorLevel="H"></l-qrcode>
```
#### 生成图片
- 1、通过调用插件的`canvasToTempFilePath`方法生成图片。
```html
<image v-if="image" :src="image" style="width: 300rpx;" mode="widthFix"></image>
<l-qrcode ref="qrcodeRef" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
<button @click="onClick">生成图片</button>
```
```js
// vue3
const qrcodeRef = ref(null)
const onClick = () => {
    if(!qrcodeRef.value) return
    qrcodeRef.value.canvasToTempFilePath({
        success(res) {
            image.value = res.tempFilePath
            console.log('success:::', res)
        },
        fail(err) {
            console.log('err:::', err)
        }
    })
}
// vue2
const el = this.$refs['qrcodeRef']
el.canvasToTempFilePath({
    success:(res)=>{
        this.image = res.tempFilePath
    },
    fail(err) {
        console.log('err:::', err)
    }
})
// uvue
const el:LQrcodeComponentPublicInstance = this.$refs['qrcodeRef'] as LQrcodeComponentPublicInstance
el.canvasToTempFilePath({
    success:(res: TakeSnapshotSuccess)=>{
        this.image = res.tempFilePath
    },
    fail(err: TakeSnapshotFail) {
        console.log('err:::', err)
    }
})
```
- 2、通过设置`useCanvasToTempFilePath`在`success`事件里接收图片地址
```html
<image v-if="image" :src="image" style="width: 300rpx;" mode="widthFix"></image>
<l-qrcode useCanvasToTempFilePath @success="success" value="https://limeui.qcoon.cn"></l-qrcode>
```
```js
const image = ref(null)
const success = (img) => {
    image.value = img
}
```
### 关于vue2的使用方式
- 插件使用了`composition-api`, 如果你希望在vue2中使用请按官方的教程[vue-composition-api](https://uniapp.dcloud.net.cn/tutorial/vue-composition-api.html)配置
- 关键代码是: 在main.js中 在vue2部分加上这一段即可
```js
// main.js vue2
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
```
另外插件也用到了TS,vue2可能会遇过官方的TS版本过低的问题,找到HX目录下的`compile-typescript`目录
```cmd
// \HBuilderX\plugins\compile-typescript
yarn add typescript -D
- or -
npm install typescript -D
```
### 查看示例
- 导入后直接使用这个标签查看演示效果
```html
// 代码位于 uni_modules/lime-qrcode/compoents/lime-qrcode
<lime-qrcode />
```
### 插件标签
- 默认 l-qrcode 为 component
- 默认 lime-qrcode 为 demo
## API
### Props
| 参数                       | 说明                                                         | 类型             | 默认值       |
| --------------------------| ------------------------------------------------------------ | ---------------- | ------------ |
| value                     | 扫描后的文本                                                   | <em>string</em>  | `-`        |
| icon                      | 二维码中图片的地址                                              | <em>string</em>  | `-`        |
| size                      | 二维码大小                                                      | <em>number,string</em>  | `160`     |
| iconSize                   | 二维码中图片的大小                                                | <em>number,string</em>  | `40`      |
| color                       | 二维码颜色                                                        | <em>string</em>  | `-`      |
| bgColor                   | 二维码背景颜色                                                    | <em>string</em>  | `-`  |
| errorLevel                 | 二维码纠错等级                                                    | `'L' | 'M' | 'Q' | 'H' ` | `M`  |
| marginSize                 | 边距码大小,默认为0码点                                                    | <em>number</em>  | `0`     |
### 常见问题
- icon 是网络地址时,H5和Nvue需要解决跨域问题,小程序需要配置download
## 打赏
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/alipay.png)
![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/wpay.png)
uni_modules/lime-shared/addUnit/index.ts
对比新文件
@@ -0,0 +1,42 @@
// @ts-nocheck
import {isNumeric} from '../isNumeric'
import {isDef} from '../isDef'
/**
 * 给一个值添加单位(像素 px)
 * @param value 要添加单位的值,可以是字符串或数字
 * @returns 添加了单位的值,如果值为 null 则返回 null
 */
// #ifndef UNI-APP-X && APP
export function addUnit(value?: string | number): string | null {
  if (!isDef(value)) {
    return null;
  }
  value = String(value); // 将值转换为字符串
  // 如果值是数字,则在后面添加单位 "px",否则保持原始值
  return isNumeric(value) ? `${value}px` : value;
}
// #endif
// #ifdef UNI-APP-X && APP
function addUnit(value: string): string
function addUnit(value: number): string
function addUnit(value: any|null): string|null  {
  if (!isDef(value)) {
    return null;
  }
  value = `${value}` //value.toString(); // 将值转换为字符串
  // 如果值是数字,则在后面添加单位 "px",否则保持原始值
  return isNumeric(value) ? `${value}px` : value;
}
export {addUnit}
// #endif
// console.log(addUnit(100)); // 输出: "100px"
// console.log(addUnit("200")); // 输出: "200px"
// console.log(addUnit("300px")); // 输出: "300px"(已经包含单位)
// console.log(addUnit()); // 输出: undefined(值为 undefined)
// console.log(addUnit(null)); // 输出: undefined(值为 null)
uni_modules/lime-shared/animation/bezier.ts
对比新文件
@@ -0,0 +1,82 @@
export function cubicBezier(p1x : number, p1y : number, p2x : number, p2y : number):(x: number)=> number {
    const ZERO_LIMIT = 1e-6;
    // Calculate the polynomial coefficients,
    // implicit first and last control points are (0,0) and (1,1).
    const ax = 3 * p1x - 3 * p2x + 1;
    const bx = 3 * p2x - 6 * p1x;
    const cx = 3 * p1x;
    const ay = 3 * p1y - 3 * p2y + 1;
    const by = 3 * p2y - 6 * p1y;
    const cy = 3 * p1y;
    function sampleCurveDerivativeX(t : number) : number {
        // `ax t^3 + bx t^2 + cx t` expanded using Horner's rule
        return (3 * ax * t + 2 * bx) * t + cx;
    }
    function sampleCurveX(t : number) : number {
        return ((ax * t + bx) * t + cx) * t;
    }
    function sampleCurveY(t : number) : number {
        return ((ay * t + by) * t + cy) * t;
    }
    // Given an x value, find a parametric value it came from.
    function solveCurveX(x : number) : number {
        let t2 = x;
        let derivative : number;
        let x2 : number;
        // https://trac.webkit.org/browser/trunk/Source/WebCore/platform/animation
        // first try a few iterations of Newton's method -- normally very fast.
        // http://en.wikipedia.org/wikiNewton's_method
        for (let i = 0; i < 8; i++) {
            // f(t) - x = 0
            x2 = sampleCurveX(t2) - x;
            if (Math.abs(x2) < ZERO_LIMIT) {
                return t2;
            }
            derivative = sampleCurveDerivativeX(t2);
            // == 0, failure
            /* istanbul ignore if */
            if (Math.abs(derivative) < ZERO_LIMIT) {
                break;
            }
            t2 -= x2 / derivative;
        }
        // Fall back to the bisection method for reliability.
        // bisection
        // http://en.wikipedia.org/wiki/Bisection_method
        let t1 = 1;
        /* istanbul ignore next */
        let t0 = 0;
        /* istanbul ignore next */
        t2 = x;
        /* istanbul ignore next */
        while (t1 > t0) {
            x2 = sampleCurveX(t2) - x;
            if (Math.abs(x2) < ZERO_LIMIT) {
                return t2;
            }
            if (x2 > 0) {
                t1 = t2;
            } else {
                t0 = t2;
            }
            t2 = (t1 + t0) / 2;
        }
        // Failure
        return t2;
    }
    return function (x : number) : number {
        return sampleCurveY(solveCurveX(x));
    }
    // return solve;
}
uni_modules/lime-shared/animation/ease.ts
对比新文件
@@ -0,0 +1,3 @@
import {cubicBezier} from './bezier';
export let ease = cubicBezier(0.25, 0.1, 0.25, 1);
export let linear = cubicBezier(0,0,1,1);
uni_modules/lime-shared/animation/index.ts
对比新文件
@@ -0,0 +1,10 @@
// @ts-nocheck
// #ifdef UNI-APP-X && APP
export * from './uvue.uts'
// #endif
// #ifndef UNI-APP-X && APP
export * from './vue.ts'
// #endif
uni_modules/lime-shared/animation/useTransition.ts
对比新文件
@@ -0,0 +1,98 @@
// @ts-nocheck
import { ComponentPublicInstance } from 'vue'
import { ease, linear } from './ease';
import { Timeline, Animation } from './';
export type UseTransitionOptions = {
    duration ?: number
    immediate ?: boolean
    context ?: ComponentPublicInstance
}
// #ifndef UNI-APP-X && APP
import { ref, watch, Ref } from '@/uni_modules/lime-shared/vue'
export function useTransition(percent : Ref<number>|(() => number), options : UseTransitionOptions) : Ref<number> {
    const current = ref(0)
    const { immediate, duration = 300 } = options
    let tl:Timeline|null = null;
    let timer = -1
    const isFunction = typeof percent === 'function'
    watch(isFunction ? percent : () => percent.value, (v) => {
        if(tl == null){
            tl = new Timeline()
        }
        tl.start();
        tl.add(
            new Animation(
                current.value,
                v,
                duration,
                0,
                ease,
                nowValue => {
                    current.value = nowValue
                    clearTimeout(timer)
                    if(current.value == v){
                        timer = setTimeout(()=>{
                            tl?.pause();
                            tl = null
                        }, duration)
                    }
                }
            )
        );
    }, { immediate })
    return current
}
// #endif
// #ifdef UNI-APP-X && APP
type UseTransitionReturnType = Ref<number>
// export function useTransition<T>(source : any, options : UseTransitionOptions) : UseTransitionReturnType
export function useTransition(source : any, options : UseTransitionOptions) : UseTransitionReturnType {
    const outputRef : Ref<number> = ref(0)
    const immediate = options.immediate ?? false
    const duration = options.duration ?? 300
    const context = options.context //as ComponentPublicInstance | null
    let tl:Timeline|null = null;
    let timer = -1
    const watchFunc = (v : number) => {
        if(tl == null){
            tl = new Timeline()
        }
        tl!.start();
        tl!.add(
            new Animation(
                outputRef.value,
                v,
                duration,
                0,
                ease,
                nowValue => {
                    outputRef.value = nowValue //nowValue < 0.0001 ? 0 : Math.abs(v - nowValue) < 0.00001 ? v : nowValue;
                    clearTimeout(timer)
                    if(outputRef.value == v){
                        timer = setTimeout(()=>{
                            tl?.pause();
                            tl = null
                        }, duration)
                    }
                }
            ), null
        );
    }
    if (context != null && typeof source == 'string') {
        context.$watch(source, watchFunc, { immediate } as WatchOptions)
    } else {
        watch(source, watchFunc, { immediate } as WatchOptions)
    }
    const stop = ()=>{
    }
    return outputRef //as UseTransitionReturnType
}
// #endif
uni_modules/lime-shared/animation/uvue.uts
对比新文件
@@ -0,0 +1,117 @@
// @ts-nocheck
import {raf, cancelRaf} from '../raf'
export class Timeline {
    state : string
    animations : Set<Animation> = new Set<Animation>()
    delAnimations : Animation[] = []
    startTimes : Map<Animation, number> = new Map<Animation, number>()
    pauseTime : number = 0
    pauseStart : number = Date.now()
    tickHandler : number = 0
    tickHandlers : number[] = []
    tick : (() => void) | null = null
    constructor() {
        this.state = 'Initiated';
    }
    start() {
        if (!(this.state === 'Initiated')) return;
        this.state = 'Started';
        let startTime = Date.now();
        this.pauseTime = 0;
        this.tick = () => {
            let now = Date.now();
            this.animations.forEach((animation : Animation) => {
                let t:number;
                const ani = this.startTimes.get(animation)
                if (ani == null) return
                if (ani < startTime) {
                    t = now - startTime - animation.delay - this.pauseTime;
                } else {
                    t = now - ani - animation.delay - this.pauseTime;
                }
                if (t > animation.duration) {
                    this.delAnimations.push(animation)
                    // 不能在 foreach 里面 对 集合进行删除操作
                    // this.animations.delete(animation);
                    t = animation.duration;
                }
                if (t > 0) animation.run(t);
            })
            // 不能在 foreach 里面 对 集合进行删除操作
            while (this.delAnimations.length > 0) {
                const animation = this.delAnimations.pop();
                if (animation == null) return
                this.animations.delete(animation);
            }
            clearTimeout(this.tickHandler);
            if (this.state != 'Started') return
            // this.tickHandler = setTimeout(() => {
            //     this.tick!()
            // }, 1000 / 60)
            this.tickHandler = raf(()=> {
                this.tick!()
            })
            // this.tickHandlers.push(this.tickHandler)
        }
        this.tick!()
    }
    pause() {
        if (!(this.state === 'Started')) return;
        this.state = 'Paused';
        this.pauseStart = Date.now();
        // clearTimeout(this.tickHandler);
        cancelRaf(this.tickHandler);
    }
    resume() {
        if (!(this.state === 'Paused')) return;
        this.state = 'Started';
        this.pauseTime += Date.now() - this.pauseStart;
        this.tick!();
    }
    reset() {
        this.pause();
        this.state = 'Initiated';
        this.pauseTime = 0;
        this.pauseStart = 0;
        this.animations.clear()
        this.delAnimations.clear()
        this.startTimes.clear()
        this.tickHandler = 0;
    }
    add(animation : Animation, startTime ?: number | null) {
        if (startTime == null) startTime = Date.now();
        this.animations.add(animation);
        this.startTimes.set(animation, startTime);
    }
}
export class Animation {
    startValue : number
    endValue : number
    duration : number
    timingFunction : (t : number) => number
    delay : number
    template : (t : number) => void
    constructor(
        startValue : number,
        endValue : number,
        duration : number,
        delay : number,
        timingFunction : (t : number) => number,
        template : (v : number) => void) {
        this.startValue = startValue;
        this.endValue = endValue;
        this.duration = duration;
        this.timingFunction = timingFunction;
        this.delay = delay;
        this.template = template;
    }
    run(time : number) {
        let range = this.endValue - this.startValue;
        let progress = time / this.duration
        if(progress != 1) progress = this.timingFunction(progress)
        this.template(this.startValue + range * progress)
    }
}
uni_modules/lime-shared/animation/vue.ts
对比新文件
@@ -0,0 +1,123 @@
// @ts-nocheck
const TICK = Symbol('tick');
const TICK_HANDLER = Symbol('tick-handler');
const ANIMATIONS = Symbol('animations');
const START_TIMES = Symbol('start-times');
const PAUSE_START = Symbol('pause-start');
const PAUSE_TIME = Symbol('pause-time');
const _raf = typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame : function(cb: Function) {return setTimeout(cb, 1000/60)}
const _caf = typeof cancelAnimationFrame !== 'undefined' ? cancelAnimationFrame: function(id: any) {clearTimeout(id)}
// const TICK = 'tick';
// const TICK_HANDLER = 'tick-handler';
// const ANIMATIONS = 'animations';
// const START_TIMES = 'start-times';
// const PAUSE_START = 'pause-start';
// const PAUSE_TIME = 'pause-time';
// const _raf = function(callback):number|null {return setTimeout(callback, 1000/60)}
// const _caf = function(id: number):void {clearTimeout(id)}
export class Timeline {
    state: string
    constructor() {
        this.state = 'Initiated';
        this[ANIMATIONS] = new Set();
        this[START_TIMES] = new Map();
    }
    start() {
        if (!(this.state === 'Initiated')) return;
        this.state = 'Started';
        let startTime = Date.now();
        this[PAUSE_TIME] = 0;
        this[TICK] = () => {
            let now = Date.now();
            this[ANIMATIONS].forEach((animation) => {
                 let t: number;
                 if (this[START_TIMES].get(animation) < startTime) {
                     t = now - startTime - animation.delay - this[PAUSE_TIME];
                 } else {
                     t = now - this[START_TIMES].get(animation) - animation.delay - this[PAUSE_TIME];
                 }
                 if (t > animation.duration) {
                     this[ANIMATIONS].delete(animation);
                     t = animation.duration;
                 }
                 if (t > 0) animation.run(t);
            })
            // for (let animation of this[ANIMATIONS]) {
            //     let t: number;
            //     console.log('animation', animation)
            //     if (this[START_TIMES].get(animation) < startTime) {
            //         t = now - startTime - animation.delay - this[PAUSE_TIME];
            //     } else {
            //         t = now - this[START_TIMES].get(animation) - animation.delay - this[PAUSE_TIME];
            //     }
            //     if (t > animation.duration) {
            //         this[ANIMATIONS].delete(animation);
            //         t = animation.duration;
            //     }
            //     if (t > 0) animation.run(t);
            // }
            this[TICK_HANDLER] = _raf(this[TICK]);
        };
        this[TICK]();
    }
    pause() {
        if (!(this.state === 'Started')) return;
        this.state = 'Paused';
        this[PAUSE_START] = Date.now();
        _caf(this[TICK_HANDLER]);
    }
    resume() {
        if (!(this.state === 'Paused')) return;
        this.state = 'Started';
        this[PAUSE_TIME] += Date.now() - this[PAUSE_START];
        this[TICK]();
    }
    reset() {
        this.pause();
        this.state = 'Initiated';
        this[PAUSE_TIME] = 0;
        this[PAUSE_START] = 0;
        this[ANIMATIONS] = new Set();
        this[START_TIMES] = new Map();
        this[TICK_HANDLER] = null;
    }
    add(animation: any, startTime?: number) {
        if (arguments.length < 2) startTime = Date.now();
        this[ANIMATIONS].add(animation);
        this[START_TIMES].set(animation, startTime);
    }
}
export class Animation {
    startValue: number
    endValue: number
    duration: number
    timingFunction: (t: number) => number
    delay: number
    template: (t: number) => void
    constructor(startValue: number, endValue: number, duration: number, delay: number, timingFunction: (t: number) => number, template: (v: number) => void) {
        timingFunction = timingFunction || (v => v);
        template = template || (v => v);
        this.startValue = startValue;
        this.endValue = endValue;
        this.duration = duration;
        this.timingFunction = timingFunction;
        this.delay = delay;
        this.template = template;
    }
    run(time: number) {
        let range = this.endValue - this.startValue;
        let progress = time / this.duration
        if(progress != 1) progress = this.timingFunction(progress)
        this.template(this.startValue + range * progress)
    }
}
uni_modules/lime-shared/arrayBufferToFile/index.ts
对比新文件
@@ -0,0 +1,8 @@
// @ts-nocheck
// #ifndef UNI-APP-X && APP
export * from './vue.ts'
// #endif
// #ifdef UNI-APP-X && APP
export * from './uvue.uts'
// #endif
uni_modules/lime-shared/arrayBufferToFile/uvue.uts
对比新文件
@@ -0,0 +1,10 @@
// @ts-nocheck
// import {platform} from '../platform'
/**
 * buffer转路径
 * @param {Object} buffer
 */
// @ts-nocheck
export function arrayBufferToFile(buffer: ArrayBuffer, name?: string, format?:string):Promise<(File|string)> {
    console.error('[arrayBufferToFile] 当前环境不支持')
}
uni_modules/lime-shared/arrayBufferToFile/vue.ts
对比新文件
@@ -0,0 +1,63 @@
// @ts-nocheck
import {platform} from '../platform'
/**
 * buffer转路径
 * @param {Object} buffer
 */
// @ts-nocheck
export function arrayBufferToFile(buffer: ArrayBuffer | Blob, name?: string, format?:string):Promise<(File|string)> {
    return new Promise((resolve, reject) => {
        // #ifdef MP
        const fs = uni.getFileSystemManager()
        //自定义文件名
        if (!name && !format) {
            reject(new Error('ERROR_NAME_PARSE'))
        }
        const fileName = `${name || new Date().getTime()}.${format.replace(/(.+)?\//,'')}`;
        let pre = platform()
        const filePath = `${pre.env.USER_DATA_PATH}/${fileName}`
        fs.writeFile({
            filePath,
            data: buffer,
            success() {
                resolve(filePath)
            },
            fail(err) {
                console.error(err)
                reject(err)
            }
        })
        // #endif
        // #ifdef H5
        const file = new File([buffer], name, {
             type: format,
        });
        resolve(file)
        // #endif
        // #ifdef APP-PLUS
        const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
        const base64 = uni.arrayBufferToBase64(buffer)
        bitmap.loadBase64Data(base64, () => {
            if (!name && !format) {
                reject(new Error('ERROR_NAME_PARSE'))
            }
            const fileNmae = `${name || new Date().getTime()}.${format.replace(/(.+)?\//,'')}`;
            const filePath = `_doc/uniapp_temp/${fileNmae}`
            bitmap.save(filePath, {},
                () => {
                    bitmap.clear()
                    resolve(filePath)
                },
                (error) => {
                    bitmap.clear()
                    reject(error)
                })
        }, (error) => {
            bitmap.clear()
            reject(error)
        })
        // #endif
    })
}
uni_modules/lime-shared/base64ToArrayBuffer/index.ts
对比新文件
@@ -0,0 +1,13 @@
// @ts-nocheck
// 未完成
export function base64ToArrayBuffer(base64 : string) {
    const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
    if (!format) {
        new Error('ERROR_BASE64SRC_PARSE')
    }
    if(uni.base64ToArrayBuffer) {
        return uni.base64ToArrayBuffer(bodyData)
    } else {
    }
}
uni_modules/lime-shared/base64ToPath/index.ts
对比新文件
@@ -0,0 +1,9 @@
// @ts-nocheck
// #ifndef UNI-APP-X && APP
export * from './vue.ts'
// #endif
// #ifdef UNI-APP-X && APP
export * from './uvue.uts'
// #endif
uni_modules/lime-shared/base64ToPath/uvue.uts
对比新文件
@@ -0,0 +1,22 @@
// @ts-nocheck
import { processFile, ProcessFileOptions  } from '@/uni_modules/lime-file-utils'
/**
 * base64转路径
 * @param {Object} base64
 */
export function base64ToPath(base64: string, filename: string | null = null):Promise<string> {
    return new Promise((resolve,reject) => {
        processFile({
            type: 'toDataURL',
            path: base64,
            filename,
            success(res: string){
               resolve(res)
            },
            fail(err){
                reject(err)
            }
        } as ProcessFileOptions)
    })
}
uni_modules/lime-shared/base64ToPath/vue.ts
对比新文件
@@ -0,0 +1,75 @@
// @ts-nocheck
import {platform} from '../platform'
/**
 * base64转路径
 * @param {Object} base64
 */
export function base64ToPath(base64: string, filename?: string):Promise<string> {
    const [, format] = /^data:image\/(\w+);base64,/.exec(base64) || [];
    return new Promise((resolve, reject) => {
        // #ifdef MP
        const fs = uni.getFileSystemManager()
        //自定义文件名
        if (!filename && !format) {
            reject(new Error('ERROR_BASE64SRC_PARSE'))
        }
        // const time = new Date().getTime();
        const name = filename || `${new Date().getTime()}.${format}`;
        let pre = platform()
        const filePath = `${pre.env.USER_DATA_PATH}/${name}`
        fs.writeFile({
            filePath,
            data: base64.split(',')[1],
            encoding: 'base64',
            success() {
                resolve(filePath)
            },
            fail(err) {
                console.error(err)
                reject(err)
            }
        })
        // #endif
        // #ifdef H5
        // mime类型
        let mimeString = base64.split(',')[0].split(':')[1].split(';')[0];
        //base64 解码
        let byteString = atob(base64.split(',')[1]);
        //创建缓冲数组
        let arrayBuffer = new ArrayBuffer(byteString.length);
        //创建视图
        let intArray = new Uint8Array(arrayBuffer);
        for (let i = 0; i < byteString.length; i++) {
            intArray[i] = byteString.charCodeAt(i);
        }
        resolve(URL.createObjectURL(new Blob([intArray], {
            type: mimeString
        })))
        // #endif
        // #ifdef APP-PLUS
        const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
        bitmap.loadBase64Data(base64, () => {
            if (!filename && !format) {
                reject(new Error('ERROR_BASE64SRC_PARSE'))
            }
            // const time = new Date().getTime();
            const name = filename || `${new Date().getTime()}.${format}`;
            const filePath = `_doc/uniapp_temp/${name}`
            bitmap.save(filePath, {},
                () => {
                    bitmap.clear()
                    resolve(filePath)
                },
                (error) => {
                    bitmap.clear()
                    reject(error)
                })
        }, (error) => {
            bitmap.clear()
            reject(error)
        })
        // #endif
    })
}
uni_modules/lime-shared/camelCase/index.ts
对比新文件
@@ -0,0 +1,21 @@
/**
 * 将字符串转换为 camelCase 或 PascalCase 风格的命名约定
 * @param str 要转换的字符串
 * @param isPascalCase 指示是否转换为 PascalCase 的布尔值,默认为 false
 * @returns 转换后的字符串
 */
export function camelCase(str: string, isPascalCase: boolean = false): string {
    // 将字符串分割成单词数组
    let words: string[] = str.split(/[\s_-]+/);
    // 将数组中的每个单词首字母大写(除了第一个单词)
    let camelCased: string[] = words.map((word, index):string => {
      if (index == 0 && !isPascalCase) {
        return word.toLowerCase(); // 第一个单词全小写
      }
      return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
    });
    // 将数组中的单词拼接成一个字符串
    return camelCased.join('');
};
uni_modules/lime-shared/canIUseCanvas2d/index.ts
对比新文件
@@ -0,0 +1,67 @@
// @ts-nocheck
// #ifndef UNI-APP-X && APP
// #ifdef MP-ALIPAY
interface My {
    SDKVersion: string
}
declare var my: My
// #endif
function compareVersion(v1:string, v2:string) {
  let a1 = v1.split('.');
  let a2 = v2.split('.');
  const len = Math.max(a1.length, a2.length);
  while (a1.length < len) {
    a1.push('0');
  }
  while (a2.length < len) {
    a2.push('0');
  }
  for (let i = 0; i < len; i++) {
    const num1 = parseInt(a1[i], 10);
    const num2 = parseInt(a2[i], 10);
    if (num1 > num2) {
      return 1;
    }
    if (num1 < num2) {
      return -1;
    }
  }
  return 0;
}
function gte(version: string) {
    let {SDKVersion} = uni.getSystemInfoSync();
    // #ifdef MP-ALIPAY
    SDKVersion = my.SDKVersion
    // #endif
    return compareVersion(SDKVersion, version) >= 0;
}
// #endif
/** 环境是否支持canvas 2d */
export function canIUseCanvas2d(): boolean {
    // #ifdef MP-WEIXIN
    return gte('2.9.0');
    // #endif
    // #ifdef MP-ALIPAY
    return gte('2.7.0');
    // #endif
    // #ifdef MP-TOUTIAO
    return gte('1.78.0');
    // #endif
    // #ifndef MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO
    return false
    // #endif
    // #ifdef UNI-APP-X && APP || APP-NVUE || APP-VUE
    return false;
    // #endif
}
uni_modules/lime-shared/capitalizedAmount/index.ts
对比新文件
@@ -0,0 +1,111 @@
// @ts-nocheck
import { isString } from "../isString";
import { isNumber } from "../isNumber";
/**
 * 将金额转换为中文大写形式
 * @param {number | string} amount - 需要转换的金额,可以是数字或字符串
 * @returns {string} 转换后的中文大写金额
 */
function capitalizedAmount(amount : number) : string
function capitalizedAmount(amount : string) : string
function capitalizedAmount(amount : any | null) : string {
    try {
        let _amountStr :string;
        let _amountNum :number = 0;
        // 如果输入是字符串,先将其转换为数字,并去除逗号
        if (typeof amount == 'string') {
             _amountNum = parseFloat((amount as string).replace(/,/g, ''));
        }
        if(isNumber(amount)) {
            _amountNum = amount as number
        }
        // 判断输入是否为有效的金额  || isNaN(amount)
        if (amount == null) throw new Error('不是有效的金额!');
        let result = '';
        // 处理负数情况
        if (_amountNum < 0) {
            result = '欠';
            _amountNum = Math.abs(_amountNum);
        }
        // 金额不能超过千亿以上
        if (_amountNum >= 10e11) throw new Error('计算金额过大!');
        // 保留两位小数并转换为字符串
        _amountStr = _amountNum.toFixed(2);
        // 定义数字、单位和小数单位的映射
        const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
        const units = ['', '拾', '佰', '仟'];
        const bigUnits = ['', '万', '亿'];
        const decimalUnits = ['角', '分'];
        // 分离整数部分和小数部分
        const amountArray = _amountStr.split('.');
        let integerPart = amountArray[0]; // string| number[]
        const decimalPart = amountArray[1];
        // 处理整数部分
        if (integerPart != '0') {
            let _integerPart = integerPart.split('').map((item):number => parseInt(item));
            // 将整数部分按四位一级进行分组
            const levels = _integerPart.reverse().reduce((prev:string[][], item, index):string[][] => {
                // const level = prev?.[0]?.length < 4 ? prev[0] : [];
                const level = prev.length > 0 && prev[0].length < 4 ? prev[0]: []
                const value = item == 0 ? digits[item] : digits[item] + units[index % 4];
                level.unshift(value);
                if (level.length == 1) {
                    prev.unshift(level);
                } else {
                    prev[0] = level;
                }
                return prev;
            }, [] as string[][]);
            // 将分组后的整数部分转换为中文大写形式
            result += levels.reduce((prev, item, index):string => {
                let _level = bigUnits[levels.length - index - 1];
                let _item = item.join('').replace(/(零)\1+/g, '$1');
                if (_item == '零') {
                    _level = '';
                    _item = '';
                } else if (_item.endsWith('零')) {
                    _item = _item.slice(0, _item.length - 1);
                }
                return prev + _item + _level;
            }, '');
        } else {
            result += '零';
        }
        // 添加元
        result += '元';
        // 处理小数部分
        if (decimalPart != '00') {
            if (result == '零元') result = '';
            for (let i = 0; i < decimalPart.length; i++) {
                const digit = parseInt(decimalPart.charAt(i));
                if (digit != 0) {
                    result += digits[digit] + decimalUnits[i];
                }
            }
        } else {
            result += '整';
        }
        return result;
    } catch (error : Error) {
        return error.message;
    }
};
uni_modules/lime-shared/changelog.md
对比新文件
@@ -0,0 +1,40 @@
## 0.1.8(2024-10-08)
- fix: vue2 条件编译 // #ifdef APP-IOS || APP-ANDROID 会生效
## 0.1.7(2024-09-23)
- fix: raf 类型跟随版本变更
## 0.1.6(2024-07-24)
- fix: vue2 app ts需要明确的后缀,所有补全
- chore: 减少依赖
## 0.1.5(2024-07-21)
- feat: 删除 Hooks
- feat: 兼容uniappx
## 0.1.4(2023-09-05)
- feat: 增加 Hooks `useIntersectionObserver`
- feat: 增加 `floatAdd`
- feat: 因为本人插件兼容 vue2 需要使用 `composition-api`,故增加vue文件代码插件的条件编译
## 0.1.3(2023-08-13)
- feat: 增加 `camelCase`
## 0.1.2(2023-07-17)
- feat: 增加 `getClassStr`
## 0.1.1(2023-07-06)
- feat: 增加 `isNumeric`, 区别于 `isNumber`
## 0.1.0(2023-06-30)
- fix: `clamp`忘记导出了
## 0.0.9(2023-06-27)
- feat: 增加`arrayBufferToFile`
## 0.0.8(2023-06-19)
- feat: 增加`createAnimation`、`clamp`
## 0.0.7(2023-06-08)
- chore: 更新注释
## 0.0.6(2023-06-08)
- chore: 增加`createImage`为`lime-watermark`和`lime-qrcode`提供依赖
## 0.0.5(2023-06-03)
- chore: 更新注释
## 0.0.4(2023-05-22)
- feat: 增加`range`,`exif`,`selectComponent`
## 0.0.3(2023-05-08)
- feat: 增加`fillZero`,`debounce`,`throttle`,`random`
## 0.0.2(2023-05-05)
- chore: 更新文档
## 0.0.1(2023-05-05)
- 无
uni_modules/lime-shared/clamp/index.ts
对比新文件
@@ -0,0 +1,16 @@
// @ts-nocheck
/**
 * 将一个值限制在指定的范围内
 * @param val 要限制的值
 * @param min 最小值
 * @param max 最大值
 * @returns 限制后的值
 */
export function clamp(val: number, min: number, max: number): number {
  return Math.max(min, Math.min(max, val));
}
// console.log(clamp(5 ,0, 10)); // 输出: 5(在范围内,不做更改)
// console.log(clamp(-5 ,0, 10)); // 输出: 0(小于最小值,被限制为最小值)
// console.log(clamp(15 ,0, 10)); // 输出: 10(大于最大值,被限制为最大值)
uni_modules/lime-shared/cloneDeep/index.ts
对比新文件
@@ -0,0 +1,10 @@
// @ts-nocheck
// #ifdef UNI-APP-X && APP
export * from './uvue.ts'
// #endif
// #ifndef UNI-APP-X && APP
export * from './vue.ts'
// #endif
uni_modules/lime-shared/cloneDeep/uvue.ts
对比新文件
@@ -0,0 +1,17 @@
// @ts-nocheck
/**
 * 深度克隆一个对象或数组
 * @param obj 要克隆的对象或数组
 * @returns 克隆后的对象或数组
 */
export function cloneDeep<T>(obj: any): T {
  // 如果传入的对象是基本数据类型(如字符串、数字等),则直接返回
  // if(['number', 'string'].includes(typeof obj) || Array.isArray(obj)){
     //   return obj as T
  // }
  if(typeof obj == 'object'){
    return JSON.parse(JSON.stringify(obj as T)) as T;
  }
  return obj as T
}
uni_modules/lime-shared/cloneDeep/vue.ts
对比新文件
@@ -0,0 +1,103 @@
// @ts-nocheck
/**
 * 深度克隆一个对象或数组
 * @param obj 要克隆的对象或数组
 * @returns 克隆后的对象或数组
 */
export function cloneDeep<T>(obj: any): T {
  // 如果传入的对象为空,返回空
  if (obj === null) {
    return null as unknown as T;
  }
  // 如果传入的对象是 Set 类型,则将其转换为数组,并通过新的 Set 构造函数创建一个新的 Set 对象
  if (obj instanceof Set) {
    return new Set([...obj]) as unknown as T;
  }
  // 如果传入的对象是 Map 类型,则将其转换为数组,并通过新的 Map 构造函数创建一个新的 Map 对象
  if (obj instanceof Map) {
    return new Map([...obj]) as unknown as T;
  }
  // 如果传入的对象是 WeakMap 类型,则直接用传入的 WeakMap 对象进行赋值
  if (obj instanceof WeakMap) {
    let weakMap = new WeakMap();
    weakMap = obj;
    return weakMap as unknown as T;
  }
  // 如果传入的对象是 WeakSet 类型,则直接用传入的 WeakSet 对象进行赋值
  if (obj instanceof WeakSet) {
    let weakSet = new WeakSet();
    weakSet = obj;
    return weakSet as unknown as T;
  }
  // 如果传入的对象是 RegExp 类型,则通过新的 RegExp 构造函数创建一个新的 RegExp 对象
  if (obj instanceof RegExp) {
    return new RegExp(obj) as unknown as T;
  }
  // 如果传入的对象是 undefined 类型,则返回 undefined
  if (typeof obj === 'undefined') {
    return undefined as unknown as T;
  }
  // 如果传入的对象是数组,则递归调用 cloneDeep 函数对数组中的每个元素进行克隆
  if (Array.isArray(obj)) {
    return obj.map(cloneDeep) as unknown as T;
  }
  // 如果传入的对象是 Date 类型,则通过新的 Date 构造函数创建一个新的 Date 对象
  if (obj instanceof Date) {
    return new Date(obj.getTime()) as unknown as T;
  }
  // 如果传入的对象是普通对象,则使用递归调用 cloneDeep 函数对对象的每个属性进行克隆
  if (typeof obj === 'object') {
    const newObj: any = {};
    for (const [key, value] of Object.entries(obj)) {
      newObj[key] = cloneDeep(value);
    }
    const symbolKeys = Object.getOwnPropertySymbols(obj);
    for (const key of symbolKeys) {
      newObj[key] = cloneDeep(obj[key]);
    }
    return newObj;
  }
  // 如果传入的对象是基本数据类型(如字符串、数字等),则直接返回
  return obj;
}
// 示例使用
// // 克隆一个对象
// const obj = { name: 'John', age: 30 };
// const clonedObj = cloneDeep(obj);
// console.log(clonedObj); // 输出: { name: 'John', age: 30 }
// console.log(clonedObj === obj); // 输出: false (副本与原对象是独立的)
// // 克隆一个数组
// const arr = [1, 2, 3];
// const clonedArr = cloneDeep(arr);
// console.log(clonedArr); // 输出: [1, 2, 3]
// console.log(clonedArr === arr); // 输出: false (副本与原数组是独立的)
// // 克隆一个包含嵌套对象的对象
// const person = {
//   name: 'Alice',
//   age: 25,
//   address: {
//     city: 'New York',
//     country: 'USA',
//   },
// };
// const clonedPerson = cloneDeep(person);
// console.log(clonedPerson); // 输出: { name: 'Alice', age: 25, address: { city: 'New York', country: 'USA' } }
// console.log(clonedPerson === person); // 输出: false (副本与原对象是独立的)
// console.log(clonedPerson.address === person.address); // 输出: false (嵌套对象的副本也是独立的)
uni_modules/lime-shared/closest/index.ts
对比新文件
@@ -0,0 +1,22 @@
// @ts-nocheck
/**
 * 在给定数组中找到最接近目标数字的元素。
 * @param arr 要搜索的数字数组。
 * @param target 目标数字。
 * @returns 最接近目标数字的数组元素。
 */
export function closest(arr: number[], target: number):number {
  return arr.reduce((pre: number, cur: number):number =>
    Math.abs(pre - target) < Math.abs(cur - target) ? pre : cur
  );
}
// 示例
// // 定义一个数字数组
// const numbers = [1, 3, 5, 7, 9];
// // 在数组中找到最接近目标数字 6 的元素
// const closestNumber = closest(numbers, 6);
// console.log(closestNumber); // 输出结果: 5
uni_modules/lime-shared/components/lime-shared/lime-shared.vue
对比新文件
@@ -0,0 +1,156 @@
<template>
    <view id="shared" style="height: 500px; width: 300px; background-color: aqua;">
    </view>
</template>
<script lang="ts">
    import { getRect, getAllRect } from '@/uni_modules/lime-shared/getRect'
    import { camelCase } from '@/uni_modules/lime-shared/camelCase'
    import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
    import { clamp } from '@/uni_modules/lime-shared/clamp'
    import { cloneDeep } from '@/uni_modules/lime-shared/cloneDeep'
    import { closest } from '@/uni_modules/lime-shared/closest'
    import { debounce } from '@/uni_modules/lime-shared/debounce'
    import { fillZero } from '@/uni_modules/lime-shared/fillZero'
    import { floatAdd } from '@/uni_modules/lime-shared/floatAdd'
    import { floatMul } from '@/uni_modules/lime-shared/floatMul'
    import { floatDiv } from '@/uni_modules/lime-shared/floatDiv'
    import { floatSub } from '@/uni_modules/lime-shared/floatSub'
    import { getClassStr } from '@/uni_modules/lime-shared/getClassStr'
    import { getCurrentPage } from '@/uni_modules/lime-shared/getCurrentPage'
    import { getStyleStr } from '@/uni_modules/lime-shared/getStyleStr'
    import { hasOwn } from '@/uni_modules/lime-shared/hasOwn'
    import { isBase64 } from '@/uni_modules/lime-shared/isBase64'
    import { isBrowser } from '@/uni_modules/lime-shared/isBrowser'
    import { isDef } from '@/uni_modules/lime-shared/isDef'
    import { isEmpty } from '@/uni_modules/lime-shared/isEmpty'
    import { isFunction } from '@/uni_modules/lime-shared/isFunction'
    import { isNumber } from '@/uni_modules/lime-shared/isNumber'
    import { isNumeric } from '@/uni_modules/lime-shared/isNumeric'
    import { isObject } from '@/uni_modules/lime-shared/isObject'
    import { isPromise } from '@/uni_modules/lime-shared/isPromise'
    import { isString } from '@/uni_modules/lime-shared/isString'
    import { kebabCase } from '@/uni_modules/lime-shared/kebabCase'
    import { raf, doubleRaf } from '@/uni_modules/lime-shared/raf'
    import { random } from '@/uni_modules/lime-shared/random'
    import { range } from '@/uni_modules/lime-shared/range'
    import { sleep } from '@/uni_modules/lime-shared/sleep'
    import { throttle } from '@/uni_modules/lime-shared/throttle'
    import { toArray } from '@/uni_modules/lime-shared/toArray'
    import { toBoolean } from '@/uni_modules/lime-shared/toBoolean'
    import { toNumber } from '@/uni_modules/lime-shared/toNumber'
    import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
    import { getCurrentInstance } from '@/uni_modules/lime-shared/vue'
    import { capitalizedAmount } from '@/uni_modules/lime-shared/capitalizedAmount'
    // #ifdef VUE2
    type UTSJSONObject = any
    // #endif
    const context = getCurrentInstance()
    // getRect('#shared', context!).then(res =>{
    //     console.log('res', res.bottom)
    // })
    // getAllRect('#shared', context).then(res =>{
    //     console.log('res', res)
    // })
    // console.log('camelCase::', camelCase("hello world"));
    // console.log('camelCase::', camelCase("my_name_is_john", true));
    // console.log('canIUseCanvas2d::', canIUseCanvas2d());
    // console.log('clamp::', clamp(5 ,0, 10));
    // console.log('cloneDeep::', cloneDeep<UTSJSONObject>({a:5}));
    // console.log('closest::', closest([1, 3, 5, 7, 9], 6));
    // const saveData = (data: any) => {
    //     // 模拟保存数据的操作
    //     console.log(`Saving data: ${data}`);
    // }
    // const debouncedSaveData = debounce(saveData, 500);
    // debouncedSaveData('Data 1');
    // debouncedSaveData('Data 2');
    // console.log('fillZero', fillZero(1))
    // console.log('floatAdd', floatAdd(0.1, 0.2), floatAdd(1.05, 0.05), floatAdd(0.1, 0.7), floatAdd(0.0001, 0.0002), floatAdd(123.456 , 789.012))
    // console.log('floatMul', floatMul(0.1, 0.02), floatMul(1.0255, 100))
    // console.log('floatDiv', floatDiv(10.44, 100), floatDiv(1.0255, 100), floatDiv(5.419909340994699, 0.2))
    // console.log('floatSub', floatSub(0.4, 0.1), floatSub(1.0255, 100))
    const now = () : number => System.nanoTime() / 1_000_000.0
    console.log('capitalizedAmount', capitalizedAmount(0.4))
    console.log('capitalizedAmount', capitalizedAmount(100))
    console.log('capitalizedAmount', capitalizedAmount(100000000))
    console.log('capitalizedAmount', capitalizedAmount('2023.04'))
    console.log('capitalizedAmount', capitalizedAmount(-1024))
    console.log('now', now(), Date.now())
    // console.log('getClassStr', getClassStr({hover: true}))
    // console.log('getStyleStr', getStyleStr({ color: 'red', fontSize: '16px', backgroundColor: '', border: null }))
    // console.log('hasOwn', hasOwn({a: true}, 'key'))
    // console.log('isBase64::', isBase64("SGVsbG8sIFdvcmxkIQ=="));
    // console.log('isBrowser::', isBrowser);
    // console.log('isDef::', isDef('6'));
    // console.log('isEmpty::', isEmpty({a: true}));
    // const b = () =>{}
    // console.log('isFunction::', isFunction(b));
    // console.log('isNumber::', isNumber('6'));
    // console.log('isNumeric::', isNumeric('6'));
    // console.log('isObject::', isObject({}));
    // const promise = ():Promise<boolean> => {
    //     return new Promise((resolve) => {
    //         resolve(true)
    //     })
    // }
    // const a = promise()
    // console.log('isPromise::', isPromise(a));
    // console.log('isString::', isString('null'));
    // console.log('kebabCase::', kebabCase('my love'));
    // console.log('raf::', raf(()=>{
    //     console.log('raf:::1')
    // }));
    // console.log('doubleRaf::', doubleRaf(()=>{
    //     console.log('doubleRaf:::1')
    // }));
    // console.log('random', random(0, 10))
    // console.log('random', random(0, 1, 2))
    // console.log('range', range(0, 10, 2))
    // console.log('sleep', sleep(300).then(res => {
    //     console.log('log')
    // }))
    // const handleScroll = (a: string) => {
    //   console.log("Scroll event handled!", a);
    // }
    // // // 使用节流函数对 handleScroll 进行节流,间隔时间为 500 毫秒
    // const throttledScroll = throttle(handleScroll, 500);
    // throttledScroll('5');
    // const page = getCurrentPage()
    // console.log('getCurrentPage::', page)
    // console.log('toArray', toArray<number>(5))
    // console.log('toBoolean', toBoolean(5))
    // console.log('toNumber', toNumber('5'))
    // console.log('unitConvert', unitConvert('5'))
    // uni.getImageInfo({
    //     src: '/static/logo.png',
    //     success(res) {
    //         console.log('res', res)
    //     }
    // })
    export default {
    }
</script>
<style>
</style>
uni_modules/lime-shared/createAnimation/index.ts
对比新文件
@@ -0,0 +1,9 @@
// @ts-nocheck
// #ifndef UNI-APP-X
export * from './type.ts'
export * from './vue.ts'
// #endif
// #ifdef UNI-APP-X
export * from './uvue.ts'
// #endif
uni_modules/lime-shared/createAnimation/type.ts
对比新文件
@@ -0,0 +1,25 @@
export type CreateAnimationOptions = {
    /**
     * 动画持续时间,单位ms
     */
    duration ?: number;
    /**
     * 定义动画的效果
     * - linear: 动画从头到尾的速度是相同的
     * - ease: 动画以低速开始,然后加快,在结束前变慢
     * - ease-in: 动画以低速开始
     * - ease-in-out: 动画以低速开始和结束
     * - ease-out: 动画以低速结束
     * - step-start: 动画第一帧就跳至结束状态直到结束
     * - step-end: 动画一直保持开始状态,最后一帧跳到结束状态
     */
    timingFunction ?: string //'linear' | 'ease' | 'ease-in' | 'ease-in-out' | 'ease-out' | 'step-start' | 'step-end';
    /**
     * 动画延迟时间,单位 ms
     */
    delay ?: number;
    /**
     * 设置transform-origin
     */
    transformOrigin ?: string;
}
uni_modules/lime-shared/createAnimation/uvue.ts
对比新文件
@@ -0,0 +1,5 @@
// @ts-nocheck
// export * from '@/uni_modules/lime-animateIt'
export function createAnimation() {
    console.error('当前环境不支持,请使用:lime-animateIt')
}
uni_modules/lime-shared/createAnimation/vue.ts
对比新文件
@@ -0,0 +1,148 @@
// @ts-nocheck
// nvue 需要在节点上设置ref或在export里传入
// const animation = createAnimation({
//   ref: this.$refs['xxx'],
//      duration: 0,
//      timingFunction: 'linear'
// })
// animation.opacity(1).translate(x, y).step({duration})
// animation.export(ref)
// 抹平nvue 与 uni.createAnimation的使用差距
// 但是nvue动画太慢
import { CreateAnimationOptions } from './type'
// #ifdef APP-NVUE
const nvueAnimation = uni.requireNativePlugin('animation')
type AnimationTypes = 'matrix' | 'matrix3d' | 'rotate' | 'rotate3d' | 'rotateX' | 'rotateY' | 'rotateZ' | 'scale' | 'scale3d' | 'scaleX' | 'scaleY' | 'scaleZ' | 'skew' | 'skewX' | 'skewY' | 'translate' | 'translate3d' | 'translateX' | 'translateY' | 'translateZ'
    | 'opacity' | 'backgroundColor' | 'width' | 'height' | 'left' | 'right' | 'top' | 'bottom'
interface Styles {
    [key : string] : any
}
interface StepConfig {
    duration?: number
    timingFunction?: string
    delay?: number
    needLayout?: boolean
    transformOrigin?: string
}
interface StepAnimate {
    styles?: Styles
    config?: StepConfig
}
interface StepAnimates {
    [key: number]: StepAnimate
}
// export interface CreateAnimationOptions extends UniApp.CreateAnimationOptions {
//     ref?: string
// }
type Callback = (time: number) => void
const animateTypes1 : AnimationTypes[] = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d',
    'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY',
    'translateZ'
]
const animateTypes2 : AnimationTypes[] = ['opacity', 'backgroundColor']
const animateTypes3 : AnimationTypes[] = ['width', 'height', 'left', 'right', 'top', 'bottom']
class LimeAnimation {
    ref : any
    context : any
    options : UniApp.CreateAnimationOptions
    // stack : any[] = []
    next : number = 0
    currentStepAnimates : StepAnimates = {}
    duration : number = 0
    constructor(options : CreateAnimationOptions) {
        const {ref} = options
        this.ref = ref
        this.options = options
    }
    addAnimate(type : AnimationTypes, args: (string | number)[]) {
        let aniObj = this.currentStepAnimates[this.next]
        let stepAnimate:StepAnimate = {}
        if (!aniObj) {
            stepAnimate = {styles: {}, config: {}}
        } else {
            stepAnimate = aniObj
        }
        if (animateTypes1.includes(type)) {
            if (!stepAnimate.styles.transform) {
                stepAnimate.styles.transform = ''
            }
            let unit = ''
            if (type === 'rotate') {
                unit = 'deg'
            }
            stepAnimate.styles.transform += `${type}(${args.map((v: number) => v + unit).join(',')}) `
        } else {
            stepAnimate.styles[type] = `${args.join(',')}`
        }
        this.currentStepAnimates[this.next] = stepAnimate
    }
    animateRun(styles: Styles = {}, config:StepConfig = {}, ref: any) {
        const el = ref || this.ref
        if (!el) return
        return new Promise((resolve) => {
            const time = +new Date()
            nvueAnimation.transition(el, {
                styles,
                ...config
            }, () => {
                resolve(+new Date() - time)
            })
        })
    }
    nextAnimate(animates: StepAnimates, step: number = 0, ref: any, cb: Callback) {
        let obj = animates[step]
        if (obj) {
            let { styles, config } = obj
            // this.duration += config.duration
            this.animateRun(styles, config, ref).then((time: number) => {
                step += 1
                this.duration += time
                this.nextAnimate(animates, step, ref, cb)
            })
        } else {
            this.currentStepAnimates = {}
            cb && cb(this.duration)
        }
    }
    step(config:StepConfig = {}) {
        this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config)
        this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin
        this.next++
        return this
    }
    export(ref: any, cb?: Callback) {
        ref = ref || this.ref
        if(!ref) return
        this.duration = 0
        this.next = 0
        this.nextAnimate(this.currentStepAnimates, 0, ref, cb)
        return null
    }
}
animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => {
    LimeAnimation.prototype[type] = function(...args: (string | number)[]) {
        this.addAnimate(type, args)
        return this
    }
})
// #endif
export function createAnimation(options : CreateAnimationOptions) {
    // #ifndef APP-NVUE
    return uni.createAnimation({ ...options })
    // #endif
    // #ifdef APP-NVUE
    return new LimeAnimation(options)
    // #endif
}
uni_modules/lime-shared/createCanvas/index.ts
对比新文件
@@ -0,0 +1,73 @@
// @ts-nocheck
// #ifndef UNI-APP-X && APP
import type { ComponentInternalInstance } from '@/uni_modules/lime-shared/vue'
import { getRect } from '@/uni_modules/lime-shared/getRect'
import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
export const isCanvas2d = canIUseCanvas2d()
// #endif
export function createCanvas(canvasId : string, component : ComponentInternalInstance) {
    // #ifdef UNI-APP-X
    uni.createCanvasContextAsync({
        canvasId,
        component,
        success(context : CanvasContext) {
        },
        fail(error : UniError) {
        }
    })
    // #endif
    // #ifndef UNI-APP-X
    const isCanvas2d = canIUseCanvas2d()
    getRect('#' + canvasId, context, isCanvas2d).then(res => {
        if (res.node) {
            res.node.width = res.width
            res.node.height = res.height
            return res.node
        } else {
            const ctx = uni.createCanvasContext(canvasId, context)
            if (!ctx._drawImage) {
                ctx._drawImage = ctx.drawImage
                ctx.drawImage = function (...args) {
                    const { path } = args.shift()
                    ctx._drawImage(path, ...args)
                }
            }
            if (!ctx.getImageData) {
                ctx.getImageData = function () {
                    return new Promise((resolve, reject) => {
                        uni.canvasGetImageData({
                            canvasId,
                            x: parseInt(arguments[0]),
                            y: parseInt(arguments[1]),
                            width: parseInt(arguments[2]),
                            height: parseInt(arguments[3]),
                            success(res) {
                                resolve(res)
                            },
                            fail(err) {
                                reject(err)
                            }
                        }, context)
                    })
                }
                return {
                    getContext(type: string) {
                        if(type == '2d') {
                            return ctx
                        }
                    },
                    width: res.width,
                    height: res.height,
                    createImage
                }
            }
        }
    })
    // #endif
}
uni_modules/lime-shared/createImage/index.ts
对比新文件
@@ -0,0 +1,71 @@
// @ts-nocheck
// #ifndef UNI-APP-X && APP
import {isBrowser} from '../isBrowser'
class Image {
    currentSrc: string | null = null
    naturalHeight: number = 0
    naturalWidth: number = 0
    width: number = 0
    height: number = 0
    tagName: string = 'IMG'
    path: string = ''
    crossOrigin: string = ''
    referrerPolicy: string = ''
    onload: () => void = () => {}
    onerror: () => void = () => {}
    complete: boolean = false
    constructor() {}
    set src(src: string) {
        console.log('src', src)
        if(!src) {
            return this.onerror()
        }
        src = src.replace(/^@\//,'/')
        this.currentSrc = src
        uni.getImageInfo({
            src,
            success: (res) => {
                const localReg = /^\.|^\/(?=[^\/])/;
                // #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO
                res.path = localReg.test(src) ?  `/${res.path}` : res.path;
                // #endif
                this.complete = true
                this.path = res.path
                this.naturalWidth = this.width = res.width
                this.naturalHeight = this.height = res.height
                this.onload()
            },
            fail: () => {
                this.onerror()
            }
        })
    }
    get src() {
        return this.currentSrc
    }
}
interface UniImage extends WechatMiniprogram.Image {
    complete?: boolean
    naturalHeight?: number
    naturalWidth?: number
}
/** 创建用于 canvas 的 img */
export function createImage(canvas?: any): HTMLImageElement | UniImage {
    if(canvas && canvas.createImage) {
        return (canvas as WechatMiniprogram.Canvas).createImage()
    } else if(this && this['tagName'] == 'canvas' && !('toBlob' in this) || canvas && !('toBlob' in canvas)){
        return new Image()
    } else if(isBrowser) {
        return new window.Image()
    }
    return new Image()
}
// #endif
// #ifdef UNI-APP-X && APP
export function createImage():Image{
    // console.error('当前环境不支持')
    return new Image()
}
// #endif
uni_modules/lime-shared/debounce/index.ts
对比新文件
@@ -0,0 +1,10 @@
// @ts-nocheck
// #ifdef UNI-APP-X && APP
export * from './uvue.ts'
// #endif
// #ifndef UNI-APP-X && APP
export * from './vue.ts'
// #endif
uni_modules/lime-shared/debounce/uvue.ts
对比新文件
@@ -0,0 +1,36 @@
// @ts-nocheck
/**
 * 防抖函数,通过延迟一定时间来限制函数的执行频率。
 * @param fn 要防抖的函数。
 * @param wait 触发防抖的等待时间,单位为毫秒。
 * @returns 防抖函数。
 */
export function debounce<A extends any>(fn : (args: A)=> void, wait = 300): (args: A)=> void {
    let timer = -1
    return (args: A) => {
        if (timer >-1) {clearTimeout(timer)};
        timer = setTimeout(()=>{
            fn(args)
        }, wait)
    }
};
// 示例
// 定义一个函数
// function saveData(data: string) {
//   // 模拟保存数据的操作
//   console.log(`Saving data: ${data}`);
// }
// // 创建一个防抖函数,延迟 500 毫秒后调用 saveData 函数
// const debouncedSaveData = debounce(saveData, 500);
// // 连续调用防抖函数
// debouncedSaveData('Data 1'); // 不会立即调用 saveData 函数
// debouncedSaveData('Data 2'); // 不会立即调用 saveData 函数
// 在 500 毫秒后,只会调用一次 saveData 函数,输出结果为 "Saving data: Data 2"
uni_modules/lime-shared/debounce/vue.ts
对比新文件
@@ -0,0 +1,40 @@
// @ts-nocheck
type Timeout = ReturnType<typeof setTimeout> | null;
/**
 * 防抖函数,通过延迟一定时间来限制函数的执行频率。
 * @param fn 要防抖的函数。
 * @param wait 触发防抖的等待时间,单位为毫秒。
 * @returns 防抖函数。
 */
export function debounce<A extends any, R>(
    fn : (...args : A) => R,
    wait : number = 300) : (...args : A) => void {
    let timer : Timeout = null;
    return function (...args : A) {
        if (timer) clearTimeout(timer); // 如果上一个 setTimeout 存在,则清除它
        // 设置一个新的 setTimeout,在指定的等待时间后调用防抖函数
        timer = setTimeout(() => {
            fn.apply(this, args); // 使用提供的参数调用原始函数
        }, wait);
    };
};
// 示例
// 定义一个函数
// function saveData(data: string) {
//   // 模拟保存数据的操作
//   console.log(`Saving data: ${data}`);
// }
// // 创建一个防抖函数,延迟 500 毫秒后调用 saveData 函数
// const debouncedSaveData = debounce(saveData, 500);
// // 连续调用防抖函数
// debouncedSaveData('Data 1'); // 不会立即调用 saveData 函数
// debouncedSaveData('Data 2'); // 不会立即调用 saveData 函数
// 在 500 毫秒后,只会调用一次 saveData 函数,输出结果为 "Saving data: Data 2"
uni_modules/lime-shared/exif/index.ts
对比新文件
@@ -0,0 +1,9 @@
// @ts-nocheck
// #ifndef UNI-APP-X && APP
export * from './vue.ts'
// #endif
// #ifdef UNI-APP-X && APP
export * from './uvue.ts'
// #endif
uni_modules/lime-shared/exif/uvue.ts
对比新文件
@@ -0,0 +1,7 @@
class EXIF {
    constructor(){
        console.error('当前环境不支持')
    }
}
export const exif = new EXIF()
uni_modules/lime-shared/exif/vue.ts
对比新文件
@@ -0,0 +1,1057 @@
// @ts-nocheck
import { base64ToArrayBuffer } from '../base64ToArrayBuffer';
import { pathToBase64 } from '../pathToBase64';
// import { isBase64 } from '../isBase64';
import { isBase64DataUri } from '../isBase64';
import { isString } from '../isString';
interface File {
    exifdata : any
    iptcdata : any
    xmpdata : any
    src : string
}
class EXIF {
    isXmpEnabled = false
    debug = false
    Tags = {
        // version tags
        0x9000: "ExifVersion", // EXIF version
        0xA000: "FlashpixVersion", // Flashpix format version
        // colorspace tags
        0xA001: "ColorSpace", // Color space information tag
        // image configuration
        0xA002: "PixelXDimension", // Valid width of meaningful image
        0xA003: "PixelYDimension", // Valid height of meaningful image
        0x9101: "ComponentsConfiguration", // Information about channels
        0x9102: "CompressedBitsPerPixel", // Compressed bits per pixel
        // user information
        0x927C: "MakerNote", // Any desired information written by the manufacturer
        0x9286: "UserComment", // Comments by user
        // related file
        0xA004: "RelatedSoundFile", // Name of related sound file
        // date and time
        0x9003: "DateTimeOriginal", // Date and time when the original image was generated
        0x9004: "DateTimeDigitized", // Date and time when the image was stored digitally
        0x9290: "SubsecTime", // Fractions of seconds for DateTime
        0x9291: "SubsecTimeOriginal", // Fractions of seconds for DateTimeOriginal
        0x9292: "SubsecTimeDigitized", // Fractions of seconds for DateTimeDigitized
        // picture-taking conditions
        0x829A: "ExposureTime", // Exposure time (in seconds)
        0x829D: "FNumber", // F number
        0x8822: "ExposureProgram", // Exposure program
        0x8824: "SpectralSensitivity", // Spectral sensitivity
        0x8827: "ISOSpeedRatings", // ISO speed rating
        0x8828: "OECF", // Optoelectric conversion factor
        0x9201: "ShutterSpeedValue", // Shutter speed
        0x9202: "ApertureValue", // Lens aperture
        0x9203: "BrightnessValue", // Value of brightness
        0x9204: "ExposureBias", // Exposure bias
        0x9205: "MaxApertureValue", // Smallest F number of lens
        0x9206: "SubjectDistance", // Distance to subject in meters
        0x9207: "MeteringMode", // Metering mode
        0x9208: "LightSource", // Kind of light source
        0x9209: "Flash", // Flash status
        0x9214: "SubjectArea", // Location and area of main subject
        0x920A: "FocalLength", // Focal length of the lens in mm
        0xA20B: "FlashEnergy", // Strobe energy in BCPS
        0xA20C: "SpatialFrequencyResponse", //
        0xA20E: "FocalPlaneXResolution", // Number of pixels in width direction per FocalPlaneResolutionUnit
        0xA20F: "FocalPlaneYResolution", // Number of pixels in height direction per FocalPlaneResolutionUnit
        0xA210: "FocalPlaneResolutionUnit", // Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution
        0xA214: "SubjectLocation", // Location of subject in image
        0xA215: "ExposureIndex", // Exposure index selected on camera
        0xA217: "SensingMethod", // Image sensor type
        0xA300: "FileSource", // Image source (3 == DSC)
        0xA301: "SceneType", // Scene type (1 == directly photographed)
        0xA302: "CFAPattern", // Color filter array geometric pattern
        0xA401: "CustomRendered", // Special processing
        0xA402: "ExposureMode", // Exposure mode
        0xA403: "WhiteBalance", // 1 = auto white balance, 2 = manual
        0xA404: "DigitalZoomRation", // Digital zoom ratio
        0xA405: "FocalLengthIn35mmFilm", // Equivalent foacl length assuming 35mm film camera (in mm)
        0xA406: "SceneCaptureType", // Type of scene
        0xA407: "GainControl", // Degree of overall image gain adjustment
        0xA408: "Contrast", // Direction of contrast processing applied by camera
        0xA409: "Saturation", // Direction of saturation processing applied by camera
        0xA40A: "Sharpness", // Direction of sharpness processing applied by camera
        0xA40B: "DeviceSettingDescription", //
        0xA40C: "SubjectDistanceRange", // Distance to subject
        // other tags
        0xA005: "InteroperabilityIFDPointer",
        0xA420: "ImageUniqueID" // Identifier assigned uniquely to each image
    }
    TiffTags = {
        0x0100: "ImageWidth",
        0x0101: "ImageHeight",
        0x8769: "ExifIFDPointer",
        0x8825: "GPSInfoIFDPointer",
        0xA005: "InteroperabilityIFDPointer",
        0x0102: "BitsPerSample",
        0x0103: "Compression",
        0x0106: "PhotometricInterpretation",
        0x0112: "Orientation",
        0x0115: "SamplesPerPixel",
        0x011C: "PlanarConfiguration",
        0x0212: "YCbCrSubSampling",
        0x0213: "YCbCrPositioning",
        0x011A: "XResolution",
        0x011B: "YResolution",
        0x0128: "ResolutionUnit",
        0x0111: "StripOffsets",
        0x0116: "RowsPerStrip",
        0x0117: "StripByteCounts",
        0x0201: "JPEGInterchangeFormat",
        0x0202: "JPEGInterchangeFormatLength",
        0x012D: "TransferFunction",
        0x013E: "WhitePoint",
        0x013F: "PrimaryChromaticities",
        0x0211: "YCbCrCoefficients",
        0x0214: "ReferenceBlackWhite",
        0x0132: "DateTime",
        0x010E: "ImageDescription",
        0x010F: "Make",
        0x0110: "Model",
        0x0131: "Software",
        0x013B: "Artist",
        0x8298: "Copyright"
    }
    GPSTags = {
        0x0000: "GPSVersionID",
        0x0001: "GPSLatitudeRef",
        0x0002: "GPSLatitude",
        0x0003: "GPSLongitudeRef",
        0x0004: "GPSLongitude",
        0x0005: "GPSAltitudeRef",
        0x0006: "GPSAltitude",
        0x0007: "GPSTimeStamp",
        0x0008: "GPSSatellites",
        0x0009: "GPSStatus",
        0x000A: "GPSMeasureMode",
        0x000B: "GPSDOP",
        0x000C: "GPSSpeedRef",
        0x000D: "GPSSpeed",
        0x000E: "GPSTrackRef",
        0x000F: "GPSTrack",
        0x0010: "GPSImgDirectionRef",
        0x0011: "GPSImgDirection",
        0x0012: "GPSMapDatum",
        0x0013: "GPSDestLatitudeRef",
        0x0014: "GPSDestLatitude",
        0x0015: "GPSDestLongitudeRef",
        0x0016: "GPSDestLongitude",
        0x0017: "GPSDestBearingRef",
        0x0018: "GPSDestBearing",
        0x0019: "GPSDestDistanceRef",
        0x001A: "GPSDestDistance",
        0x001B: "GPSProcessingMethod",
        0x001C: "GPSAreaInformation",
        0x001D: "GPSDateStamp",
        0x001E: "GPSDifferential"
    }
    // EXIF 2.3 Spec
    IFD1Tags = {
        0x0100: "ImageWidth",
        0x0101: "ImageHeight",
        0x0102: "BitsPerSample",
        0x0103: "Compression",
        0x0106: "PhotometricInterpretation",
        0x0111: "StripOffsets",
        0x0112: "Orientation",
        0x0115: "SamplesPerPixel",
        0x0116: "RowsPerStrip",
        0x0117: "StripByteCounts",
        0x011A: "XResolution",
        0x011B: "YResolution",
        0x011C: "PlanarConfiguration",
        0x0128: "ResolutionUnit",
        0x0201: "JpegIFOffset", // When image format is JPEG, this value show offset to JPEG data stored.(aka "ThumbnailOffset" or "JPEGInterchangeFormat")
        0x0202: "JpegIFByteCount", // When image format is JPEG, this value shows data size of JPEG image (aka "ThumbnailLength" or "JPEGInterchangeFormatLength")
        0x0211: "YCbCrCoefficients",
        0x0212: "YCbCrSubSampling",
        0x0213: "YCbCrPositioning",
        0x0214: "ReferenceBlackWhite"
    }
    StringValues = {
        ExposureProgram: {
            0: "Not defined",
            1: "Manual",
            2: "Normal program",
            3: "Aperture priority",
            4: "Shutter priority",
            5: "Creative program",
            6: "Action program",
            7: "Portrait mode",
            8: "Landscape mode"
        },
        MeteringMode: {
            0: "Unknown",
            1: "Average",
            2: "CenterWeightedAverage",
            3: "Spot",
            4: "MultiSpot",
            5: "Pattern",
            6: "Partial",
            255: "Other"
        },
        LightSource: {
            0: "Unknown",
            1: "Daylight",
            2: "Fluorescent",
            3: "Tungsten (incandescent light)",
            4: "Flash",
            9: "Fine weather",
            10: "Cloudy weather",
            11: "Shade",
            12: "Daylight fluorescent (D 5700 - 7100K)",
            13: "Day white fluorescent (N 4600 - 5400K)",
            14: "Cool white fluorescent (W 3900 - 4500K)",
            15: "White fluorescent (WW 3200 - 3700K)",
            17: "Standard light A",
            18: "Standard light B",
            19: "Standard light C",
            20: "D55",
            21: "D65",
            22: "D75",
            23: "D50",
            24: "ISO studio tungsten",
            255: "Other"
        },
        Flash: {
            0x0000: "Flash did not fire",
            0x0001: "Flash fired",
            0x0005: "Strobe return light not detected",
            0x0007: "Strobe return light detected",
            0x0009: "Flash fired, compulsory flash mode",
            0x000D: "Flash fired, compulsory flash mode, return light not detected",
            0x000F: "Flash fired, compulsory flash mode, return light detected",
            0x0010: "Flash did not fire, compulsory flash mode",
            0x0018: "Flash did not fire, auto mode",
            0x0019: "Flash fired, auto mode",
            0x001D: "Flash fired, auto mode, return light not detected",
            0x001F: "Flash fired, auto mode, return light detected",
            0x0020: "No flash function",
            0x0041: "Flash fired, red-eye reduction mode",
            0x0045: "Flash fired, red-eye reduction mode, return light not detected",
            0x0047: "Flash fired, red-eye reduction mode, return light detected",
            0x0049: "Flash fired, compulsory flash mode, red-eye reduction mode",
            0x004D: "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",
            0x004F: "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",
            0x0059: "Flash fired, auto mode, red-eye reduction mode",
            0x005D: "Flash fired, auto mode, return light not detected, red-eye reduction mode",
            0x005F: "Flash fired, auto mode, return light detected, red-eye reduction mode"
        },
        SensingMethod: {
            1: "Not defined",
            2: "One-chip color area sensor",
            3: "Two-chip color area sensor",
            4: "Three-chip color area sensor",
            5: "Color sequential area sensor",
            7: "Trilinear sensor",
            8: "Color sequential linear sensor"
        },
        SceneCaptureType: {
            0: "Standard",
            1: "Landscape",
            2: "Portrait",
            3: "Night scene"
        },
        SceneType: {
            1: "Directly photographed"
        },
        CustomRendered: {
            0: "Normal process",
            1: "Custom process"
        },
        WhiteBalance: {
            0: "Auto white balance",
            1: "Manual white balance"
        },
        GainControl: {
            0: "None",
            1: "Low gain up",
            2: "High gain up",
            3: "Low gain down",
            4: "High gain down"
        },
        Contrast: {
            0: "Normal",
            1: "Soft",
            2: "Hard"
        },
        Saturation: {
            0: "Normal",
            1: "Low saturation",
            2: "High saturation"
        },
        Sharpness: {
            0: "Normal",
            1: "Soft",
            2: "Hard"
        },
        SubjectDistanceRange: {
            0: "Unknown",
            1: "Macro",
            2: "Close view",
            3: "Distant view"
        },
        FileSource: {
            3: "DSC"
        },
        Components: {
            0: "",
            1: "Y",
            2: "Cb",
            3: "Cr",
            4: "R",
            5: "G",
            6: "B"
        }
    }
    enableXmp() {
        this.isXmpEnabled = true
    }
    disableXmp() {
        this.isXmpEnabled = false;
    }
    /**
     * 获取图片数据
     * @param img 图片地址
     * @param callback 回调 返回图片数据
     * */
    getData(img : any, callback : Function) {
        // if (((self.Image && img instanceof self.Image) || (self.HTMLImageElement && img instanceof self.HTMLImageElement)) && !img.complete)
        //     return false;
        let file : File = {
            src: '',
            exifdata: null,
            iptcdata: null,
            xmpdata: null,
        }
        if (isBase64(img)) {
            file.src = img
        } else if (img.path) {
            file.src = img.path
        } else if (isString(img)) {
            file.src = img
        } else {
            return false;
        }
        if (!imageHasData(file)) {
            getImageData(file, callback);
        } else {
            if (callback) {
                callback.call(file);
            }
        }
        return true;
    }
    /**
     * 获取图片tag
     * @param img 图片数据
     * @param tag tag 类型
     * */
    getTag(img : File, tag : string) {
        if (!imageHasData(img)) return;
        return img.exifdata[tag];
    }
    getIptcTag(img : File, tag : string) {
        if (!imageHasData(img)) return;
        return img.iptcdata[tag];
    }
    getAllTags(img : File) {
        if (!imageHasData(img)) return {};
        let a,
            data = img.exifdata,
            tags = {};
        for (a in data) {
            if (data.hasOwnProperty(a)) {
                tags[a] = data[a];
            }
        }
        return tags;
    }
    getAllIptcTags(img : File) {
        if (!imageHasData(img)) return {};
        let a,
            data = img.iptcdata,
            tags = {};
        for (a in data) {
            if (data.hasOwnProperty(a)) {
                tags[a] = data[a];
            }
        }
        return tags;
    }
    pretty(img : File) {
        if (!imageHasData(img)) return "";
        let a,
            data = img.exifdata,
            strPretty = "";
        for (a in data) {
            if (data.hasOwnProperty(a)) {
                if (typeof data[a] == "object") {
                    if (data[a] instanceof Number) {
                        strPretty += a + " : " + data[a] + " [" + data[a].numerator + "/" + data[a]
                            .denominator + "]\r\n";
                    } else {
                        strPretty += a + " : [" + data[a].length + " values]\r\n";
                    }
                } else {
                    strPretty += a + " : " + data[a] + "\r\n";
                }
            }
        }
        return strPretty;
    }
    readFromBinaryFile(file: ArrayBuffer) {
        return findEXIFinJPEG(file);
    }
}
export const exif = new EXIF()
// export function getData(img, callback) {
//     const exif = new EXIF()
//     exif.getData(img, callback)
// }
// export default {getData}
const ExifTags = exif.Tags
const TiffTags = exif.TiffTags
const IFD1Tags = exif.IFD1Tags
const GPSTags = exif.GPSTags
const StringValues = exif.StringValues
function imageHasData(img : File) : boolean {
    return !!(img.exifdata);
}
function objectURLToBlob(url : string, callback : Function) {
    try {
        const http = new XMLHttpRequest();
        http.open("GET", url, true);
        http.responseType = "blob";
        http.onload = function (e) {
            if (this.status == 200 || this.status === 0) {
                callback(this.response);
            }
        };
        http.send();
    } catch (e) {
        console.warn(e)
    }
}
function getImageData(img : File, callback : Function) {
    function handleBinaryFile(binFile: ArrayBuffer) {
        const data = findEXIFinJPEG(binFile);
        img.exifdata = data ?? {};
        const iptcdata = findIPTCinJPEG(binFile);
        img.iptcdata = iptcdata ?? {};
        if (exif.isXmpEnabled) {
            const xmpdata = findXMPinJPEG(binFile);
            img.xmpdata = xmpdata ?? {};
        }
        if (callback) {
            callback.call(img);
        }
    }
    if (img.src) {
        if (/^data\:/i.test(img.src)) { // Data URI
            // var arrayBuffer = base64ToArrayBuffer(img.src);
            handleBinaryFile(base64ToArrayBuffer(img.src));
        } else if (/^blob\:/i.test(img.src) && typeof FileReader !== 'undefined') { // Object URL
            var fileReader = new FileReader();
            fileReader.onload = function (e) {
                handleBinaryFile(e.target.result);
            };
            objectURLToBlob(img.src, function (blob : Blob) {
                fileReader.readAsArrayBuffer(blob);
            });
        } else if (typeof XMLHttpRequest !== 'undefined') {
            var http = new XMLHttpRequest();
            http.onload = function () {
                if (this.status == 200 || this.status === 0) {
                    handleBinaryFile(http.response);
                } else {
                    throw "Could not load image";
                }
                http = null;
            };
            http.open("GET", img.src, true);
            http.responseType = "arraybuffer";
            http.send(null);
        } else {
            pathToBase64(img.src).then(res => {
                handleBinaryFile(base64ToArrayBuffer(res));
            })
        }
    } else if (typeof FileReader !== 'undefined' && self.FileReader && (img instanceof self.Blob || img instanceof self.File)) {
        var fileReader = new FileReader();
        fileReader.onload = function (e : any) {
            if (exif.debug) console.log("Got file of length " + e.target.result.byteLength);
            handleBinaryFile(e.target.result);
        };
        fileReader.readAsArrayBuffer(img);
    }
}
function findEXIFinJPEG(file: ArrayBuffer) {
    const dataView = new DataView(file);
    if (exif.debug) console.log("Got file of length " + file.byteLength);
    if ((dataView.getUint8(0) != 0xFF) || (dataView.getUint8(1) != 0xD8)) {
        if (exif.debug) console.log("Not a valid JPEG");
        return false; // not a valid jpeg
    }
    let offset = 2,
        length = file.byteLength,
        marker;
    while (offset < length) {
        if (dataView.getUint8(offset) != 0xFF) {
            if (exif.debug) console.log("Not a valid marker at offset " + offset + ", found: " + dataView.getUint8(
                offset));
            return false; // not a valid marker, something is wrong
        }
        marker = dataView.getUint8(offset + 1);
        if (exif.debug) console.log(marker);
        // we could implement handling for other markers here,
        // but we're only looking for 0xFFE1 for EXIF data
        if (marker == 225) {
            if (exif.debug) console.log("Found 0xFFE1 marker");
            return readEXIFData(dataView, offset + 4, dataView.getUint16(offset + 2) - 2);
            // offset += 2 + file.getShortAt(offset+2, true);
        } else {
            offset += 2 + dataView.getUint16(offset + 2);
        }
    }
}
function findIPTCinJPEG(file: ArrayBuffer) {
    const dataView = new DataView(file);
    if (exif.debug) console.log("Got file of length " + file.byteLength);
    if ((dataView.getUint8(0) != 0xFF) || (dataView.getUint8(1) != 0xD8)) {
        if (exif.debug) console.log("Not a valid JPEG");
        return false; // not a valid jpeg
    }
    let offset = 2,
        length = file.byteLength;
    const isFieldSegmentStart = function (dataView, offset: number) {
        return (
            dataView.getUint8(offset) === 0x38 &&
            dataView.getUint8(offset + 1) === 0x42 &&
            dataView.getUint8(offset + 2) === 0x49 &&
            dataView.getUint8(offset + 3) === 0x4D &&
            dataView.getUint8(offset + 4) === 0x04 &&
            dataView.getUint8(offset + 5) === 0x04
        );
    };
    while (offset < length) {
        if (isFieldSegmentStart(dataView, offset)) {
            // Get the length of the name header (which is padded to an even number of bytes)
            var nameHeaderLength = dataView.getUint8(offset + 7);
            if (nameHeaderLength % 2 !== 0) nameHeaderLength += 1;
            // Check for pre photoshop 6 format
            if (nameHeaderLength === 0) {
                // Always 4
                nameHeaderLength = 4;
            }
            var startOffset = offset + 8 + nameHeaderLength;
            var sectionLength = dataView.getUint16(offset + 6 + nameHeaderLength);
            return readIPTCData(file, startOffset, sectionLength);
            break;
        }
        // Not the marker, continue searching
        offset++;
    }
}
const IptcFieldMap = {
    0x78: 'caption',
    0x6E: 'credit',
    0x19: 'keywords',
    0x37: 'dateCreated',
    0x50: 'byline',
    0x55: 'bylineTitle',
    0x7A: 'captionWriter',
    0x69: 'headline',
    0x74: 'copyright',
    0x0F: 'category'
};
function readIPTCData(file: ArrayBuffer, startOffset: number, sectionLength: number) {
    const dataView = new DataView(file);
    let data = {};
    let fieldValue, fieldName, dataSize, segmentType, segmentSize;
    let segmentStartPos = startOffset;
    while (segmentStartPos < startOffset + sectionLength) {
        if (dataView.getUint8(segmentStartPos) === 0x1C && dataView.getUint8(segmentStartPos + 1) === 0x02) {
            segmentType = dataView.getUint8(segmentStartPos + 2);
            if (segmentType in IptcFieldMap) {
                dataSize = dataView.getInt16(segmentStartPos + 3);
                segmentSize = dataSize + 5;
                fieldName = IptcFieldMap[segmentType];
                fieldValue = getStringFromDB(dataView, segmentStartPos + 5, dataSize);
                // Check if we already stored a value with this name
                if (data.hasOwnProperty(fieldName)) {
                    // Value already stored with this name, create multivalue field
                    if (data[fieldName] instanceof Array) {
                        data[fieldName].push(fieldValue);
                    } else {
                        data[fieldName] = [data[fieldName], fieldValue];
                    }
                } else {
                    data[fieldName] = fieldValue;
                }
            }
        }
        segmentStartPos++;
    }
    return data;
}
function readTags(file: DataView, tiffStart: number, dirStart: number, strings: any[], bigEnd: number) {
    let entries = file.getUint16(dirStart, !bigEnd),
        tags = {},
        entryOffset, tag;
    for (let i = 0; i < entries; i++) {
        entryOffset = dirStart + i * 12 + 2;
        tag = strings[file.getUint16(entryOffset, !bigEnd)];
        if (!tag && exif.debug) console.log("Unknown tag: " + file.getUint16(entryOffset, !bigEnd));
        tags[tag] = readTagValue(file, entryOffset, tiffStart, dirStart, bigEnd);
    }
    return tags;
}
function readTagValue(file: DataView, entryOffset: number, tiffStart: number, dirStart: number, bigEnd: number) {
    let type = file.getUint16(entryOffset + 2, !bigEnd),
        numValues = file.getUint32(entryOffset + 4, !bigEnd),
        valueOffset = file.getUint32(entryOffset + 8, !bigEnd) + tiffStart,
        offset,
        vals, val, n,
        numerator, denominator;
    switch (type) {
        case 1: // byte, 8-bit unsigned int
        case 7: // undefined, 8-bit byte, value depending on field
            if (numValues == 1) {
                return file.getUint8(entryOffset + 8, !bigEnd);
            } else {
                offset = numValues > 4 ? valueOffset : (entryOffset + 8);
                vals = [];
                for (n = 0; n < numValues; n++) {
                    vals[n] = file.getUint8(offset + n);
                }
                return vals;
            }
        case 2: // ascii, 8-bit byte
            offset = numValues > 4 ? valueOffset : (entryOffset + 8);
            return getStringFromDB(file, offset, numValues - 1);
        case 3: // short, 16 bit int
            if (numValues == 1) {
                return file.getUint16(entryOffset + 8, !bigEnd);
            } else {
                offset = numValues > 2 ? valueOffset : (entryOffset + 8);
                vals = [];
                for (n = 0; n < numValues; n++) {
                    vals[n] = file.getUint16(offset + 2 * n, !bigEnd);
                }
                return vals;
            }
        case 4: // long, 32 bit int
            if (numValues == 1) {
                return file.getUint32(entryOffset + 8, !bigEnd);
            } else {
                vals = [];
                for (n = 0; n < numValues; n++) {
                    vals[n] = file.getUint32(valueOffset + 4 * n, !bigEnd);
                }
                return vals;
            }
        case 5: // rational = two long values, first is numerator, second is denominator
            if (numValues == 1) {
                numerator = file.getUint32(valueOffset, !bigEnd);
                denominator = file.getUint32(valueOffset + 4, !bigEnd);
                val = new Number(numerator / denominator);
                val.numerator = numerator;
                val.denominator = denominator;
                return val;
            } else {
                vals = [];
                for (n = 0; n < numValues; n++) {
                    numerator = file.getUint32(valueOffset + 8 * n, !bigEnd);
                    denominator = file.getUint32(valueOffset + 4 + 8 * n, !bigEnd);
                    vals[n] = new Number(numerator / denominator);
                    vals[n].numerator = numerator;
                    vals[n].denominator = denominator;
                }
                return vals;
            }
        case 9: // slong, 32 bit signed int
            if (numValues == 1) {
                return file.getInt32(entryOffset + 8, !bigEnd);
            } else {
                vals = [];
                for (n = 0; n < numValues; n++) {
                    vals[n] = file.getInt32(valueOffset + 4 * n, !bigEnd);
                }
                return vals;
            }
        case 10: // signed rational, two slongs, first is numerator, second is denominator
            if (numValues == 1) {
                return file.getInt32(valueOffset, !bigEnd) / file.getInt32(valueOffset + 4, !bigEnd);
            } else {
                vals = [];
                for (n = 0; n < numValues; n++) {
                    vals[n] = file.getInt32(valueOffset + 8 * n, !bigEnd) / file.getInt32(valueOffset + 4 + 8 *
                        n, !bigEnd);
                }
                return vals;
            }
    }
}
/**
     * Given an IFD (Image File Directory) start offset
     * returns an offset to next IFD or 0 if it's the last IFD.
     */
function getNextIFDOffset(dataView: DataView, dirStart: number, bigEnd: number) {
    //the first 2bytes means the number of directory entries contains in this IFD
    var entries = dataView.getUint16(dirStart, !bigEnd);
    // After last directory entry, there is a 4bytes of data,
    // it means an offset to next IFD.
    // If its value is '0x00000000', it means this is the last IFD and there is no linked IFD.
    return dataView.getUint32(dirStart + 2 + entries * 12, !bigEnd); // each entry is 12 bytes long
}
function readThumbnailImage(dataView: DataView, tiffStart: number, firstIFDOffset: number, bigEnd: number) {
    // get the IFD1 offset
    const IFD1OffsetPointer = getNextIFDOffset(dataView, tiffStart + firstIFDOffset, bigEnd);
    if (!IFD1OffsetPointer) {
        // console.log('******** IFD1Offset is empty, image thumb not found ********');
        return {};
    } else if (IFD1OffsetPointer > dataView.byteLength) { // this should not happen
        // console.log('******** IFD1Offset is outside the bounds of the DataView ********');
        return {};
    }
    // console.log('*******  thumbnail IFD offset (IFD1) is: %s', IFD1OffsetPointer);
    let thumbTags : any = readTags(dataView, tiffStart, tiffStart + IFD1OffsetPointer, IFD1Tags, bigEnd)
    // EXIF 2.3 specification for JPEG format thumbnail
    // If the value of Compression(0x0103) Tag in IFD1 is '6', thumbnail image format is JPEG.
    // Most of Exif image uses JPEG format for thumbnail. In that case, you can get offset of thumbnail
    // by JpegIFOffset(0x0201) Tag in IFD1, size of thumbnail by JpegIFByteCount(0x0202) Tag.
    // Data format is ordinary JPEG format, starts from 0xFFD8 and ends by 0xFFD9. It seems that
    // JPEG format and 160x120pixels of size are recommended thumbnail format for Exif2.1 or later.
    if (thumbTags['Compression'] && typeof Blob !== 'undefined') {
        // console.log('Thumbnail image found!');
        switch (thumbTags['Compression']) {
            case 6:
                // console.log('Thumbnail image format is JPEG');
                if (thumbTags.JpegIFOffset && thumbTags.JpegIFByteCount) {
                    // extract the thumbnail
                    var tOffset = tiffStart + thumbTags.JpegIFOffset;
                    var tLength = thumbTags.JpegIFByteCount;
                    thumbTags['blob'] = new Blob([new Uint8Array(dataView.buffer, tOffset, tLength)], {
                        type: 'image/jpeg'
                    });
                }
                break;
            case 1:
                console.log("Thumbnail image format is TIFF, which is not implemented.");
                break;
            default:
                console.log("Unknown thumbnail image format '%s'", thumbTags['Compression']);
        }
    } else if (thumbTags['PhotometricInterpretation'] == 2) {
        console.log("Thumbnail image format is RGB, which is not implemented.");
    }
    return thumbTags;
}
function getStringFromDB(buffer: DataView, start: number, length: number) {
    let outstr = "";
    for (let n = start; n < start + length; n++) {
        outstr += String.fromCharCode(buffer.getUint8(n));
    }
    return outstr;
}
function readEXIFData(file: DataView, start: number) {
    if (getStringFromDB(file, start, 4) != "Exif") {
        if (exif.debug) console.log("Not valid EXIF data! " + getStringFromDB(file, start, 4));
        return false;
    }
    let bigEnd,
        tags, tag,
        exifData, gpsData,
        tiffOffset = start + 6;
    // test for TIFF validity and endianness
    if (file.getUint16(tiffOffset) == 0x4949) {
        bigEnd = false;
    } else if (file.getUint16(tiffOffset) == 0x4D4D) {
        bigEnd = true;
    } else {
        if (exif.debug) console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)");
        return false;
    }
    if (file.getUint16(tiffOffset + 2, !bigEnd) != 0x002A) {
        if (exif.debug) console.log("Not valid TIFF data! (no 0x002A)");
        return false;
    }
    const firstIFDOffset = file.getUint32(tiffOffset + 4, !bigEnd);
    if (firstIFDOffset < 0x00000008) {
        if (exif.debug) console.log("Not valid TIFF data! (First offset less than 8)", file.getUint32(tiffOffset + 4,
            !bigEnd));
        return false;
    }
    tags = readTags(file, tiffOffset, tiffOffset + firstIFDOffset, TiffTags, bigEnd);
    if (tags.ExifIFDPointer) {
        exifData = readTags(file, tiffOffset, tiffOffset + tags.ExifIFDPointer, ExifTags, bigEnd);
        for (tag in exifData) {
            switch (tag) {
                case "LightSource":
                case "Flash":
                case "MeteringMode":
                case "ExposureProgram":
                case "SensingMethod":
                case "SceneCaptureType":
                case "SceneType":
                case "CustomRendered":
                case "WhiteBalance":
                case "GainControl":
                case "Contrast":
                case "Saturation":
                case "Sharpness":
                case "SubjectDistanceRange":
                case "FileSource":
                    exifData[tag] = StringValues[tag][exifData[tag]];
                    break;
                case "ExifVersion":
                case "FlashpixVersion":
                    exifData[tag] = String.fromCharCode(exifData[tag][0], exifData[tag][1], exifData[tag][2],
                        exifData[tag][3]);
                    break;
                case "ComponentsConfiguration":
                    exifData[tag] =
                        StringValues.Components[exifData[tag][0]] +
                        StringValues.Components[exifData[tag][1]] +
                        StringValues.Components[exifData[tag][2]] +
                        StringValues.Components[exifData[tag][3]];
                    break;
            }
            tags[tag] = exifData[tag];
        }
    }
    if (tags.GPSInfoIFDPointer) {
        gpsData = readTags(file, tiffOffset, tiffOffset + tags.GPSInfoIFDPointer, GPSTags, bigEnd);
        for (tag in gpsData) {
            switch (tag) {
                case "GPSVersionID":
                    gpsData[tag] = gpsData[tag][0] +
                        "." + gpsData[tag][1] +
                        "." + gpsData[tag][2] +
                        "." + gpsData[tag][3];
                    break;
            }
            tags[tag] = gpsData[tag];
        }
    }
    // extract thumbnail
    tags['thumbnail'] = readThumbnailImage(file, tiffOffset, firstIFDOffset, bigEnd);
    return tags;
}
function findXMPinJPEG(file: ArrayBuffer) {
    if (!('DOMParser' in self)) {
        // console.warn('XML parsing not supported without DOMParser');
        return;
    }
    const dataView = new DataView(file);
    if (exif.debug) console.log("Got file of length " + file.byteLength);
    if ((dataView.getUint8(0) != 0xFF) || (dataView.getUint8(1) != 0xD8)) {
        if (exif.debug) console.log("Not a valid JPEG");
        return false; // not a valid jpeg
    }
    let offset = 2,
        length = file.byteLength,
        dom = new DOMParser();
    while (offset < (length - 4)) {
        if (getStringFromDB(dataView, offset, 4) == "http") {
            const startOffset = offset - 1;
            const sectionLength = dataView.getUint16(offset - 2) - 1;
            let xmpString = getStringFromDB(dataView, startOffset, sectionLength)
            const xmpEndIndex = xmpString.indexOf('xmpmeta>') + 8;
            xmpString = xmpString.substring(xmpString.indexOf('<x:xmpmeta'), xmpEndIndex);
            const indexOfXmp = xmpString.indexOf('x:xmpmeta') + 10
            //Many custom written programs embed xmp/xml without any namespace. Following are some of them.
            //Without these namespaces, XML is thought to be invalid by parsers
            xmpString = xmpString.slice(0, indexOfXmp) +
                'xmlns:Iptc4xmpCore="http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/" ' +
                'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
                'xmlns:tiff="http://ns.adobe.com/tiff/1.0/" ' +
                'xmlns:plus="http://schemas.android.com/apk/lib/com.google.android.gms.plus" ' +
                'xmlns:ext="http://www.gettyimages.com/xsltExtension/1.0" ' +
                'xmlns:exif="http://ns.adobe.com/exif/1.0/" ' +
                'xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" ' +
                'xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#" ' +
                'xmlns:crs="http://ns.adobe.com/camera-raw-settings/1.0/" ' +
                'xmlns:xapGImg="http://ns.adobe.com/xap/1.0/g/img/" ' +
                'xmlns:Iptc4xmpExt="http://iptc.org/std/Iptc4xmpExt/2008-02-29/" ' +
                xmpString.slice(indexOfXmp)
            var domDocument = dom.parseFromString(xmpString, 'text/xml');
            return xml2Object(domDocument);
        } else {
            offset++;
        }
    }
}
function xml2json(xml: any) {
    var json = {};
    if (xml.nodeType == 1) { // element node
        if (xml.attributes.length > 0) {
            json['@attributes'] = {};
            for (var j = 0; j < xml.attributes.length; j++) {
                var attribute = xml.attributes.item(j);
                json['@attributes'][attribute.nodeName] = attribute.nodeValue;
            }
        }
    } else if (xml.nodeType == 3) { // text node
        return xml.nodeValue;
    }
    // deal with children
    if (xml.hasChildNodes()) {
        for (var i = 0; i < xml.childNodes.length; i++) {
            var child = xml.childNodes.item(i);
            var nodeName = child.nodeName;
            if (json[nodeName] == null) {
                json[nodeName] = xml2json(child);
            } else {
                if (json[nodeName].push == null) {
                    var old = json[nodeName];
                    json[nodeName] = [];
                    json[nodeName].push(old);
                }
                json[nodeName].push(xml2json(child));
            }
        }
    }
    return json;
}
function xml2Object(xml: any) {
    try {
        var obj = {};
        if (xml.children.length > 0) {
            for (var i = 0; i < xml.children.length; i++) {
                var item = xml.children.item(i);
                var attributes = item.attributes;
                for (var idx in attributes) {
                    var itemAtt = attributes[idx];
                    var dataKey = itemAtt.nodeName;
                    var dataValue = itemAtt.nodeValue;
                    if (dataKey !== undefined) {
                        obj[dataKey] = dataValue;
                    }
                }
                var nodeName = item.nodeName;
                if (typeof (obj[nodeName]) == "undefined") {
                    obj[nodeName] = xml2json(item);
                } else {
                    if (typeof (obj[nodeName].push) == "undefined") {
                        var old = obj[nodeName];
                        obj[nodeName] = [];
                        obj[nodeName].push(old);
                    }
                    obj[nodeName].push(xml2json(item));
                }
            }
        } else {
            obj = xml.textContent;
        }
        return obj;
    } catch (e) {
        console.log(e.message);
    }
}
uni_modules/lime-shared/fillZero/index.ts
对比新文件
@@ -0,0 +1,11 @@
// @ts-nocheck
/**
 * 在数字前填充零,返回字符串形式的结果
 * @param number 要填充零的数字
 * @param length 填充零后的字符串长度,默认为2
 * @returns 填充零后的字符串
 */
export function fillZero(number: number, length: number = 2): string {
  // 将数字转换为字符串,然后使用 padStart 方法填充零到指定长度
  return `${number}`.padStart(length, '0');
}
uni_modules/lime-shared/floatAdd/index.ts
对比新文件
@@ -0,0 +1,36 @@
import { isNumber } from '../isNumber'
/**
 * 返回两个浮点数相加的结果
 * @param num1 第一个浮点数
 * @param num2 第二个浮点数
 * @returns 两个浮点数的相加结果
 */
export function floatAdd(num1 : number, num2 : number) : number {
    // 检查 num1 和 num2 是否为数字类型
    if (!(isNumber(num1) || isNumber(num2))) {
        console.warn('Please pass in the number type');
        return NaN;
    }
    let r1 : number, r2 : number, m : number;
    try {
        // 获取 num1 小数点后的位数
        r1 = num1.toString().split('.')[1].length;
    } catch (error) {
        r1 = 0;
    }
    try {
        // 获取 num2 小数点后的位数
        r2 = num2.toString().split('.')[1].length;
    } catch (error) {
        r2 = 0;
    }
    // 计算需要扩大的倍数
    m = Math.pow(10, Math.max(r1, r2));
    // 返回相加结果
    return (num1 * m + num2 * m) / m;
}
uni_modules/lime-shared/floatDiv/index.ts
对比新文件
@@ -0,0 +1,45 @@
import { floatMul } from '../floatMul';
import { isNumber } from '../isNumber';
/**
 * 除法函数,用于处理浮点数除法并保持精度。
 * @param {number} num1 - 被除数。
 * @param {number} num2 - 除数。
 * @returns {number} 除法运算的结果,保留正确的精度。
 */
export function floatDiv(num1:number, num2:number):number {
  // 如果传入的不是数字类型,则打印警告并返回NaN
  if (!isNumber(num1) || !isNumber(num2)) {
    console.warn('请传入数字类型');
    return NaN;
  }
  let m1 = 0, // 被除数小数点后的位数
    m2 = 0, // 除数小数点后的位数
    s1 = num1.toString(), // 将被除数转换为字符串
    s2 = num2.toString(); // 将除数转换为字符串
  // 计算被除数小数点后的位数
  try {
    m1 += s1.split('.')[1].length;
  } catch (error) {}
  // 计算除数小数点后的位数
  try {
    m2 += s2.split('.')[1].length;
  } catch (error) {}
  // 进行除法运算并处理小数点后的位数,使用之前定义的乘法函数保持精度
  // #ifdef APP-ANDROID
  return floatMul(
    parseFloat(s1.replace('.', '')) / parseFloat(s2.replace('.', '')),
    Math.pow(10, m2 - m1),
  );
  // #endif
  // #ifndef APP-ANDROID
  return floatMul(
    Number(s1.replace('.', '')) / Number(s2.replace('.', '')),
    Math.pow(10, m2 - m1),
  );
  // #endif
}
uni_modules/lime-shared/floatMul/index.ts
对比新文件
@@ -0,0 +1,44 @@
// @ts-nocheck
import {isNumber} from '../isNumber';
// #ifdef APP-ANDROID
import BigDecimal from 'java.math.BigDecimal'
// import BigDecimal from 'java.math.BigDecimal'
// import StringBuilder from 'java.lang.StringBuilder'
// import java.math.BigDecimal;
// #endif
/**
 * 乘法函数,用于处理浮点数乘法并保持精度。
 * @param {number} num1 - 第一个乘数。
 * @param {number} num2 - 第二个乘数。
 * @returns {number} 乘法运算的结果,保留正确的精度。
 */
export function floatMul(num1 : number, num2 : number) : number {
    if (!(isNumber(num1) || isNumber(num2))) {
        console.warn('Please pass in the number type');
        return NaN;
    }
    let m = 0;
    // #ifdef APP-ANDROID
    let    s1 = BigDecimal.valueOf(num1.toDouble()).toPlainString(); //new UTSNumber(num1).toString() // //`${num1.toFloat()}`// num1.toString(),
    let    s2 = BigDecimal.valueOf(num2.toDouble()).toPlainString(); //new UTSNumber(num2).toString() //`${num2.toFloat()}`//.toString();
    // #endif
    // #ifndef APP-ANDROID
    let    s1:string = `${num1}`// num1.toString(),
    let    s2:string = `${num2}`//.toString();
    // #endif
    try {
        m += s1.split('.')[1].length;
    } catch (error) { }
    try {
        m += s2.split('.')[1].length;
    } catch (error) { }
    // #ifdef APP-ANDROID
    return parseFloat(s1.replace('.', '')) * parseFloat(s2.replace('.', '')) / Math.pow(10, m);
    // #endif
    // #ifndef APP-ANDROID
    return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m);
    // #endif
}
uni_modules/lime-shared/floatSub/index.ts
对比新文件
@@ -0,0 +1,32 @@
import { isNumber } from '../isNumber';
/**
 * 减法函数,用于处理浮点数减法并保持精度。
 * @param {number} num1 - 被减数。
 * @param {number} num2 - 减数。
 * @returns {number} 减法运算的结果,保留正确的精度。
 */
export function floatSub(num1 : number, num2 : number) : number {
    if (!(isNumber(num1) || isNumber(num2))) {
        console.warn('Please pass in the number type');
        return NaN;
    }
    let r1:number, r2:number, m:number, n:number;
    try {
        r1 = num1.toString().split('.')[1].length;
    } catch (error) {
        r1 = 0;
    }
    try {
        r2 = num2.toString().split('.')[1].length;
    } catch (error) {
        r2 = 0;
    }
    m = Math.pow(10, Math.max(r1, r2));
    n = r1 >= r2 ? r1 : r2;
    // #ifndef APP-ANDROID
    return Number(((num1 * m - num2 * m) / m).toFixed(n));
    // #endif
    // #ifdef APP-ANDROID
    return parseFloat(((num1 * m - num2 * m) / m).toFixed(n));
    // #endif
}
uni_modules/lime-shared/getClassStr/index.ts
对比新文件
@@ -0,0 +1,53 @@
// @ts-nocheck
// #ifdef UNI-APP-X && APP
import { isNumber } from '../isNumber'
import { isString } from '../isString'
import { isDef } from '../isDef'
// #endif
/**
 * 获取对象的类名字符串
 * @param obj - 需要处理的对象
 * @returns 由对象属性作为类名组成的字符串
 */
export function getClassStr<T>(obj : T) : string {
    let classNames : string[] = [];
    // #ifdef UNI-APP-X && APP
    if (obj instanceof UTSJSONObject) {
        (obj as UTSJSONObject).toMap().forEach((value, key) => {
            if (isDef(value)) {
                if (isNumber(value)) {
                    classNames.push(key);
                }
                if (isString(value) && value !== '') {
                    classNames.push(key);
                }
                if (typeof value == 'boolean' && (value as boolean)) {
                    classNames.push(key);
                }
            }
        })
    }
    // #endif
    // #ifndef UNI-APP-X && APP
    // 遍历对象的属性
    for (let key in obj) {
        // 检查属性确实属于对象自身且其值为true
        if ((obj as any).hasOwnProperty(key) && obj[key]) {
            // 将属性名添加到类名数组中
            classNames.push(key);
        }
    }
    // #endif
    // 将类名数组用空格连接成字符串并返回
    return classNames.join(' ');
}
// 示例
// const obj = { foo: true, bar: false, baz: true };
// const classNameStr = getClassStr(obj);
// console.log(classNameStr); // 输出: "foo baz"
uni_modules/lime-shared/getCurrentPage/index.ts
对比新文件
@@ -0,0 +1,9 @@
// @ts-nocheck
// #ifndef UNI-APP-X && APP
export * from './vue.ts'
// #endif
// #ifdef UNI-APP-X && APP
export * from './uvue.uts'
// #endif
uni_modules/lime-shared/getCurrentPage/uvue.uts
对比新文件
@@ -0,0 +1,5 @@
// @ts-nocheck
export const getCurrentPage = ():Page => {
  const pages = getCurrentPages();
  return pages[pages.length - 1]
};
uni_modules/lime-shared/getCurrentPage/vue.ts
对比新文件
@@ -0,0 +1,6 @@
// @ts-nocheck
/** 获取当前页 */
export const getCurrentPage = () => {
  const pages = getCurrentPages();
  return pages[pages.length - 1] //as T & WechatMiniprogram.Page.TrivialInstance;
};
uni_modules/lime-shared/getLocalFilePath/index.ts
对比新文件
@@ -0,0 +1,62 @@
// @ts-nocheck
// #ifdef APP-NVUE  || APP-VUE
export const getLocalFilePath = (path : string) => {
    if (typeof plus == 'undefined') return path
    if (/^(_www|_doc|_documents|_downloads|file:\/\/|\/storage\/emulated\/0\/)/.test(path)) return path
    if (/^\//.test(path)) {
        const localFilePath = plus.io.convertAbsoluteFileSystem(path)
        if (localFilePath !== path) {
            return localFilePath
        } else {
            path = path.slice(1)
        }
    }
    return '_www/' + path
}
// #endif
// #ifdef UNI-APP-X && APP
export { getResourcePath as getLocalFilePath } from '@/uni_modules/lime-file-utils'
// export const getLocalFilePath = (path : string) : string => {
//     let uri = path
//     if (uri.startsWith("http") || uri.startsWith("<svg") || uri.startsWith("data:image/svg+xml")) {
//         return uri
//     }
//     if (uri.startsWith("file://")) {
//         uri = uri.substring("file://".length)
//     } else if (uri.startsWith("unifile://")) {
//         uri = UTSAndroid.convert2AbsFullPath(uri)
//     } else {
//         uri = UTSAndroid.convert2AbsFullPath(uri)
//         if (uri.startsWith("/android_asset/")) {
//             uri = uri.replace("/android_asset/", "")
//         }
//     }
//     if (new File(uri).exists()) {
//         return uri
//     } else {
//         return null
//     }
//     // return UTSAndroid.convert2AbsFullPath(path)
// }
// #endif
// #ifdef APP-IOS
// export const getLocalFilePath = (path : string) : string => {
//     try {
//         let uri = path
//         if (uri.startsWith("http") || uri.startsWith("<svg") || uri.startsWith("data:image/svg+xml")) {
//             return uri
//         }
//         if (uri.startsWith("file://")) {
//             return uri.substring("file://".length)
//         } else if (path.startsWith("/var/")) {
//             return path
//         }
//         return UTSiOS.getResourcePath(path)
//     } catch (e) {
//         return null
//     }
//     // return UTSiOS.getResourcePath(path)
// }
// #endif
uni_modules/lime-shared/getRect/index.ts
对比新文件
@@ -0,0 +1,9 @@
// @ts-nocheck
// #ifdef UNI-APP-X && APP
export * from './uvue.uts'
// #endif
// #ifndef UNI-APP-X && APP
export * from './vue.ts'
// #endif
uni_modules/lime-shared/getRect/uvue.uts
对比新文件
@@ -0,0 +1,16 @@
// @ts-nocheck
export function getRect(selector : string, context: ComponentInternalInstance):Promise<NodeInfo> {
    return new Promise((resolve)=>{
        uni.createSelectorQuery().in(context).select(selector).boundingClientRect(res =>{
            resolve(res as NodeInfo)
        }).exec();
    })
}
export function getAllRect(selector : string, context: ComponentInternalInstance):Promise<NodeInfo[]> {
    return new Promise((resolve)=>{
        uni.createSelectorQuery().in(context).selectAll(selector).boundingClientRect(res =>{
            resolve(res as NodeInfo[])
        }).exec();
    })
}
uni_modules/lime-shared/getRect/vue.ts
对比新文件
@@ -0,0 +1,117 @@
// @ts-nocheck
// #ifdef APP-NVUE
// 当编译环境是 APP-NVUE 时,引入 uni.requireNativePlugin('dom'),具体插件用途未知
const dom = uni.requireNativePlugin('dom')
// #endif
/**
 * 获取节点信息
 * @param selector 选择器字符串
 * @param context ComponentInternalInstance 对象
 * @param node 是否获取node
 * @returns 包含节点信息的 Promise 对象
 */
export function getRect(selector : string, context : ComponentInternalInstance, node: boolean = false) {
    // 之前是个对象,现在改成实例,防止旧版会报错
    if(context== null) {
        return Promise.reject('context is null')
    }
    if(context.context){
        context = context.context
    }
    // #ifdef MP || VUE2
    if (context.proxy) context = context.proxy
    // #endif
    return new Promise<UniNamespace.NodeInfo>((resolve, reject) => {
        // #ifndef APP-NVUE
        const dom = uni.createSelectorQuery().in(context).select(selector);
        const result = (rect: UniNamespace.NodeInfo) => {
            if (rect) {
                resolve(rect)
            } else {
                reject('no rect')
            }
        }
        if (!node) {
            dom.boundingClientRect(result).exec()
        } else {
            dom.fields({
                node: true,
                size: true,
                rect: true
            }, result).exec()
        }
        // #endif
        // #ifdef APP-NVUE
        let { context } = options
        if (/#|\./.test(selector) && context.refs) {
            selector = selector.replace(/#|\./, '')
            if (context.refs[selector]) {
                selector = context.refs[selector]
                if(Array.isArray(selector)) {
                    selector = selector[0]
                }
            }
        }
        dom.getComponentRect(selector, (res) => {
            if (res.size) {
                resolve(res.size)
            } else {
                reject('no rect')
            }
        })
        // #endif
    });
};
export function getAllRect(selector : string, context: ComponentInternalInstance, node:boolean = false) {
    if(context== null) {
        return Promise.reject('context is null')
    }
    // #ifdef MP || VUE2
    if (context.proxy) context = context.proxy
    // #endif
    return new Promise<UniNamespace.NodeInfo>((resolve, reject) => {
        // #ifndef APP-NVUE
        const dom = uni.createSelectorQuery().in(context).selectAll(selector);
        const result = (rect: UniNamespace.NodeInfo[]) => {
            if (rect) {
                resolve(rect)
            } else {
                reject('no rect')
            }
        }
        if (!node) {
            dom.boundingClientRect(result).exec()
        } else {
            dom.fields({
                node: true,
                size: true,
                rect: true
            }, result).exec()
        }
        // #endif
        // #ifdef APP-NVUE
        let { context } = options
        if (/#|\./.test(selector) && context.refs) {
            selector = selector.replace(/#|\./, '')
            if (context.refs[selector]) {
                selector = context.refs[selector]
                if(Array.isArray(selector)) {
                    selector = selector[0]
                }
            }
        }
        dom.getComponentRect(selector, (res) => {
            if (res.size) {
                resolve([res.size])
            } else {
                reject('no rect')
            }
        })
        // #endif
    });
};
uni_modules/lime-shared/getStyleStr/index.ts
对比新文件
@@ -0,0 +1,54 @@
// @ts-nocheck
// #ifndef UNI-APP-X && APP
interface CSSProperties {
    [key : string] : string | number | null
}
// #endif
// #ifdef VUE3
// #ifdef UNI-APP-X && APP
type CSSProperties = UTSJSONObject
// #endif
// #endif
/**
 * 将字符串转换为带有连字符分隔的小写形式
 * @param key - 要转换的字符串
 * @returns 转换后的字符串
 */
export function toLowercaseSeparator(key : string):string {
    return key.replace(/([A-Z])/g, '-$1').toLowerCase();
}
/**
 * 获取样式对象对应的样式字符串
 * @param style - CSS样式对象
 * @returns 由非空有效样式属性键值对组成的字符串
 */
export function getStyleStr(style : CSSProperties) : string {
    // #ifdef UNI-APP-X && APP
    let styleStr = '';
    style.toMap().forEach((value, key) => {
        if(value !== null && value != '') {
            styleStr += `${toLowercaseSeparator(key as string)}: ${value};`
        }
    })
    return styleStr
    // #endif
    // #ifndef UNI-APP-X && APP
    return Object.keys(style)
        .filter(
            (key) =>
                style[key] !== undefined &&
                style[key] !== null &&
                style[key] !== '')
        .map((key : string) => `${toLowercaseSeparator(key)}: ${style[key]};`)
        .join(' ');
    // #endif
}
// 示例
// const style = { color: 'red', fontSize: '16px', backgroundColor: '', border: null };
// const styleStr = getStyleStr(style);
// console.log(styleStr);
// 输出: "color: red; font-size: 16px;"
uni_modules/lime-shared/getStyleStr/index_.uts
对比新文件
@@ -0,0 +1,39 @@
// @ts-nocheck
// #ifndef UNI-APP-X
interface CSSProperties {
    [key : string] : string | number
}
// #endif
// #ifdef UNI-APP-X
type CSSProperties = UTSJSONObject
// #endif
/**
 * 将字符串转换为带有连字符分隔的小写形式
 * @param key - 要转换的字符串
 * @returns 转换后的字符串
 */
export function toLowercaseSeparator(key : string) : string {
    return key.replace(/([A-Z])/g, '-$1').toLowerCase();
}
/**
 * 获取样式对象对应的样式字符串
 * @param style - CSS样式对象
 * @returns 由非空有效样式属性键值对组成的字符串
 */
export function getStyleStr(style : CSSProperties) : string {
    let styleStr = '';
    style.toMap().forEach((value, key) => {
        if(value !== null && value != '') {
            styleStr += `${toLowercaseSeparator(key as string)}: ${value};`
        }
    })
    return styleStr
}
// 示例
// const style = { color: 'red', fontSize: '16px', backgroundColor: '', border: null };
// const styleStr = getStyleStr(style);
// console.log(styleStr);
// 输出: "color: red; font-size: 16px;"
uni_modules/lime-shared/hasOwn/index.ts
对比新文件
@@ -0,0 +1,9 @@
// @ts-nocheck
// #ifdef UNI-APP-X && APP
export * from './uvue.ts'
// #endif
// #ifndef UNI-APP-X && APP
export * from './vue.ts'
// #endif
uni_modules/lime-shared/hasOwn/uvue.ts
对比新文件
@@ -0,0 +1,39 @@
// @ts-nocheck
/**
 * 检查对象或数组是否具有指定的属性或键
 * @param obj 要检查的对象或数组
 * @param key 指定的属性或键
 * @returns 如果对象或数组具有指定的属性或键,则返回true;否则返回false
 */
function hasOwn(obj: UTSJSONObject, key: string): boolean
function hasOwn(obj: Map<string, unknown>, key: string): boolean
function hasOwn(obj: any, key: string): boolean {
  if(obj instanceof UTSJSONObject){
     return obj[key] != null
  }
  if(obj instanceof Map<string, unknown>){
       return (obj as Map<string, unknown>).has(key)
  }
  return false
}
export {
    hasOwn
}
// 示例
// const obj = { name: 'John', age: 30 };
// if (hasOwn(obj, 'name')) {
//   console.log("对象具有 'name' 属性");
// } else {
//   console.log("对象不具有 'name' 属性");
// }
// // 输出: 对象具有 'name' 属性
// const arr = [1, 2, 3];
// if (hasOwn(arr, 'length')) {
//   console.log("数组具有 'length' 属性");
// } else {
//   console.log("数组不具有 'length' 属性");
// }
// 输出: 数组具有 'length' 属性
uni_modules/lime-shared/hasOwn/vue.ts
对比新文件
@@ -0,0 +1,30 @@
// @ts-nocheck
const hasOwnProperty = Object.prototype.hasOwnProperty
/**
 * 检查对象或数组是否具有指定的属性或键
 * @param obj 要检查的对象或数组
 * @param key 指定的属性或键
 * @returns 如果对象或数组具有指定的属性或键,则返回true;否则返回false
 */
export function hasOwn(obj: Object | Array<any>, key: string): boolean {
  return hasOwnProperty.call(obj, key);
}
// 示例
// const obj = { name: 'John', age: 30 };
// if (hasOwn(obj, 'name')) {
//   console.log("对象具有 'name' 属性");
// } else {
//   console.log("对象不具有 'name' 属性");
// }
// // 输出: 对象具有 'name' 属性
// const arr = [1, 2, 3];
// if (hasOwn(arr, 'length')) {
//   console.log("数组具有 'length' 属性");
// } else {
//   console.log("数组不具有 'length' 属性");
// }
// 输出: 数组具有 'length' 属性
uni_modules/lime-shared/index.ts
对比新文件
@@ -0,0 +1,43 @@
// @ts-nocheck
// validator
// export * from './isString'
// export * from './isNumber'
// export * from './isNumeric'
// export * from './isDef'
// export * from './isFunction'
// export * from './isObject'
// export * from './isPromise'
// export * from './isBase64'
// export * from './hasOwn'
// // 单位转换
// export * from './addUnit'
// export * from './unitConvert'
// export * from './toNumber'
// export * from './random'
// export * from './range'
// export * from './fillZero'
// // image
// export * from './base64ToPath'
// export * from './pathToBase64'
// export * from './exif'
// // canvas
// export * from './canIUseCanvas2d'
// // page
// export * from './getCurrentPage'
// // dom
// export * from './getRect'
// export * from './selectComponent'
// export * from './createAnimation'
// // delay
// export * from './sleep'
// export * from './debounce'
// export * from './throttle'
uni_modules/lime-shared/isBase64/index.ts
对比新文件
@@ -0,0 +1,23 @@
// @ts-nocheck
/**
 * 判断一个字符串是否为Base64编码。
 * Base64编码的字符串只包含A-Z、a-z、0-9、+、/ 和 = 这些字符。
 * @param {string} str - 要检查的字符串。
 * @returns {boolean} 如果字符串是Base64编码,返回true,否则返回false。
 */
export function isBase64(str: string): boolean {
    const base64Regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
    return base64Regex.test(str);
}
/**
 * 判断一个字符串是否为Base64编码的data URI。
 * Base64编码的data URI通常以"data:"开头,后面跟着MIME类型和编码信息,然后是Base64编码的数据。
 * @param {string} str - 要检查的字符串。
 * @returns {boolean} 如果字符串是Base64编码的data URI,返回true,否则返回false。
 */
export function isBase64DataUri(str: string): boolean {
    const dataUriRegex = /^data:([a-zA-Z]+\/[a-zA-Z0-9-+.]+)(;base64)?,([a-zA-Z0-9+/]+={0,2})$/;
    return dataUriRegex.test(str);
}
uni_modules/lime-shared/isBrowser/index.ts
对比新文件
@@ -0,0 +1,8 @@
// @ts-nocheck
// #ifdef WEB
export const isBrowser = typeof window !== 'undefined';
// #endif
// #ifndef WEB
export const isBrowser = false;
// #endif
uni_modules/lime-shared/isDef/index.ts
对比新文件
@@ -0,0 +1,23 @@
// @ts-nocheck
/**
 * 检查一个值是否已定义(不为 undefined)且不为 null
 * @param value 要检查的值
 * @returns 如果值已定义且不为 null,则返回 true;否则返回 false
 */
// #ifndef UNI-APP-X
export function isDef(value: unknown): boolean {
  return value !== undefined && value !== null;
}
// #endif
// #ifdef UNI-APP-X
export function isDef(value : any|null) : boolean {
    // #ifdef UNI-APP-X && APP
    return value != null;
    // #endif
    // #ifndef UNI-APP-X && APP
    return value != null && value != undefined;
    // #endif
}
// #endif
uni_modules/lime-shared/isEmpty/index.ts
对比新文件
@@ -0,0 +1,83 @@
// @ts-nocheck
import {isDef} from '../isDef'
import {isString} from '../isString'
import {isNumber} from '../isNumber'
/**
 * 判断一个值是否为空。
 *
 * 对于字符串,去除首尾空格后判断长度是否为0。
 * 对于数组,判断长度是否为0。
 * 对于对象,判断键的数量是否为0。
 * 对于null或undefined,直接返回true。
 * 其他类型(如数字、布尔值等)默认不为空。
 *
 * @param {any} value - 要检查的值。
 * @returns {boolean} 如果值为空,返回true,否则返回false。
 */
// #ifdef UNI-APP-X && APP
export function isEmpty(value : any | null) : boolean {
    // 为null
    if(!isDef(value)){
        return true
    }
    // 为空字符
    if(isString(value)){
        return value.toString().trim().length == 0
    }
    // 为数值
    if(isNumber(value)){
        return false
    }
    if(typeof value == 'object'){
        // 数组
        if(Array.isArray(value)){
            return (value as Array<unknown>).length == 0
        }
        // Map
        if(value instanceof Map<unknown, unknown>) {
            return value.size == 0
        }
        // Set
        if(value instanceof Set<unknown>) {
            return value.size == 0
        }
        if(value instanceof UTSJSONObject) {
            return value.toMap().size == 0
        }
        return JSON.stringify(value) == '{}'
    }
    return true
}
// #endif
// #ifndef UNI-APP-X && APP
export function isEmpty(value: any): boolean {
    // 检查是否为null或undefined
    if (value == null) {
        return true;
    }
    // 检查字符串是否为空
    if (typeof value === 'string') {
        return value.trim().length === 0;
    }
    // 检查数组是否为空
    if (Array.isArray(value)) {
        return value.length === 0;
    }
    // 检查对象是否为空
    if (typeof value === 'object') {
        return Object.keys(value).length === 0;
    }
    // 其他类型(如数字、布尔值等)不为空
    return false;
}
// #endif
uni_modules/lime-shared/isFunction/index.ts
对比新文件
@@ -0,0 +1,16 @@
// @ts-nocheck
/**
 * 检查一个值是否为函数类型
 * @param val 要检查的值
 * @returns 如果值的类型是函数类型,则返回 true;否则返回 false
 */
// #ifdef UNI-APP-X && APP
export const isFunction = (val: any):boolean => typeof val == 'function';
 // #endif
// #ifndef UNI-APP-X && APP
export const isFunction = (val: unknown): val is Function =>
  typeof val === 'function';
// #endif
uni_modules/lime-shared/isNumber/index.ts
对比新文件
@@ -0,0 +1,26 @@
// @ts-nocheck
/**
 * 检查一个值是否为数字类型
 * @param value 要检查的值,可以是 number 类型或 string 类型的数字
 * @returns 如果值是数字类型且不是 NaN,则返回 true;否则返回 false
 */
// #ifndef UNI-APP-X
export function isNumber(value: number | string | null): boolean {
  return typeof value === 'number' && !isNaN(value);
}
// #endif
// #ifdef UNI-APP-X
export function isNumber(value: any|null): boolean {
    // #ifdef APP-ANDROID
    return ['Byte', 'UByte','Short','UShort','Int','UInt','Long','ULong','Float','Double','number'].includes(typeof value)
    // #endif
    // #ifdef APP-IOS
    return ['Int8', 'UInt8','Int16','UInt16','Int32','UInt32','Int64','UInt64','Int','UInt','Float','Float16','Float32','Float64','Double', 'number'].includes(typeof value)
    // #endif
    // #ifndef UNI-APP-X && APP
    return typeof value === 'number' && !isNaN(value);
    // #endif
}
// #endif
uni_modules/lime-shared/isNumeric/index.ts
对比新文件
@@ -0,0 +1,33 @@
// @ts-nocheck
/**
 * 检查一个值是否为数字类型或表示数字的字符串
 * @param value 要检查的值,可以是 string 类型或 number 类型
 * @returns 如果值是数字类型或表示数字的字符串,则返回 true;否则返回 false
 */
// #ifndef UNI-APP-X && APP
export function isNumeric(value: string | number | undefined | null): boolean {
  return /^(-)?\d+(\.\d+)?$/.test(value);
}
// #endif
// #ifdef UNI-APP-X && APP
import {isNumber} from '../isNumber';
import {isString} from '../isString';
export function isNumeric(value : any|null) : boolean {
    if(value == null) {
        return false
    }
    if(isNumber(value)) {
        return true
    } else if(isString(value)) {
        // const regex = "-?\\d+(\\.\\d+)?".toRegex()
        const regex = new RegExp("^(-)?\\d+(\\.\\d+)?$")
        return  regex.test(value as string) //regex.matches(value as string)
    }
    return false
    // return /^(-)?\d+(\.\d+)?$/.test(value);
}
// #endif
uni_modules/lime-shared/isObject/index.ts
对比新文件
@@ -0,0 +1,19 @@
// @ts-nocheck
/**
 * 检查一个值是否为对象类型
 * @param val 要检查的值
 * @returns 如果值的类型是对象类型,则返回 true;否则返回 false
 */
// #ifndef UNI-APP-X && APP
export const isObject = (val : unknown) : val is Record<any, any> =>
    val !== null && typeof val === 'object';
// #endif
// #ifdef UNI-APP-X && APP
export const isObject = (val : any | null) : boolean =>{
    return val !== null && typeof val === 'object';
}
// #endif
uni_modules/lime-shared/isPromise/index.ts
对比新文件
@@ -0,0 +1,22 @@
// @ts-nocheck
import {isFunction} from '../isFunction'
import {isObject} from '../isObject'
/**
 * 检查一个值是否为 Promise 类型
 * @param val 要检查的值
 * @returns 如果值的类型是 Promise 类型,则返回 true;否则返回 false
 */
// #ifndef APP-ANDROID
export const isPromise = <T = any>(val: unknown): val is Promise<T> => {
  // 使用 isObject 函数判断值是否为对象类型
  // 使用 isFunction 函数判断值是否具有 then 方法和 catch 方法
  return isObject(val) && isFunction(val.then) && isFunction(val.catch);
};
// #endif
// #ifdef APP-ANDROID
export const isPromise = (val: any): boolean => {
  return val instanceof Promise<unknown>
};
// #endif
uni_modules/lime-shared/isString/index.ts
对比新文件
@@ -0,0 +1,19 @@
// @ts-nocheck
/**
 * 检查一个值是否为字符串类型
 * @param str 要检查的值
 * @returns 如果值的类型是字符串类型,则返回 true;否则返回 false
 */
// #ifndef UNI-APP-X && APP
// export const isString = (str: unknown): str is string => typeof str === 'string';
export function isString (str: unknown): str is string {
    return typeof str == 'string'
}
// #endif
// #ifdef UNI-APP-X && APP
export function isString (str: any|null): boolean {
    return typeof str == 'string'
}
// #endif
uni_modules/lime-shared/kebabCase/index.ts
对比新文件
@@ -0,0 +1,24 @@
// @ts-nocheck
// export function toLowercaseSeparator(key: string) {
//   return key.replace(/([A-Z])/g, '-$1').toLowerCase();
// }
/**
 * 将字符串转换为指定连接符的命名约定
 * @param str 要转换的字符串
 * @param separator 指定的连接符,默认为 "-"
 * @returns 转换后的字符串
 */
export function kebabCase(str : string, separator : string = "-") : string {
    return str
        // #ifdef UNI-APP-X && APP
        .replace(/[A-Z]/g, (match : string, _ : number, _ : string) : string => `${separator}${match.toLowerCase()}`) // 将大写字母替换为连接符加小写字母
        // #endif
        // #ifndef UNI-APP-X && APP
        .replace(/[A-Z]/g, (match : string) : string => `${separator}${match.toLowerCase()}`) // 将大写字母替换为连接符加小写字母
        // #endif
        .replace(/[\s_-]+/g, separator) // 将空格、下划线和短横线替换为指定连接符
        .replace(new RegExp(`^${separator}|${separator}$`, "g"), "") // 删除开头和结尾的连接符
        .toLowerCase(); // 将结果转换为全小写
}
uni_modules/lime-shared/package.json
对比新文件
@@ -0,0 +1,86 @@
{
  "id": "lime-shared",
  "displayName": "lime-shared",
  "version": "0.1.8",
  "description": "本人插件的几个公共函数,获取当前页,图片的base64转临时路径,图片的exif信息等",
  "keywords": [
    "lime-shared",
    "exif"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "sdk-js",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "无",
      "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
    ],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y",
        "alipay": "n"
      },
      "client": {
        "Vue": {
          "vue2": "y",
          "vue3": "y"
        },
        "App": {
          "app-vue": "y",
          "app-uvue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "u",
          "Edge": "u",
          "Firefox": "u",
          "Safari": "u"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y",
          "钉钉": "y",
          "快手": "y",
          "飞书": "y",
          "京东": "u"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        }
      }
    }
  }
}
uni_modules/lime-shared/pathToBase64/index.ts
对比新文件
@@ -0,0 +1,9 @@
// @ts-nocheck
// #ifndef UNI-APP-X && APP
export * from './vue.ts'
// #endif
// #ifdef UNI-APP-X && APP
export * from './uvue.uts'
// #endif
uni_modules/lime-shared/pathToBase64/uvue.uts
对比新文件
@@ -0,0 +1,17 @@
// @ts-nocheck
// import { processFile, ProcessFileOptions } from '@/uni_modules/lime-file-utils'
export function pathToBase64(path : string) : Promise<string> {
    console.error('pathToBase64: 当前环境不支持,请使用 【lime-file-utils】')
    // return new Promise((resolve, reject) => {
    //     processFile({
    //         type: 'toDataURL',
    //         path,
    //         success(res : string) {
    //             resolve(res)
    //         },
    //         fail(err: any){
    //             reject(err)
    //         }
    //     } as ProcessFileOptions)
    // })
}
uni_modules/lime-shared/pathToBase64/vue.ts
对比新文件
@@ -0,0 +1,121 @@
// @ts-nocheck
// #ifdef APP-PLUS
import { getLocalFilePath } from '../getLocalFilePath'
// #endif
function isImage(extension : string) {
    const imageExtensions = ["jpg", "jpeg", "png", "gif", "bmp", "svg"];
    return imageExtensions.includes(extension.toLowerCase());
}
// #ifdef H5
function getSVGFromURL(url: string) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.responseType = 'text';
        xhr.onload = function () {
            if (xhr.status === 200) {
                const svg = xhr.responseText;
                resolve(svg);
            } else {
                reject(new Error(xhr.statusText));
            }
        };
        xhr.onerror = function () {
            reject(new Error('Network error'));
        };
        xhr.send();
    });
}
// #endif
/**
 * 路径转base64
 * @param {Object} string
 */
export function pathToBase64(path : string) : Promise<string> {
    if (/^data:/.test(path)) return path
    let extension = path.substring(path.lastIndexOf('.') + 1);
    const isImageFile = isImage(extension)
    let prefix = ''
    if (isImageFile) {
        prefix = 'image/';
        if(extension == 'svg') {
            extension += '+xml'
        }
    } else if (extension === 'pdf') {
        prefix = 'application/pdf';
    } else if (extension === 'txt') {
        prefix = 'text/plain';
    } else {
        // 添加更多文件类型的判断
        // 如果不是图片、PDF、文本等类型,可以设定默认的前缀或采取其他处理
        prefix = 'application/octet-stream';
    }
    return new Promise((resolve, reject) => {
        // #ifdef H5
        if (isImageFile) {
            if(extension == 'svg') {
                getSVGFromURL(path).then(svg => {
                    const base64 = btoa(svg);
                    resolve(`data:image/svg+xml;base64,${base64}`);
                })
            } else {
                let image = new Image();
                image.setAttribute("crossOrigin", 'Anonymous');
                image.onload = function () {
                    let canvas = document.createElement('canvas');
                    canvas.width = this.naturalWidth;
                    canvas.height = this.naturalHeight;
                    canvas.getContext('2d').drawImage(image, 0, 0);
                    let result = canvas.toDataURL(`${prefix}${extension}`)
                    resolve(result);
                    canvas.height = canvas.width = 0
                }
                image.src = path + '?v=' + Math.random()
                image.onerror = (error) => {
                    reject(error);
                };
            }
        } else {
            reject('not image');
        }
        // #endif
        // #ifdef MP
        if (uni.canIUse('getFileSystemManager')) {
            uni.getFileSystemManager().readFile({
                filePath: path,
                encoding: 'base64',
                success: (res) => {
                    resolve(`data:${prefix}${extension};base64,${res.data}`)
                },
                fail: (error) => {
                    console.error({ error, path })
                    reject(error)
                }
            })
        }
        // #endif
        // #ifdef APP-PLUS
        plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), (entry) => {
            entry.file((file : any) => {
                const fileReader = new plus.io.FileReader()
                fileReader.onload = (data) => {
                    resolve(data.target.result)
                }
                fileReader.onerror = (error) => {
                    console.error({ error, path })
                    reject(error)
                }
                fileReader.readAsDataURL(file)
            }, reject)
        }, reject)
        // #endif
    })
}
uni_modules/lime-shared/platform/index.ts
对比新文件
@@ -0,0 +1,34 @@
// @ts-nocheck
export function getPlatform():Uni {
    // #ifdef MP-WEIXIN
    return wx
    // #endif
    // #ifdef MP-BAIDU
    return swan
    // #endif
    // #ifdef MP-ALIPAY
    return my
    // #endif
    // #ifdef MP-JD
    return jd
    // #endif
    // #ifdef MP-QQ
    return qq
    // #endif
    // #ifdef MP-360
    return qh
    // #endif
    // #ifdef MP-KUAISHOU
    return ks
    // #endif
    // #ifdef MP-LARK||MP-TOUTIAO
    return tt
    // #endif
    // #ifdef MP-DINGTALK
    return dd
    // #endif
    // #ifdef QUICKAPP-WEBVIEW || QUICKAPP-WEBVIEW-UNION || QUICKAPP-WEBVIEW-HUAWEI
    return qa
    // #endif
    return uni
}
uni_modules/lime-shared/raf/index.ts
对比新文件
@@ -0,0 +1,10 @@
// @ts-nocheck
// #ifdef UNI-APP-X && APP
export * from './uvue.ts'
// #endif
// #ifndef UNI-APP-X && APP
export * from './vue.ts'
// #endif
uni_modules/lime-shared/raf/uvue.ts
对比新文件
@@ -0,0 +1,48 @@
// @ts-nocheck
// 是否支持被动事件监听
export const supportsPassive = true;
// #ifdef  uniVersion < 4.25
// 请求动画帧
export function raf(fn: TimerCallback): number {
   return setTimeout(fn, 1000 / 60);
}
// 取消动画帧
export function cancelRaf(id: number) {
  clearTimeout(id);
}
// 双倍动画帧
export function doubleRaf(fn: TimerCallback): void {
  raf(():number => raf(fn)); // 在下一帧回调中再次请求动画帧,实现双倍动画帧效果
}
// #endif
// #ifdef  uniVersion >= 4.25
// 请求动画帧
export function raf(fn: UniAnimationFrameCallback): number
export function raf(fn: UniAnimationFrameCallbackWithNoArgument): number
export function raf(fn: any): number {
    if(typeof fn == 'UniAnimationFrameCallback') {
        return requestAnimationFrame(fn as UniAnimationFrameCallback);
    } else {
        return requestAnimationFrame(fn as UniAnimationFrameCallbackWithNoArgument);
    }
}
// 取消动画帧
export function cancelRaf(id: number) {
  cancelAnimationFrame(id);
}
// 双倍动画帧
export function doubleRaf(fn: UniAnimationFrameCallback): void
export function doubleRaf(fn: UniAnimationFrameCallbackWithNoArgument): void
export function doubleRaf(fn: any): void {
  raf(():number => raf(fn)); // 在下一帧回调中再次请求动画帧,实现双倍动画帧效果
}
// #endif
uni_modules/lime-shared/raf/vue.ts
对比新文件
@@ -0,0 +1,32 @@
// @ts-nocheck
type Callback = () => void//Function
// 是否支持被动事件监听
export const supportsPassive = true;
// 请求动画帧
export function raf(fn : Callback) : number {
    // #ifndef WEB
    return setTimeout(fn, 1000 / 60); // 请求动画帧
    // #endif
    // #ifdef WEB
    return requestAnimationFrame(fn); // 请求动画帧
    // #endif
}
// 取消动画帧
export function cancelRaf(id : number) {
    // 如果是在浏览器环境下,使用 cancelAnimationFrame 方法
    // #ifdef WEB
    cancelAnimationFrame(id); // 取消动画帧
    // #endif
    // #ifndef WEB
    clearTimeout(id); // 取消动画帧
    // #endif
}
// 双倍动画帧
export function doubleRaf(fn : Callback) : void {
    raf(() => {
        raf(fn)
    }); // 在下一帧回调中再次请求动画帧,实现双倍动画帧效果
}
uni_modules/lime-shared/random/index.ts
对比新文件
@@ -0,0 +1,24 @@
// @ts-nocheck
/**
 * 生成一个指定范围内的随机数
 * @param min 随机数的最小值
 * @param max 随机数的最大值
 * @param fixed 随机数的小数位数,默认为 0
 * @returns 生成的随机数
 */
export function random(min: number, max: number, fixed: number = 0):number {
  // 将 min 和 max 转换为数字类型
  // min = +min || 0;
  // max = +max || 0;
  // 计算随机数范围内的一个随机数
  const num = Math.random() * (max - min) + min;
  // 如果 fixed 参数为 0,则返回四舍五入的整数随机数;否则保留固定小数位数
  // Number
  return fixed == 0 ? Math.round(num) : parseFloat(num.toFixed(fixed));
}
// 示例
// console.log(random(0, 10)); // 输出:在 0 和 10 之间的一个整数随机数
// console.log(random(0, 1, 2)); // 输出:在 0 和 1 之间的一个保留两位小数的随机数
// console.log(random(1, 100, 3)); // 输出:在 1 和 100 之间的一个保留三位小数的随机数
uni_modules/lime-shared/range/index.ts
对比新文件
@@ -0,0 +1,36 @@
// @ts-nocheck
/**
 * 生成一个数字范围的数组
 * @param start 范围的起始值
 * @param end 范围的结束值
 * @param step 步长,默认为 1
 * @param fromRight 是否从右侧开始生成,默认为 false
 * @returns 生成的数字范围数组
 */
export function range(start : number, end : number, step : number = 1, fromRight : boolean = false) : number[] {
    let index = -1;
    // 计算范围的长度
    let length = Math.max(Math.ceil((end - start) / step), 0);
    // 创建一个长度为 length 的数组
    // #ifdef APP-ANDROID
    const result = Array.fromNative(new IntArray(length.toInt()));
    // #endif
    // #ifndef APP-ANDROID
    const result = new Array(length);
    // #endif
    // 使用循环生成数字范围数组
    let _start = start
    while (length-- > 0) {
        // 根据 fromRight 参数决定从左侧还是右侧开始填充数组
        result[fromRight ? length : ++index] = _start;
        _start += step;
    }
    return result;
}
// 示例
// console.log(range(0, 5)); // 输出: [0, 1, 2, 3, 4]
// console.log(range(1, 10, 2, true)); // 输出: [9, 7, 5, 3, 1]
// console.log(range(5, 0, -1)); // 输出: [5, 4, 3, 2, 1]
uni_modules/lime-shared/readme.md
对比新文件
@@ -0,0 +1,445 @@
# lime-shared 工具库
- 本人插件的几个公共函数
- 按需引入
## 引入
按需引入只会引入相关的方法,不要看着 插件函数列表多 而占空间,只要不引用不会被打包
```js
import {getRect} from '@/uni_modules/lime-shared/getRect'
```
## 目录
+ [getRect](#api_getRect): 获取节点尺寸信息
+ [addUnit](#api_addUnit): 将未带单位的数值添加px,如果有单位则返回原值
+ [unitConvert](#api_unitConvert): 将带有rpx|px的字符转成number,若本身是number则直接返回
+ [canIUseCanvas2d](#api_canIUseCanvas2d): 环境是否支持使用 canvas 2d
+ [getCurrentPage](#api_getCurrentPage): 获取当前页
+ [base64ToPath](#api_base64ToPath): 把base64的图片转成临时路径
+ [pathToBase64](#api_pathToBase64): 把图片的临时路径转成base64
+ [sleep](#api_sleep): async 内部程序等待一定时间后再执行
+ [throttle](#api_throttle): 节流
+ [debounce](#api_debounce): 防抖
+ [random](#api_random): 返回指定范围的随机数
+ [range](#api_range): 生成区间数组
+ [clamp](#api_clamp): 夹在min和max之间的数值
+ [floatAdd](#api_floatAdd): 返回两个浮点数相加的结果
+ [fillZero](#api_fillZero): 补零,如果传入的是个位数则在前面补0
+ [exif](#api_exif): 获取图片exif
+ [selectComponent](#api_selectComponent): 获取页面或当前实例的指定组件
+ [createAnimation](#api_createAnimation): uni.createAnimation
+ [animation](#api_animation): 数值从一个值到另一个值的过渡
+ [camelCase](#api_camelCase): 字符串转换为 camelCase 或 PascalCase 风格的命名约定
+ [kebabCase](#api_kebabCase): 将字符串转换为指定连接符的命名约定
+ [closest](#api_closest): 在给定数组中找到最接近目标数字的元素
+ [isBase64](#api_isBase64): 判断字符串是否为base64
+ [isNumber](#api_isNumber): 检查一个值是否为数字类型
+ [isNumeric](#api_isNumeric): 检查一个值是否为数字类型或表示数字的字符串
+ [isString](#api_isString): 检查一个值是否为字符串类型
+ [composition-api](#api_composition-api): 为兼容vue2
## Utils
### getRect <a id="api_getRect"></a>
- 返回节点尺寸信息
```js
// 组件内需要传入上下文
// 如果是nvue 则需要在节点上加与id或class同名的ref
getRect('#id',{context: this}).then(res => {})
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### addUnit <a id="api_addUnit"></a>
- 将未带单位的数值添加px,如果有单位则返回原值
```js
addUnit(10)
// 10px
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### unitConvert <a id="api_unitConvert"></a>
- 将带有rpx|px的字符转成number,若本身是number则直接返回
```js
unitConvert('10rpx')
// 5 设备不同 返回的值也不同
unitConvert('10px')
// 10
unitConvert(10)
// 10
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### canIUseCanvas2d <a id="api_canIUseCanvas2d"></a>
- 环境是否支持使用 canvas 2d
```js
canIUseCanvas2d()
// 若支持返回 true 否则 false
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### getCurrentPage <a id="api_getCurrentPage"></a>
- 获取当前页
```js
const page = getCurrentPage()
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### base64ToPath <a id="api_base64ToPath"></a>
- 把base64的图片转成临时路径
```js
base64ToPath(`xxxxx`).then(res => {})
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### pathToBase64 <a id="api_pathToBase64"></a>
- 把图片的临时路径转成base64
```js
pathToBase64(`xxxxx/xxx.png`).then(res => {})
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### sleep <a id="api_sleep"></a>
- 睡眠,让 async 内部程序等待一定时间后再执行
```js
async next () => {
    await sleep(300)
    console.log('limeui');
}
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### throttle <a id="api_throttle"></a>
- 节流
```js
throttle((nama) => {console.log(nama)}, 200)('limeui');
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### debounce <a id="api_debounce"></a>
- 防抖
```js
debounce((nama) => {console.log(nama)}, 200)('limeui');
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### random <a id="api_random"></a>
- 返回指定范围的随机数
```js
random(1, 5);
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### range <a id="api_range"></a>
- 生成区间数组
```js
range(0, 5)
// [0,1,2,3,4,5]
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### clamp <a id="api_clamp"></a>
- 夹在min和max之间的数值,如小于min,返回min, 如大于max,返回max,否侧原值返回
```js
clamp(0, 10, -1)
// 0
clamp(0, 10, 11)
// 10
clamp(0, 10, 9)
// 9
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### floatAdd <a id="api_floatAdd"></a>
- 返回两个浮点数相加的结果
```js
floatAdd(0.1, 0.2) // 0.3
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### fillZero <a id="api_fillZero"></a>
- 补零,如果传入的是`个位数`则在前面补0
```js
fillZero(9);
// 09
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### exif <a id="api_exif"></a>
- 获取图片exif
- 支持临时路径、base64
```js
uni.chooseImage({
    count: 1, //最多可以选择的图片张数
    sizeType: "original",
    success: (res) => {
        exif.getData(res.tempFiles[0], function() {
            let tagj = exif.getTag(this, "GPSLongitude");
            let    Orientation = exif.getTag(this, 'Orientation');
            console.log(tagj, Orientation)
        })
    }
})
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | x                 |
### selectComponent <a id="api_selectComponent"></a>
- 获取页面或当前实例的指定组件,会在页面或实例向所有的节点查找(包括子组件或子子组件)
- 仅vue3,vue2没有测试过
```js
// 当前页面
const page = getCurrentPage()
selectComponent('.custom', {context: page}).then(res => {
})
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | x                 |
### createAnimation <a id="api_createAnimation"></a>
- 创建动画,与uni.createAnimation使用方法一致,只为了抹平nvue
```html
<view ref="ball" :animation="animationData"></view>
```
```js
const ball = ref(null)
const animation = createAnimation({
  transformOrigin: "50% 50%",
  duration: 1000,
  timingFunction: "ease",
  delay: 0
})
animation.scale(2,2).rotate(45).step()
// nvue 无导出数据,这样写只为了平台一致,
// nvue 需要把 ref 传入,其它平台不需要
const animationData = animation.export(ball.value)
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### camelCase <a id="api_camelCase"></a>
- 将字符串转换为 camelCase 或 PascalCase 风格的命名约定
```js
camelCase("hello world") // helloWorld
camelCase("hello world", true) // HelloWorld
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### kebabCase <a id="api_kebabCase"></a>
- 将字符串转换为指定连接符的命名约定
```js
kebabCase("helloWorld") // hello-world
kebabCase("hello world_example") // hello-world-example
kebabCase("helloWorld", "_") // hello_world
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### closest <a id="api_closest"></a>
- 在给定数组中找到最接近目标数字的元素
```js
closest([1, 3, 5, 7, 9], 6) // 5
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### isBase64 <a id="api_isBase64"></a>
- 判断字符串是否为base64
```js
isBase64('xxxxx')
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### isNumber <a id="api_isNumber"></a>
-  检查一个值是否为数字类型
```js
isNumber('0') // false
isNumber(0) // true
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### isNumeric <a id="api_isNumeric"></a>
-  检查一个值是否为数字类型或表示数字的字符串
```js
isNumeric('0') // true
isNumeric(0) // true
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
### isString <a id="api_isString"></a>
-  检查一个值是否为数字类型或表示数字的字符串
```js
isString('0') // true
isString(0) // false
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | √                 |
## composition-api <a id="api_composition-api"></a>
- 因本人插件需要兼容vue2/vue3,故增加一个vue文件,代替条件编译
- vue2需要在main.js加上这一段
```js
// vue2
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
```
```js
//使用
import {computed, onMounted, watch, reactive} from '@/uni_modules/lime-shared/vue'
```
##### 兼容性
| uni-app      | uni-app x                      |
|------------|----------------------------------|
| √     | x                 |
uni_modules/lime-shared/selectAllComponent/index.ts
对比新文件
@@ -0,0 +1,8 @@
// @ts-nocheck
// #ifdef UNI-APP-X
export * from './uvue.uts'
// #endif
// #ifndef UNI-APP-X
export * from './vue.ts'
// #endif
uni_modules/lime-shared/selectAllComponent/uvue.uts
对比新文件
@@ -0,0 +1,39 @@
// @ts-nocheck
import { type ComponentPublicInstance } from 'vue';
type SelectOptions = {
    context : ComponentPublicInstance,
    needAll : boolean | null,
}
export function selectAllComponent(selector : string, options : UTSJSONObject) : ComponentPublicInstance[]|null {
    const context = options.get('context')! as ComponentPublicInstance;
    let needAll = options.get('needAll') as  boolean;
    let result:ComponentPublicInstance[] = []
    if(needAll == null) { needAll = true };
    if(context.$children.length > 0) {
        const queue:ComponentPublicInstance[] = [...context.$children];
        while(queue.length > 0) {
            const child = queue.shift();
            const name = child?.$options?.name;
            if(name == selector) {
                result.push(child as ComponentPublicInstance)
            } else {
                const children = child?.$children
                if(children !== null) {
                    queue.push(...children)
                }
            }
            if(result.length > 0 && !needAll) {
                break;
            }
        }
    }
    if(result.length > 0) {
        return result
    }
    return null
}
uni_modules/lime-shared/selectAllComponent/vue.ts
对比新文件
@@ -0,0 +1,151 @@
// @ts-nocheck
interface SelectOptions {
    context?: any
    needAll?: boolean
    node?: boolean
}
// #ifdef MP
function selectMPComponent(key: string, name: string, context: any, needAll: boolean) {
    const {proxy, $vm} = context
    context = $vm || proxy
    if(!['ref','component'].includes(key)) {
        const queue = [context]
        let result = null
        const selector = (key == 'id' ? '#': '.') + name;
        while(queue.length > 0) {
            const child = queue.shift();
            const flag = child?.selectComponent(selector)
            if(flag) {
                if(!needAll) {return result = flag.$vm}
                return result = child.selectAllComponents(selector).map(item => item.$vm)
            } else {
                child.$children && (queue.push(...child.$children));
            }
        }
        return result
    } else {
        const {$templateRefs} = context.$
        const nameMap = {}
        for (var i = 0; i < $templateRefs.length; i++) {
            const item = $templateRefs[i]
            nameMap[item.i] = item.r
        }
        let result = []
        if(context.$children.length) {
            const queue = [...context.$children]
            while(queue.length > 0) {
                const child = queue.shift();
                if(key == 'component' && (child.type?.name === name || child.$?.type?.name === name)) {
                    result.push(child)
                } else if(child.$refs && child.$refs[name]) {
                    result = child.$refs[name]
                } else if(nameMap[child.id] === name){
                    result.push(child)
                }  else {
                    child.$children && (queue.push(...child.$children));
                }
                if(result.length && !needAll) {
                    return;
                }
            }
        }
        return needAll ? result : result[0]
    }
}
// #endif
// #ifdef H5
function selectH5Component(key: string, name: string, context: any, needAll: boolean) {
    const {_, component } = context
    const child = {component: _ || component || context, children: null , subTree: null, props: null}
    let result = []
    let queue = [child]
    while(queue.length > 0 ) {
        const child = queue.shift()
        const {component, children , props, subTree} = child
        if(key === 'component' && component?.type?.name == name) {
            result.push(component)
        } else if(key === 'ref' && component && (props?.ref == name || component[key][name])) {
            if(props?.ref == name) {
                //exposed
                result.push(component)
            } else if(component[key][name]) {
                result.push(component[key][name])
            }
        } else if(key !== 'ref' && component?.exposed && new RegExp(`\\b${name}\\b`).test(component.attrs[key])) {
            // exposed
            result.push(component)
        } else if(children && Array.isArray(children)) {
            queue.push(...children)
        } else if(!component && subTree) {
            queue.push(subTree)
        } else if(component?.subTree) {
            queue.push(component.subTree)
        }
        if(result.length && !needAll) {
            break
        }
    }
    return needAll ? result : result[0]
}
// #endif
// #ifdef APP
function selectAPPComponent(key: string, name: string, context: any, needAll: boolean, node: boolean) {
    let result = []
    // const {_, component} = context
    // const child = {component: _ || component || context, children: null, props: null, subTree: null}
    const queue = [context]
    while(queue.length > 0) {
        const child = queue.shift()
        const {component, children, props, subTree} = child
        const isComp = component && props && component.exposed && !node
        if(key == 'component' && child.type && child.type.name === name) {
            result.push(component)
        } else if(props?.[key] === name && node) {
            result.push(child)
        } else if(key === 'ref' && isComp && (props.ref === name || props.ref_key === name)) {
            // exposed
            result.push(component)
        } else if(key !== 'ref' && isComp && new RegExp(`\\b${name}\\b`).test(props[key])) {
            // exposed
            result.push(component)
        }
        // else if(component && component.subTree && Array.isArray(component.subTree.children)){
        //     queue.push(...component.subTree.children)
        // }
        else if(subTree) {
            queue.push(subTree)
        } else if(component && component.subTree){
            queue.push(component.subTree)
        }
         else if(children && Array.isArray(children)) {
            queue.push(...children)
        }
        if(result.length && !needAll) {
            break;
        }
    }
    return needAll ? result : result[0]
}
// #endif
export function selectAllComponent(selector: string, options: SelectOptions = {}) {
    // . class
    // # id
    // $ ref
    // @ component name
    const reg = /^(\.|#|@|\$)([a-zA-Z_0-9\-]+)$/;
    if(!reg.test(selector)) return null
    let { context, needAll = true, node} = options
    const [,prefix, name] = selector.match(reg)
    const symbolMappings  = {'.': 'class', '#': 'id', '$':'ref', '@':'component'}
    const key = symbolMappings [prefix] //prefix === '.' ? 'class' : prefix === '#' ? 'id' : 'ref';
    // #ifdef MP
    return selectMPComponent(key, name, context, needAll)
    // #endif
    // #ifdef H5
    return selectH5Component(key, name, context, needAll)
    // #endif
    // #ifdef APP
    return selectAPPComponent(key, name, context, needAll, node)
    // #endif
}
uni_modules/lime-shared/selectComponent/index.ts
对比新文件
@@ -0,0 +1,7 @@
// @ts-nocheck
// #ifndef UNI-APP-X
export * from './vue.ts'
// #endif
// #ifdef UNI-APP-X
export * from './uvue.uts'
// #endif
uni_modules/lime-shared/selectComponent/uvue.uts
对比新文件
@@ -0,0 +1,75 @@
// @ts-nocheck
import { type ComponentPublicInstance } from 'vue';
// #ifdef APP
function findChildren(selector: string, context: ComponentPublicInstance, needAll: boolean): ComponentPublicInstance [] | null{
    let result:ComponentPublicInstance[] = []
    if(context !== null && context.$children.length > 0) {
        const queue:ComponentPublicInstance[] = [...context.$children];
        while(queue.length > 0) {
            const child = queue.shift();
            const name = child?.$options?.name;
            if(name == selector) {
                result.push(child as ComponentPublicInstance)
            } else {
                const children = child?.$children
                if(children !== null) {
                    queue.push(...children)
                }
            }
            if(result.length > 0 && !needAll) {
                break;
            }
        }
    }
    if(result.length > 0) {
        return result
    }
    return null
}
class Query {
    context : ComponentPublicInstance | null = null
    selector : string = ''
    // components : ComponentPublicInstance[] = []
    constructor(selector : string, context : ComponentPublicInstance | null) {
        this.selector = selector
        this.context = context
    }
    in(context : ComponentPublicInstance) : Query {
        return new Query(this.selector, context)
    }
    find(): ComponentPublicInstance | null {
        const selector = this.selector
        if(selector == '') return null
        const component = findChildren(selector, this.context!, false)
        return component != null ? component[0]: null
    }
    findAll():ComponentPublicInstance[] | null {
        const selector = this.selector
        if(selector == '') return null
        return findChildren(selector, this.context!, true)
    }
    closest(): ComponentPublicInstance | null {
        const selector = this.selector
        if(selector == '') return null
        let parent = this.context!.$parent
        let name = parent?.$options?.name;
        while (parent != null && (name == null || selector != name)) {
            parent = parent.$parent
            if (parent != null) {
                name = parent.$options.name
            }
        }
        return parent
    }
}
export function selectComponent(selector: string): Query{
    return new Query(selector, null)
}
// #endif
// selectComponent('selector').in(this).find()
// selectComponent('selector').in(this).findAll()
// selectComponent('selector').in(this).closest()
uni_modules/lime-shared/selectComponent/vue.ts
对比新文件
@@ -0,0 +1,149 @@
// @ts-nocheck
// #ifdef MP
function findChildren(selector : string, context : ComponentPublicInstance, needAll : boolean) {
    const { proxy, $vm } = context
    context = $vm || proxy
    if ((selector.startsWith('.') || selector.startsWith('#'))) {
        const queue = [context]
        let result = null
        while (queue.length > 0) {
            const child = queue.shift();
            const flag = child?.selectComponent(selector)
            if (flag) {
                if (!needAll) { return result = flag.$vm }
                return result = child.selectAllComponents(selector).map(item => item.$vm)
            } else {
                child.$children && (queue.push(...child.$children));
            }
        }
        return result
    } else {
        const { $templateRefs } = context.$
        const selectorValue = /#|\.|@|$/.test(selector) ? selector.substring(1) : selector
        const nameMap = {}
        for (var i = 0; i < $templateRefs.length; i++) {
            const item = $templateRefs[i]
            nameMap[item.i] = item.r
        }
        let result = []
        if (context.$children.length) {
            const queue = [...context.$children]
            while (queue.length > 0) {
                const child = queue.shift();
                if (child.type?.name === selectorValue || child.$?.type?.name === selectorValue) {
                    result.push(child)
                } else if (child.$refs && child.$refs[selectorValue]) {
                    result = child.$refs[selectorValue]
                } else if (nameMap[child.id] === selectorValue) {
                    result.push(child)
                } else {
                    child.$children && (queue.push(...child.$children));
                }
                if (result.length && !needAll) {
                    return;
                }
            }
        }
        return needAll ? result : result[0]
    }
}
// #endif
// #ifdef H5
function findChildren(selector : string, context : ComponentPublicInstance, needAll : boolean){
    const {_, component } = context
    const child = {component: _ || component || context, children: null , subTree: null, props: null}
    let result = []
    let queue = [child]
    const selectorValue = /#|\.|@|$/.test(selector) ? selector.substring(1) : selector
    while(queue.length > 0 ) {
        const child = queue.shift()
        const {component, children , props, subTree} = child
        if(component?.type?.name == selectorValue) {
            result.push(component)
        } else if(selector.startsWith('$') && component && (props?.ref == selectorValue || component[key][selectorValue])) {
            if(props?.ref == selectorValue) {
                //exposed
                result.push(component)
            } else if(component[key][selectorValue]) {
                result.push(component[key][selectorValue])
            }
        } else if(!selector.startsWith('$') && component?.exposed && new RegExp(`\\b${selectorValue}\\b`).test(component.attrs[key])) {
            // exposed
            result.push(component)
        } else if(children && Array.isArray(children)) {
            queue.push(...children)
        } else if(!component && subTree) {
            queue.push(subTree)
        } else if(component?.subTree) {
            queue.push(component.subTree)
        }
        if(result.length && !needAll) {
            break
        }
    }
    return needAll ? result : result[0]
}
// #endif
// #ifdef APP
function findChildren(selector : string, context : ComponentPublicInstance, needAll : boolean){
    let result = []
    const selectorValue = /#|\.|@|$/.test(selector) ? selector.substring(1) : selector
    const queue = [context]
    while(queue.length > 0) {
        const child = queue.shift()
        const {component, children, props, subTree} = child
        const isComp = component && props && component.exposed && !node
        if(child.type && child.type.name === selectorValue) {
            result.push(component)
        } else if(props?.[key] === selectorValue && node) {
            result.push(child)
        } else if(selector.startsWith('$') && isComp && (props.ref === selectorValue || props.ref_key === selectorValue)) {
            // exposed
            result.push(component)
        } else if(!selector.startsWith('$') && isComp && new RegExp(`\\b${selectorValue}\\b`).test(props[key])) {
            // exposed
            result.push(component)
        }
        else if(subTree) {
            queue.push(subTree)
        } else if(component && component.subTree){
            queue.push(component.subTree)
        }
         else if(children && Array.isArray(children)) {
            queue.push(...children)
        }
        if(result.length && !needAll) {
            break;
        }
    }
    return needAll ? result : result[0]
}
// #endif
class Query {
    context : ComponentPublicInstance | null = null
    selector : string = ''
    // components : ComponentPublicInstance[] = []
    constructor(selector : string, context : ComponentPublicInstance | null) {
        this.selector = selector
        this.context = context
    }
    in(context : ComponentPublicInstance) : Query {
        return new Query(this.selector, context)
    }
    find() : ComponentPublicInstance | null {
        return findChildren(this.selector, this.context, false)
    }
    findAll() : ComponentPublicInstance[] | null {
        return findChildren(this.selector, this.context, true)
    }
    closest() : ComponentPublicInstance | null {
        return null
    }
}
export function selectComponent(selector: string) {
    return new Query(selector)
}
uni_modules/lime-shared/selectElement/index.uts
对比新文件
@@ -0,0 +1,275 @@
// @ts-nocheck
import {isDef} from '../isDef'
import {ComponentPublicInstance} from 'vue'
type HasSelectorFunc = (selector : string, element : UniElement) => boolean
const hasSelectorClassName : HasSelectorFunc = (selector : string, element : UniElement) : boolean => {
    return element.classList.includes(selector)
}
const hasSelectorId : HasSelectorFunc = (selector : string, element : UniElement) : boolean => {
    return element.getAttribute("id") == selector
}
const hasSelectorTagName : HasSelectorFunc = (selector : string, element : UniElement) : boolean => {
    return element.tagName!.toLowerCase() == selector.toLowerCase()
}
type ProcessSelectorResult = {
    selectorValue : string
    hasSelector : HasSelectorFunc
}
const processSelector = (selector : string) : ProcessSelectorResult => {
    const selectorValue = /#|\./.test(selector) ? selector.substring(1) : selector
    let hasSelector : HasSelectorFunc
    if (selector.startsWith('.')) {
        hasSelector = hasSelectorClassName
    } else if (selector.startsWith('#')) {
        hasSelector = hasSelectorId
    } else {
        hasSelector = hasSelectorTagName
    }
    return {
        selectorValue,
        hasSelector
    } as ProcessSelectorResult
}
function isNotEmptyString(str:string): boolean {
  return str.length > 0;
}
function isElement(element:UniElement|null):boolean {
  return isDef(element) && element?.tagName != 'COMMENT';
}
type ElementArray = Array<UniElement|null>
class Query {
    context : ComponentPublicInstance | null = null
    selector : string = ''
    elements : ElementArray = []
    constructor(selector : string | null, context : ComponentPublicInstance | null) {
        this.context = context
        if(selector != null){
            this.selector = selector
        }
        this.find(this.selector)
    }
    in(context : ComponentPublicInstance) : Query {
        return new Query(this.selector, context)
    }
    findAll(selector : string): Query {
        if (isDef(this.context)) {
            const root = this.context?.$el //as Element | null;
            if (isDef(root)) {
                this.elements = [root!] //as ElementArray
            }
            const { selectorValue, hasSelector } = processSelector(selector)
            const foundElements : ElementArray = [];
            function findChildren(element : UniElement) {
                element.children.forEach((child : UniElement) => {
                    if (hasSelector(selectorValue, child)) {
                        foundElements.push(child)
                    }
                })
            }
            this.elements.forEach(el => {
                findChildren(el!);
            });
            this.elements = foundElements
        } else if (selector.startsWith('#')) {
            const element = uni.getElementById(selector)
            if (isElement(element!)) {
                this.elements = [element]
            }
        }
        return this;
    }
    /**
     * 在当前元素集合中查找匹配的元素
     */
    find(selector : string) : Query {
        if (isDef(this.context)) {
            const root = this.context?.$el //as Element | null;
            if (isElement(root)) {
                this.elements = [root] //as ElementArray
            }
            if(isNotEmptyString(selector) && this.elements.length > 0){
                const { selectorValue, hasSelector } = processSelector(selector)
                const foundElements : ElementArray = [];
                function findChildren(element : UniElement) {
                    element.children.forEach((child : UniElement) => {
                        if (hasSelector(selectorValue, child) && foundElements.length < 1) {
                            foundElements.push(child)
                        }
                        if (foundElements.length < 1) {
                            findChildren(child);
                        }
                    })
                }
                this.elements.forEach(el => {
                    findChildren(el!);
                });
                this.elements = foundElements
            }
        } else if (selector.startsWith('#')) {
            const element = uni.getElementById(selector)
            if (isElement(element!)) {
                this.elements = [element]
            }
        }
        return this;
    }
    /**
     * 获取当前元素集合的直接子元素
     */
    children() : Query {
        // if (this.elements.length > 0) {
            // const children = this.elements.reduce((acc, el) => [...acc, ...Array.from(el.children)], []);
            // this.elements = children;
        // }
        return this;
    }
    /**
     * 获取当前元素集合的父元素
     */
    parent() : Query {
        // if (this.elements.length > 0) {
        //     const parents = this.elements.map(el => el.parentElement).filter(parent => parent !== null) as ElementArray;
        //     this.elements = parents
        //     // this.elements = Array.from(new Set(parents));
        // }
        return this;
    }
    /**
     * 获取当前元素集合的兄弟元素
     */
    siblings() : Query {
        // if (this.elements.length > 0) {
            // const siblings = this.elements.reduce((acc, el) => [...acc, ...Array.from(el.parentElement?.children || [])], []);
            // this.elements = siblings.filter(sibling => sibling !== null && !this.elements?.includes(sibling));
        // }
        return this;
    }
    /**
     * 获取当前元素集合的下一个兄弟元素
     */
    next() : Query {
        // if (this.elements.length > 0) {
        //     const nextElements = this.elements.map(el => el.nextElementSibling).filter(next => next !== null) as ElementArray;
        //     this.elements = nextElements;
        // }
        return this;
    }
    /**
     * 获取当前元素集合的上一个兄弟元素
     */
    prev() : Query {
        // if (this.elements.length > 0) {
        //     const prevElements = this.elements.map(el => el.previousElementSibling).filter(prev => prev !== null) as ElementArray;
        //     this.elements = prevElements;
        // }
        return this;
    }
    /**
     * 从当前元素开始向上查找匹配的元素
     */
    closest(selector : string) : Query {
        if (isDef(this.context)) {
            // && this.context.$parent != null && this.context.$parent.$el !== null
            if(this.elements.length == 0 && isDef(this.context?.$parent) && isElement(this.context!.$parent?.$el)){
                this.elements = [this.context!.$parent?.$el!]
            }
            const selectorsArray = selector.split(',')
            // const { selectorValue, hasSelector } = processSelector(selector)
            const processedSelectors = selectorsArray.map((selector: string):ProcessSelectorResult => processSelector(selector))
            const closestElements = this.elements.map((el) : UniElement | null => {
                let closestElement : UniElement | null = el
                while (closestElement !== null) {
                    // if (hasSelector(selectorValue, closestElement)) {
                    //     break;
                    // }
                    const isMatchingSelector = processedSelectors.some(({selectorValue, hasSelector}):boolean => {
                        return hasSelector(selectorValue, closestElement!)
                    })
                    if(isMatchingSelector){
                        break;
                    }
                    closestElement = closestElement.parentElement;
                }
                return closestElement
            })
            this.elements = closestElements.filter((closest : UniElement | null) : boolean => isDef(closest))// as ElementArray
        }
        return this;
    }
    /**
     * 从当前元素集合中过滤出匹配的元素
     */
    filter() : Query {
        return this;
    }
    /**
     * 从当前元素集合中排除匹配的元素
     */
    not() { }
    /**
     * 从当前元素集合中查找包含匹配元素的元素
     */
    has() { }
    /**
     * 获取当前元素集合的第一个
     */
    first() : Query {
        if (this.elements.length > 0) {
            // this.elements = [this.elements[0]];
        }
        return this;
    }
    /**
     * 最后一个元素
     */
    last() : Query {
        if (this.elements.length > 0) {
            // this.elements = [this.elements[this.elements.length - 1]];
        }
        return this;
    }
    /**
     * 获取当前元素在其兄弟元素中的索引
     */
    index() : number | null {
        // if (this.elements.length > 0 && this.elements.length > 0 && this.elements[0].parentElement !== null) {
        //     return Array.from(this.elements[0].parentElement.children).indexOf(this.elements[0]);
        // }
        return null;
    }
    get(index : number) : UniElement | null {
        if (this.elements.length > index) {
            return this.elements[index] //as Element
        }
        return null
    }
}
export function selectElement(selector : string | null = null) : Query {
    // if(typeof selector == 'string' || selector == null){
    //     return new Query(selector as string | null, null)
    // }
    // else if(selector instanceof  ComponentPublicInstance){
    //     return new Query(null, selector)
    // }
    return new Query(selector, null)
}
// $('xxx').in(this).find('xxx')
// $('xxx').in(this).get()
uni_modules/lime-shared/sleep/index.ts
对比新文件
@@ -0,0 +1,44 @@
// @ts-nocheck
/**
 * 延迟指定时间后解析的 Promise
 * @param delay 延迟的时间(以毫秒为单位),默认为 300 毫秒
 * @returns 一个 Promise,在延迟结束后解析
 */
// #ifdef UNI-APP-X && APP
function sleep(delay: number = 300):Promise<boolean> {
    return new Promise((resolve):void => {setTimeout(() => {resolve(true)}, delay)});
}
export {
    sleep
}
// #endif
// #ifndef UNI-APP-X && APP
export const sleep = (delay: number = 300) =>
  new Promise(resolve => setTimeout(resolve, delay));
// #endif
// 示例
// async function example() {
//   console.log("Start");
//   // 延迟 1 秒后执行
//   await sleep(1000);
//   console.log("1 second later");
//   // 延迟 500 毫秒后执行
//   await sleep(500);
//   console.log("500 milliseconds later");
//   // 延迟 2 秒后执行
//   await sleep(2000);
//   console.log("2 seconds later");
//   console.log("End");
// }
// example();
uni_modules/lime-shared/throttle/index.ts
对比新文件
@@ -0,0 +1,77 @@
// @ts-nocheck
/**
 * 节流函数,用于限制函数的调用频率
 * @param fn 要进行节流的函数
 * @param delay 两次调用之间的最小间隔时间
 * @returns 节流后的函数
 */
// #ifndef UNI-APP-X && APP
export function throttle(fn: (...args: any[]) => void, delay: number) {
  let flag = true; // 标记是否可以执行函数
  return (...args: any[]) => {
    if (flag) {
      flag = false; // 设置为不可执行状态
      fn(...args); // 执行传入的函数
      setTimeout(() => {
        flag = true; // 经过指定时间后,设置为可执行状态
      }, delay);
    }
  };
}
// #endif
// #ifdef UNI-APP-X && APP
// type Rfun = (...args: any[]) => void
// type Rfun = (...args: any[]) => void
export function throttle<T extends any|null>(
    fn: (args : T) => void,
    delay: number):(args : T) => void {
    let flag = true; // 标记是否可以执行函数
    return (args : T) =>{
        if(flag){
            flag = false;
            fn(args);
            setTimeout(()=>{
                flag = true;
            }, delay)
        }
    }
  // return (...args: any[]) => {
  //   // if (flag) {
  //   //   flag = false; // 设置为不可执行状态
  //   //   fn(...args); // 执行传入的函数
  //   //   setTimeout(() => {
  //   //     flag = true; // 经过指定时间后,设置为可执行状态
  //   //   }, delay);
  //   // }
  // };
}
// #endif
// // 示例
// // 定义一个被节流的函数
// function handleScroll() {
//   console.log("Scroll event handled!");
// }
// // 使用节流函数对 handleScroll 进行节流,间隔时间为 500 毫秒
// const throttledScroll = throttle(handleScroll, 500);
// // 模拟多次调用 handleScroll
// throttledScroll(); // 输出 "Scroll event handled!"
// throttledScroll(); // 不会输出
// throttledScroll(); // 不会输出
// // 经过 500 毫秒后,再次调用 handleScroll
// setTimeout(() => {
//   throttledScroll(); // 输出 "Scroll event handled!"
// }, 500);
uni_modules/lime-shared/toArray/index.ts
对比新文件
@@ -0,0 +1,21 @@
// @ts-nocheck
/**
 * 将一个或多个元素转换为数组
 * @param item 要转换为数组的元素
 * @returns 转换后的数组
 */
// #ifndef UNI-APP-X && APP
export const toArray = <T>(item: T | T[]): T[] => Array.isArray(item) ? item : [item];
// #endif
// #ifdef UNI-APP-X && APP
export function toArray<T extends any>(item: any): T[] {
    return Array.isArray(item) ? item as T[] : [item as T]// as T[]
};
// #endif
// 示例
// console.log(toArray(5)); // 输出: [5]
// console.log(toArray("hello")); // 输出: ["hello"]
// console.log(toArray([1, 2, 3])); // 输出: [1, 2, 3]
// console.log(toArray(["apple", "banana"])); // 输出: ["apple", "banana"]
uni_modules/lime-shared/toBoolean/index.ts
对比新文件
@@ -0,0 +1,40 @@
// @ts-nocheck
import { isNumber } from '../isNumber'
import { isString } from '../isString'
// 函数重载,定义多个函数签名
// function toBoolean(value : any) : boolean;
// function toBoolean(value : string) : boolean;
// function toBoolean(value : number) : boolean;
// function toBoolean(value : boolean) : boolean;
// #ifdef UNI-APP-X && APP
function toBoolean(value : any | null) : boolean {
    // 根据输入值的类型,返回相应的布尔值
    // if (isNumber(value)) {
    //     return (value as number) != 0;
    // }
    // if (isString(value)) {
    //     return `${value}`.length > 0;
    // }
    // if (typeof value == 'boolean') {
    //     return value as boolean;
    // }
    // #ifdef APP-IOS
    return value != null && value != undefined
    // #endif
    // #ifdef APP-ANDROID
    return value != null
    // #endif
}
// #endif
// #ifndef UNI-APP-X && APP
function toBoolean(value : any | null) : value is NonNullable<typeof value> {
    return !!value//value !== null && value !== undefined;
}
// #endif
export {
    toBoolean
}
uni_modules/lime-shared/toNumber/index.ts
对比新文件
@@ -0,0 +1,28 @@
// @ts-nocheck
/**
 * 将字符串转换为数字
 * @param val 要转换的字符串
 * @returns 转换后的数字或原始字符串
 */
// #ifdef UNI-APP-X && APP
// function toNumber(val: string): number
// function toNumber(val: string): string
function toNumber(val: string): number|null {
  const n = parseFloat(val); // 使用 parseFloat 函数将字符串转换为浮点数
  return isNaN(n) ? null : n; // 使用 isNaN 函数判断是否为非数字,返回转换后的数字或原始字符串
}
export {toNumber}
// #endif
// #ifndef UNI-APP-X && APP
export function toNumber(val: string): number | string {
  const n = parseFloat(val); // 使用 parseFloat 函数将字符串转换为浮点数
  return isNaN(n) ? val : n; // 使用 isNaN 函数判断是否为非数字,返回转换后的数字或原始字符串
}
// #endif
// 示例
// console.log(toNumber("123")); // 输出: 123
// console.log(toNumber("3.14")); // 输出: 3.14
// console.log(toNumber("hello")); // 输出: "hello"
uni_modules/lime-shared/unitConvert/index.ts
对比新文件
@@ -0,0 +1,79 @@
// @ts-nocheck
import { isString } from '../isString'
import { isNumeric } from '../isNumeric'
/**
 * 单位转换函数,将字符串数字或带有单位的字符串转换为数字
 * @param value 要转换的值,可以是字符串数字或带有单位的字符串
 * @returns 转换后的数字,如果无法转换则返回0
 */
// #ifndef UNI-APP-X && APP
export function unitConvert(value : string | number, base: number = 0) : number {
    // 如果是字符串数字
    if (isNumeric(value)) {
        return Number(value);
    }
    // 如果有单位
    if (isString(value)) {
        const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g;
        const results = reg.exec(value);
        if (!value || !results) {
            return 0;
        }
        const unit = results[3];
        const _value = parseFloat(value);
        if (unit === 'rpx') {
            return uni.upx2px(_value);
        }
        if (unit === 'px') {
            return _value * 1;
        }
        if(unit == '%') {
            return _value / 100 * base
        }
        // 如果是其他单位,可以继续添加对应的转换逻辑
    }
    return 0;
}
// #endif
// #ifdef UNI-APP-X && APP
import { isNumber } from '../isNumber'
export function unitConvert(value : any | null, base: number = 0) : number {
    if (isNumber(value)) {
        return value as number
    }
    // 如果是字符串数字
    if (isNumeric(value)) {
        return parseFloat(value as string);
    }
    // 如果有单位
    if (isString(value)) {
        const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g;
        const results = reg.exec(value as string);
        if (results == null) {
            return 0;
        }
        const unit = results[3];
        const _value = parseFloat(value);
        if (unit == 'rpx') {
            const { windowWidth } = uni.getWindowInfo()
            return windowWidth / 750 * _value;
        }
        if (unit == 'px') {
            return _value;
        }
        if(unit == '%') {
            return _value / 100 * base
        }
        // 如果是其他单位,可以继续添加对应的转换逻辑
    }
    return 0;
}
// #endif
// 示例
// console.log(unitConvert("123")); // 输出: 123 (字符串数字转换为数字)
// console.log(unitConvert("3.14em")); // 输出: 0 (无法识别的单位)
// console.log(unitConvert("20rpx")); // 输出: 根据具体情况而定 (根据单位进行转换)
// console.log(unitConvert(10)); // 输出: 10 (数字不需要转换)
uni_modules/lime-shared/vue/index.ts
对比新文件
@@ -0,0 +1,16 @@
// @ts-nocheck
// #ifdef VUE3
export * from 'vue';
// #endif
// #ifndef VUE3
export * from '@vue/composition-api';
// #ifdef APP-NVUE
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
// #endif
// #endif
uni_modules/uni-badge/changelog.md
对比新文件
@@ -0,0 +1,33 @@
## 1.2.2(2023-01-28)
- 修复 运行/打包 控制台警告问题
## 1.2.1(2022-09-05)
- 修复 当 text 超过 max-num 时,badge 的宽度计算是根据 text 的长度计算,更改为 css 计算实际展示宽度,详见:[https://ask.dcloud.net.cn/question/150473](https://ask.dcloud.net.cn/question/150473)
## 1.2.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-badge](https://uniapp.dcloud.io/component/uniui/uni-badge)
## 1.1.7(2021-11-08)
- 优化 升级ui
- 修改 size 属性默认值调整为 small
- 修改 type 属性,默认值调整为 error,info 替换 default
## 1.1.6(2021-09-22)
- 修复 在字节小程序上样式不生效的 bug
## 1.1.5(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.4(2021-07-29)
- 修复 去掉 nvue 不支持css 的 align-self 属性,nvue 下不暂支持 absolute 属性
## 1.1.3(2021-06-24)
- 优化 示例项目
## 1.1.1(2021-05-12)
- 新增 组件示例地址
## 1.1.0(2021-05-12)
- 新增 uni-badge 的 absolute 属性,支持定位
- 新增 uni-badge 的 offset 属性,支持定位偏移
- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点
- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+
- 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式
## 1.0.7(2021-05-07)
- 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug
- 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug
- 新增 uni-badge 属性 custom-style, 支持自定义样式
## 1.0.6(2021-02-04)
- 调整为uni_modules目录规范
uni_modules/uni-badge/components/uni-badge/uni-badge.vue
对比新文件
@@ -0,0 +1,268 @@
<template>
    <view class="uni-badge--x">
        <slot />
        <text v-if="text" :class="classNames" :style="[positionStyle, customStyle, dotStyle]"
            class="uni-badge" @click="onClick()">{{displayValue}}</text>
    </view>
</template>
<script>
    /**
     * Badge 数字角标
     * @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景
     * @tutorial https://ext.dcloud.net.cn/plugin?id=21
     * @property {String} text 角标内容
     * @property {String} size = [normal|small] 角标内容
     * @property {String} type = [info|primary|success|warning|error] 颜色类型
     *     @value info 灰色
     *     @value primary 蓝色
     *     @value success 绿色
     *     @value warning 黄色
     *     @value error 红色
     * @property {String} inverted = [true|false] 是否无需背景颜色
     * @property {Number} maxNum 展示封顶的数字值,超过 99 显示 99+
     * @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上
     *     @value rightTop 右上
     *     @value rightBottom 右下
     *     @value leftTop 左上
     *     @value leftBottom 左下
     * @property {Array[number]} offset    距定位角中心点的偏移量,只有存在 absolute 属性时有效,例如:[-10, -10] 表示向外偏移 10px,[10, 10] 表示向 absolute 指定的内偏移 10px
     * @property {String} isDot = [true|false] 是否显示为一个小点
     * @event {Function} click 点击 Badge 触发事件
     * @example <uni-badge text="1"></uni-badge>
     */
    export default {
        name: 'UniBadge',
        emits: ['click'],
        props: {
            type: {
                type: String,
                default: 'error'
            },
            inverted: {
                type: Boolean,
                default: false
            },
            isDot: {
                type: Boolean,
                default: false
            },
            maxNum: {
                type: Number,
                default: 99
            },
            absolute: {
                type: String,
                default: ''
            },
            offset: {
                type: Array,
                default () {
                    return [0, 0]
                }
            },
            text: {
                type: [String, Number],
                default: ''
            },
            size: {
                type: String,
                default: 'small'
            },
            customStyle: {
                type: Object,
                default () {
                    return {}
                }
            }
        },
        data() {
            return {};
        },
        computed: {
            width() {
                return String(this.text).length * 8 + 12
            },
            classNames() {
                const {
                    inverted,
                    type,
                    size,
                    absolute
                } = this
                return [
                    inverted ? 'uni-badge--' + type + '-inverted' : '',
                    'uni-badge--' + type,
                    'uni-badge--' + size,
                    absolute ? 'uni-badge--absolute' : ''
                ].join(' ')
            },
            positionStyle() {
                if (!this.absolute) return {}
                let w = this.width / 2,
                    h = 10
                if (this.isDot) {
                    w = 5
                    h = 5
                }
                const x = `${- w  + this.offset[0]}px`
                const y = `${- h + this.offset[1]}px`
                const whiteList = {
                    rightTop: {
                        right: x,
                        top: y
                    },
                    rightBottom: {
                        right: x,
                        bottom: y
                    },
                    leftBottom: {
                        left: x,
                        bottom: y
                    },
                    leftTop: {
                        left: x,
                        top: y
                    }
                }
                const match = whiteList[this.absolute]
                return match ? match : whiteList['rightTop']
            },
            dotStyle() {
                if (!this.isDot) return {}
                return {
                    width: '10px',
                    minWidth: '0',
                    height: '10px',
                    padding: '0',
                    borderRadius: '10px'
                }
            },
            displayValue() {
                const {
                    isDot,
                    text,
                    maxNum
                } = this
                return isDot ? '' : (Number(text) > maxNum ? `${maxNum}+` : text)
            }
        },
        methods: {
            onClick() {
                this.$emit('click');
            }
        }
    };
</script>
<style lang="scss" >
    $uni-primary: #2979ff !default;
    $uni-success: #4cd964 !default;
    $uni-warning: #f0ad4e !default;
    $uni-error: #dd524d !default;
    $uni-info: #909399 !default;
    $bage-size: 12px;
    $bage-small: scale(0.8);
    .uni-badge--x {
        /* #ifdef APP-NVUE */
        // align-self: flex-start;
        /* #endif */
        /* #ifndef APP-NVUE */
        display: inline-block;
        /* #endif */
        position: relative;
    }
    .uni-badge--absolute {
        position: absolute;
    }
    .uni-badge--small {
        transform: $bage-small;
        transform-origin: center center;
    }
    .uni-badge {
        /* #ifndef APP-NVUE */
        display: flex;
        overflow: hidden;
        box-sizing: border-box;
        font-feature-settings: "tnum";
        min-width: 20px;
        /* #endif */
        justify-content: center;
        flex-direction: row;
        height: 20px;
        padding: 0 4px;
        line-height: 18px;
        color: #fff;
        border-radius: 100px;
        background-color: $uni-info;
        background-color: transparent;
        border: 1px solid #fff;
        text-align: center;
        font-family: 'Helvetica Neue', Helvetica, sans-serif;
        font-size: $bage-size;
        /* #ifdef H5 */
        z-index: 999;
        cursor: pointer;
        /* #endif */
        &--info {
            color: #fff;
            background-color: $uni-info;
        }
        &--primary {
            background-color: $uni-primary;
        }
        &--success {
            background-color: $uni-success;
        }
        &--warning {
            background-color: $uni-warning;
        }
        &--error {
            background-color: $uni-error;
        }
        &--inverted {
            padding: 0 5px 0 0;
            color: $uni-info;
        }
        &--info-inverted {
            color: $uni-info;
            background-color: transparent;
        }
        &--primary-inverted {
            color: $uni-primary;
            background-color: transparent;
        }
        &--success-inverted {
            color: $uni-success;
            background-color: transparent;
        }
        &--warning-inverted {
            color: $uni-warning;
            background-color: transparent;
        }
        &--error-inverted {
            color: $uni-error;
            background-color: transparent;
        }
    }
</style>
uni_modules/uni-badge/package.json
对比新文件
@@ -0,0 +1,85 @@
{
  "id": "uni-badge",
  "displayName": "uni-badge 数字角标",
  "version": "1.2.2",
  "description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。",
  "keywords": [
    "",
    "badge",
    "uni-ui",
    "uniui",
    "数字角标",
    "徽章"
],
  "repository": "https://github.com/dcloudio/uni-ui",
  "engines": {
    "HBuilderX": ""
  },
  "directories": {
    "example": "../../temps/example_temps"
  },
"dcloudext": {
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "无",
      "permissions": "无"
    },
    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
    "type": "component-vue"
  },
  "uni_modules": {
    "dependencies": ["uni-scss"],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y"
      },
      "client": {
        "App": {
          "app-vue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y"
        },
        "快应用": {
          "华为": "y",
          "联盟": "y"
        },
        "Vue": {
            "vue2": "y",
            "vue3": "y"
        }
      }
    }
  }
}
uni_modules/uni-badge/readme.md
对比新文件
@@ -0,0 +1,10 @@
## Badge 数字角标
> **组件名:uni-badge**
> 代码块: `uBadge`
数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景,
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-badge)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
uni_modules/uni-calendar/changelog.md
对比新文件
@@ -0,0 +1,30 @@
## 1.4.12(2024-09-21)
- 修复 calendar在选择日期范围后重新选择日期需要点两次的Bug
## 1.4.11(2024-01-10)
- 修复 回到今天时,月份显示不一致问题
## 1.4.10(2023-04-10)
- 修复 某些情况 monthSwitch 未触发的Bug
## 1.4.9(2023-02-02)
- 修复 某些情况切换月份错误的Bug
## 1.4.8(2023-01-30)
- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/161964)
## 1.4.7(2022-09-16)
- 优化 支持使用 uni-scss 控制主题色
## 1.4.6(2022-09-08)
- 修复 表头年月切换,导致改变当前日期为选择月1号,且未触发change事件的Bug
## 1.4.5(2022-02-25)
- 修复 条件编译 nvue 不支持的 css 样式的Bug
## 1.4.4(2022-02-25)
- 修复 条件编译 nvue 不支持的 css 样式的Bug
## 1.4.3(2021-09-22)
- 修复 startDate、 endDate 属性失效的Bug
## 1.4.2(2021-08-24)
- 新增 支持国际化
## 1.4.1(2021-08-05)
- 修复 弹出层被 tabbar 遮盖的Bug
## 1.4.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.3.16(2021-05-12)
- 新增 组件示例地址
## 1.3.15(2021-02-04)
- 调整为uni_modules目录规范
uni_modules/uni-calendar/components/uni-calendar/calendar.js
对比新文件
@@ -0,0 +1,544 @@
/**
* @1900-2100区间内的公历、农历互转
* @charset UTF-8
* @github  https://github.com/jjonline/calendar.js
* @Author  Jea杨(JJonline@JJonline.Cn)
* @Time    2014-7-21
* @Time    2016-8-13 Fixed 2033hex、Attribution Annals
* @Time    2016-9-25 Fixed lunar LeapMonth Param Bug
* @Time    2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
* @Version 1.0.3
* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
*/
/* eslint-disable */
var calendar = {
  /**
      * 农历1900-2100的润大小信息表
      * @Array Of Property
      * @return Hex
      */
  lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
    0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
    0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
    0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
    0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
    0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
    0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
    0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
    0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
    0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
    0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
    0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
    0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
    0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
    0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
    /** Add By JJonline@JJonline.Cn**/
    0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
    0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
    0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
    0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
    0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
    0x0d520], // 2100
  /**
      * 公历每个月份的天数普通表
      * @Array Of Property
      * @return Number
      */
  solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
  /**
      * 天干地支之天干速查表
      * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
      * @return Cn string
      */
  Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
  /**
      * 天干地支之地支速查表
      * @Array Of Property
      * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
      * @return Cn string
      */
  Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],
  /**
      * 天干地支之地支速查表<=>生肖
      * @Array Of Property
      * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
      * @return Cn string
      */
  Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],
  /**
      * 24节气速查表
      * @Array Of Property
      * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
      * @return Cn string
      */
  solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],
  /**
      * 1900-2100各年的24节气日期速查表
      * @Array Of Property
      * @return 0x string For splice
      */
  sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
    '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
    '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
    '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
    'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
    '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
    '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
    '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
    '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
    '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
    '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
    '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
    '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
    '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
    '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
    '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
    '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
    '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
    '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
    '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
    '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
    '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
    '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
    '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
    '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
    '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
    '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
    '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
    '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
    '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
    '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
    '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
    '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
    '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
    '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
    '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
    '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
    '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
    '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
    '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
    '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
    '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
    '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
    '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
    '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
    '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
    '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
    '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
    '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
    '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
    '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
    '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
    '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
    '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
    '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
    '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
    '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],
  /**
      * 数字转中文速查表
      * @Array Of Property
      * @trans ['日','一','二','三','四','五','六','七','八','九','十']
      * @return Cn string
      */
  nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],
  /**
      * 日期转农历称呼速查表
      * @Array Of Property
      * @trans ['初','十','廿','卅']
      * @return Cn string
      */
  nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
  /**
      * 月份转农历称呼速查表
      * @Array Of Property
      * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
      * @return Cn string
      */
  nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],
  /**
      * 返回农历y年一整年的总天数
      * @param lunar Year
      * @return Number
      * @eg:var count = calendar.lYearDays(1987) ;//count=387
      */
  lYearDays: function (y) {
    var i; var sum = 348
    for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
    return (sum + this.leapDays(y))
  },
  /**
      * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
      * @param lunar Year
      * @return Number (0-12)
      * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
      */
  leapMonth: function (y) { // 闰字编码 \u95f0
    return (this.lunarInfo[y - 1900] & 0xf)
  },
  /**
      * 返回农历y年闰月的天数 若该年没有闰月则返回0
      * @param lunar Year
      * @return Number (0、29、30)
      * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
      */
  leapDays: function (y) {
    if (this.leapMonth(y)) {
      return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
    }
    return (0)
  },
  /**
      * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
      * @param lunar Year
      * @return Number (-1、29、30)
      * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
      */
  monthDays: function (y, m) {
    if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1
    return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
  },
  /**
      * 返回公历(!)y年m月的天数
      * @param solar Year
      * @return Number (-1、28、29、30、31)
      * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
      */
  solarDays: function (y, m) {
    if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
    var ms = m - 1
    if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
      return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
    } else {
      return (this.solarMonth[ms])
    }
  },
  /**
     * 农历年份转换为干支纪年
     * @param  lYear 农历年的年份数
     * @return Cn string
     */
  toGanZhiYear: function (lYear) {
    var ganKey = (lYear - 3) % 10
    var zhiKey = (lYear - 3) % 12
    if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
    if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
    return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
  },
  /**
     * 公历月、日判断所属星座
     * @param  cMonth [description]
     * @param  cDay [description]
     * @return Cn string
     */
  toAstro: function (cMonth, cDay) {
    var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
    var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
    return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
  },
  /**
      * 传入offset偏移量返回干支
      * @param offset 相对甲子的偏移量
      * @return Cn string
      */
  toGanZhi: function (offset) {
    return this.Gan[offset % 10] + this.Zhi[offset % 12]
  },
  /**
      * 传入公历(!)y年获得该年第n个节气的公历日期
      * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
      * @return day Number
      * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
      */
  getTerm: function (y, n) {
    if (y < 1900 || y > 2100) { return -1 }
    if (n < 1 || n > 24) { return -1 }
    var _table = this.sTermInfo[y - 1900]
    var _info = [
      parseInt('0x' + _table.substr(0, 5)).toString(),
      parseInt('0x' + _table.substr(5, 5)).toString(),
      parseInt('0x' + _table.substr(10, 5)).toString(),
      parseInt('0x' + _table.substr(15, 5)).toString(),
      parseInt('0x' + _table.substr(20, 5)).toString(),
      parseInt('0x' + _table.substr(25, 5)).toString()
    ]
    var _calday = [
      _info[0].substr(0, 1),
      _info[0].substr(1, 2),
      _info[0].substr(3, 1),
      _info[0].substr(4, 2),
      _info[1].substr(0, 1),
      _info[1].substr(1, 2),
      _info[1].substr(3, 1),
      _info[1].substr(4, 2),
      _info[2].substr(0, 1),
      _info[2].substr(1, 2),
      _info[2].substr(3, 1),
      _info[2].substr(4, 2),
      _info[3].substr(0, 1),
      _info[3].substr(1, 2),
      _info[3].substr(3, 1),
      _info[3].substr(4, 2),
      _info[4].substr(0, 1),
      _info[4].substr(1, 2),
      _info[4].substr(3, 1),
      _info[4].substr(4, 2),
      _info[5].substr(0, 1),
      _info[5].substr(1, 2),
      _info[5].substr(3, 1),
      _info[5].substr(4, 2)
    ]
    return parseInt(_calday[n - 1])
  },
  /**
      * 传入农历数字月份返回汉语通俗表示法
      * @param lunar month
      * @return Cn string
      * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
      */
  toChinaMonth: function (m) { // 月 => \u6708
    if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
    var s = this.nStr3[m - 1]
    s += '\u6708'// 加上月字
    return s
  },
  /**
      * 传入农历日期数字返回汉字表示法
      * @param lunar day
      * @return Cn string
      * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
      */
  toChinaDay: function (d) { // 日 => \u65e5
    var s
    switch (d) {
      case 10:
        s = '\u521d\u5341'; break
      case 20:
        s = '\u4e8c\u5341'; break
      case 30:
        s = '\u4e09\u5341'; break
      default :
        s = this.nStr2[Math.floor(d / 10)]
        s += this.nStr1[d % 10]
    }
    return (s)
  },
  /**
      * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
      * @param y year
      * @return Cn string
      * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
      */
  getAnimal: function (y) {
    return this.Animals[(y - 4) % 12]
  },
  /**
      * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
      * @param y  solar year
      * @param m  solar month
      * @param d  solar day
      * @return JSON object
      * @eg:console.log(calendar.solar2lunar(1987,11,01));
      */
  solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
    // 年份限定、上限
    if (y < 1900 || y > 2100) {
      return -1// undefined转换为数字变为NaN
    }
    // 公历传参最下限
    if (y == 1900 && m == 1 && d < 31) {
      return -1
    }
    // 未传参  获得当天
    if (!y) {
      var objDate = new Date()
    } else {
      var objDate = new Date(y, parseInt(m) - 1, d)
    }
    var i; var leap = 0; var temp = 0
    // 修正ymd参数
    var y = objDate.getFullYear()
    var m = objDate.getMonth() + 1
    var d = objDate.getDate()
    var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
    for (i = 1900; i < 2101 && offset > 0; i++) {
      temp = this.lYearDays(i)
      offset -= temp
    }
    if (offset < 0) {
      offset += temp; i--
    }
    // 是否今天
    var isTodayObj = new Date()
    var isToday = false
    if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
      isToday = true
    }
    // 星期几
    var nWeek = objDate.getDay()
    var cWeek = this.nStr1[nWeek]
    // 数字表示周几顺应天朝周一开始的惯例
    if (nWeek == 0) {
      nWeek = 7
    }
    // 农历年
    var year = i
    var leap = this.leapMonth(i) // 闰哪个月
    var isLeap = false
    // 效验闰月
    for (i = 1; i < 13 && offset > 0; i++) {
      // 闰月
      if (leap > 0 && i == (leap + 1) && isLeap == false) {
        --i
        isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
      } else {
        temp = this.monthDays(year, i)// 计算农历普通月天数
      }
      // 解除闰月
      if (isLeap == true && i == (leap + 1)) { isLeap = false }
      offset -= temp
    }
    // 闰月导致数组下标重叠取反
    if (offset == 0 && leap > 0 && i == leap + 1) {
      if (isLeap) {
        isLeap = false
      } else {
        isLeap = true; --i
      }
    }
    if (offset < 0) {
      offset += temp; --i
    }
    // 农历月
    var month = i
    // 农历日
    var day = offset + 1
    // 天干地支处理
    var sm = m - 1
    var gzY = this.toGanZhiYear(year)
    // 当月的两个节气
    // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
    var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
    var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始
    // 依据12节气修正干支月
    var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
    if (d >= firstNode) {
      gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
    }
    // 传入的日期的节气与否
    var isTerm = false
    var Term = null
    if (firstNode == d) {
      isTerm = true
      Term = this.solarTerm[m * 2 - 2]
    }
    if (secondNode == d) {
      isTerm = true
      Term = this.solarTerm[m * 2 - 1]
    }
    // 日柱 当月一日与 1900/1/1 相差天数
    var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
    var gzD = this.toGanZhi(dayCyclical + d - 1)
    // 该日期所属的星座
    var astro = this.toAstro(m, d)
    return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
  },
  /**
      * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
      * @param y  lunar year
      * @param m  lunar month
      * @param d  lunar day
      * @param isLeapMonth  lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
      * @return JSON object
      * @eg:console.log(calendar.lunar2solar(1987,9,10));
      */
  lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
    var isLeapMonth = !!isLeapMonth
    var leapOffset = 0
    var leapMonth = this.leapMonth(y)
    var leapDay = this.leapDays(y)
    if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
    if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
    var day = this.monthDays(y, m)
    var _day = day
    // bugFix 2016-9-25
    // if month is leap, _day use leapDays method
    if (isLeapMonth) {
      _day = this.leapDays(y, m)
    }
    if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验
    // 计算农历的时间差
    var offset = 0
    for (var i = 1900; i < y; i++) {
      offset += this.lYearDays(i)
    }
    var leap = 0; var isAdd = false
    for (var i = 1; i < m; i++) {
      leap = this.leapMonth(y)
      if (!isAdd) { // 处理闰月
        if (leap <= i && leap > 0) {
          offset += this.leapDays(y); isAdd = true
        }
      }
      offset += this.monthDays(y, i)
    }
    // 转换闰月农历 需补充该年闰月的前一个月的时差
    if (isLeapMonth) { offset += day }
    // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
    var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
    var calObj = new Date((offset + d - 31) * 86400000 + stmap)
    var cY = calObj.getUTCFullYear()
    var cM = calObj.getUTCMonth() + 1
    var cD = calObj.getUTCDate()
    return this.solar2lunar(cY, cM, cD)
  }
}
export default calendar
uni_modules/uni-calendar/components/uni-calendar/i18n/en.json
对比新文件
@@ -0,0 +1,12 @@
{
    "uni-calender.ok": "ok",
    "uni-calender.cancel": "cancel",
    "uni-calender.today": "today",
    "uni-calender.MON": "MON",
    "uni-calender.TUE": "TUE",
    "uni-calender.WED": "WED",
    "uni-calender.THU": "THU",
    "uni-calender.FRI": "FRI",
    "uni-calender.SAT": "SAT",
    "uni-calender.SUN": "SUN"
}
uni_modules/uni-calendar/components/uni-calendar/i18n/index.js
对比新文件
@@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
    en,
    'zh-Hans': zhHans,
    'zh-Hant': zhHant
}
uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json
对比新文件
@@ -0,0 +1,12 @@
{
    "uni-calender.ok": "确定",
    "uni-calender.cancel": "取消",
    "uni-calender.today": "今日",
    "uni-calender.SUN": "日",
    "uni-calender.MON": "一",
    "uni-calender.TUE": "二",
    "uni-calender.WED": "三",
    "uni-calender.THU": "四",
    "uni-calender.FRI": "五",
    "uni-calender.SAT": "六"
}
uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json
对比新文件
@@ -0,0 +1,12 @@
{
    "uni-calender.ok": "確定",
    "uni-calender.cancel": "取消",
    "uni-calender.today": "今日",
    "uni-calender.SUN": "日",
    "uni-calender.MON": "一",
    "uni-calender.TUE": "二",
    "uni-calender.WED": "三",
    "uni-calender.THU": "四",
    "uni-calender.FRI": "五",
    "uni-calender.SAT": "六"
}
uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue
对比新文件
@@ -0,0 +1,187 @@
<template>
    <view class="uni-calendar-item__weeks-box" :class="{
        'uni-calendar-item--disable':weeks.disable,
        'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
        'uni-calendar-item--checked':(calendar.fullDate === weeks.fullDate && !weeks.isDay) ,
        'uni-calendar-item--before-checked':weeks.beforeMultiple,
        'uni-calendar-item--multiple': weeks.multiple,
        'uni-calendar-item--after-checked':weeks.afterMultiple,
        }"
     @click="choiceDate(weeks)">
        <view class="uni-calendar-item__weeks-box-item">
            <text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
            <text class="uni-calendar-item__weeks-box-text" :class="{
                'uni-calendar-item--isDay-text': weeks.isDay,
                'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
                'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
                'uni-calendar-item--before-checked':weeks.beforeMultiple,
                'uni-calendar-item--multiple': weeks.multiple,
                'uni-calendar-item--after-checked':weeks.afterMultiple,
                'uni-calendar-item--disable':weeks.disable,
                }">{{weeks.date}}</text>
            <text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uni-calendar-item__weeks-lunar-text" :class="{
                'uni-calendar-item--isDay-text':weeks.isDay,
                'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
                'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
                'uni-calendar-item--before-checked':weeks.beforeMultiple,
                'uni-calendar-item--multiple': weeks.multiple,
                'uni-calendar-item--after-checked':weeks.afterMultiple,
                }">{{todayText}}</text>
            <text v-if="lunar&&!weeks.extraInfo" class="uni-calendar-item__weeks-lunar-text" :class="{
                'uni-calendar-item--isDay-text':weeks.isDay,
                'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
                'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
                'uni-calendar-item--before-checked':weeks.beforeMultiple,
                'uni-calendar-item--multiple': weeks.multiple,
                'uni-calendar-item--after-checked':weeks.afterMultiple,
                'uni-calendar-item--disable':weeks.disable,
                }">{{weeks.isDay ? todayText : (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text>
            <text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uni-calendar-item__weeks-lunar-text" :class="{
                'uni-calendar-item--extra':weeks.extraInfo.info,
                'uni-calendar-item--isDay-text':weeks.isDay,
                'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
                'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
                'uni-calendar-item--before-checked':weeks.beforeMultiple,
                'uni-calendar-item--multiple': weeks.multiple,
                'uni-calendar-item--after-checked':weeks.afterMultiple,
                'uni-calendar-item--disable':weeks.disable,
                }">{{weeks.extraInfo.info}}</text>
        </view>
    </view>
</template>
<script>
    import { initVueI18n } from '@dcloudio/uni-i18n'
    import i18nMessages from './i18n/index.js'
    const {    t    } = initVueI18n(i18nMessages)
    export default {
        emits:['change'],
        props: {
            weeks: {
                type: Object,
                default () {
                    return {}
                }
            },
            calendar: {
                type: Object,
                default: () => {
                    return {}
                }
            },
            selected: {
                type: Array,
                default: () => {
                    return []
                }
            },
            lunar: {
                type: Boolean,
                default: false
            }
        },
        computed: {
            todayText() {
                return t("uni-calender.today")
            },
        },
        methods: {
            choiceDate(weeks) {
                this.$emit('change', weeks)
            }
        }
    }
</script>
<style lang="scss" scoped>
    $uni-font-size-base:14px;
    $uni-text-color:#333;
    $uni-font-size-sm:12px;
    $uni-color-error: #e43d33;
    $uni-opacity-disabled: 0.3;
    $uni-text-color-disable:#c0c0c0;
    $uni-primary: #2979ff !default;
    .uni-calendar-item__weeks-box {
        flex: 1;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: column;
        justify-content: center;
        align-items: center;
    }
    .uni-calendar-item__weeks-box-text {
        font-size: $uni-font-size-base;
        color: $uni-text-color;
    }
    .uni-calendar-item__weeks-lunar-text {
        font-size: $uni-font-size-sm;
        color: $uni-text-color;
    }
    .uni-calendar-item__weeks-box-item {
        position: relative;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: column;
        justify-content: center;
        align-items: center;
        width: 100rpx;
        height: 100rpx;
    }
    .uni-calendar-item__weeks-box-circle {
        position: absolute;
        top: 5px;
        right: 5px;
        width: 8px;
        height: 8px;
        border-radius: 8px;
        background-color: $uni-color-error;
    }
    .uni-calendar-item--disable {
        background-color: rgba(249, 249, 249, $uni-opacity-disabled);
        color: $uni-text-color-disable;
    }
    .uni-calendar-item--isDay-text {
        color: $uni-primary;
    }
    .uni-calendar-item--isDay {
        background-color: $uni-primary;
        opacity: 0.8;
        color: #fff;
    }
    .uni-calendar-item--extra {
        color: $uni-color-error;
        opacity: 0.8;
    }
    .uni-calendar-item--checked {
        background-color: $uni-primary;
        color: #fff;
        opacity: 0.8;
    }
    .uni-calendar-item--multiple {
        background-color: $uni-primary;
        color: #fff;
        opacity: 0.8;
    }
    .uni-calendar-item--before-checked {
        background-color: #ff5a5f;
        color: #fff;
    }
    .uni-calendar-item--after-checked {
        background-color: #ff5a5f;
        color: #fff;
    }
</style>
uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue
对比新文件
@@ -0,0 +1,567 @@
<template>
    <view class="uni-calendar">
        <view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></view>
        <view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}">
            <view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top">
                <view class="uni-calendar__header-btn-box" @click="close">
                    <text class="uni-calendar__header-text uni-calendar--fixed-width">{{cancelText}}</text>
                </view>
                <view class="uni-calendar__header-btn-box" @click="confirm">
                    <text class="uni-calendar__header-text uni-calendar--fixed-width">{{okText}}</text>
                </view>
            </view>
            <view class="uni-calendar__header">
                <view class="uni-calendar__header-btn-box" @click.stop="pre">
                    <view class="uni-calendar__header-btn uni-calendar--left"></view>
                </view>
                <picker mode="date" :value="date" fields="month" @change="bindDateChange">
                    <text class="uni-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
                </picker>
                <view class="uni-calendar__header-btn-box" @click.stop="next">
                    <view class="uni-calendar__header-btn uni-calendar--right"></view>
                </view>
                <text class="uni-calendar__backtoday" @click="backToday">{{todayText}}</text>
            </view>
            <view class="uni-calendar__box">
                <view v-if="showMonth" class="uni-calendar__box-bg">
                    <text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
                </view>
                <view class="uni-calendar__weeks">
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
                    </view>
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{monText}}</text>
                    </view>
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
                    </view>
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
                    </view>
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{THUText}}</text>
                    </view>
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
                    </view>
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{SATText}}</text>
                    </view>
                </view>
                <view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
                    <view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
                        <calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" @change="choiceDate"></calendar-item>
                    </view>
                </view>
            </view>
        </view>
    </view>
</template>
<script>
    import Calendar from './util.js';
    import CalendarItem from './uni-calendar-item.vue'
    import { initVueI18n } from '@dcloudio/uni-i18n'
    import i18nMessages from './i18n/index.js'
    const {    t    } = initVueI18n(i18nMessages)
    /**
     * Calendar 日历
     * @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
     * @tutorial https://ext.dcloud.net.cn/plugin?id=56
     * @property {String} date 自定义当前时间,默认为今天
     * @property {Boolean} lunar 显示农历
     * @property {String} startDate 日期选择范围-开始日期
     * @property {String} endDate 日期选择范围-结束日期
     * @property {Boolean} range 范围选择
     * @property {Boolean} insert = [true|false] 插入模式,默认为false
     *     @value true 弹窗模式
     *     @value false 插入模式
     * @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
     * @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
     * @property {Boolean} showMonth 是否选择月份为背景
     * @event {Function} change 日期改变,`insert :ture` 时生效
     * @event {Function} confirm 确认选择`insert :false` 时生效
     * @event {Function} monthSwitch 切换月份时触发
     * @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
     */
    export default {
        components: {
            CalendarItem
        },
        emits:['close','confirm','change','monthSwitch'],
        props: {
            date: {
                type: String,
                default: ''
            },
            selected: {
                type: Array,
                default () {
                    return []
                }
            },
            lunar: {
                type: Boolean,
                default: false
            },
            startDate: {
                type: String,
                default: ''
            },
            endDate: {
                type: String,
                default: ''
            },
            range: {
                type: Boolean,
                default: false
            },
            insert: {
                type: Boolean,
                default: true
            },
            showMonth: {
                type: Boolean,
                default: true
            },
            clearDate: {
                type: Boolean,
                default: true
            }
        },
        data() {
            return {
                show: false,
                weeks: [],
                calendar: {},
                nowDate: '',
                aniMaskShow: false
            }
        },
        computed:{
            /**
             * for i18n
             */
            okText() {
                return t("uni-calender.ok")
            },
            cancelText() {
                return t("uni-calender.cancel")
            },
            todayText() {
                return t("uni-calender.today")
            },
            monText() {
                return t("uni-calender.MON")
            },
            TUEText() {
                return t("uni-calender.TUE")
            },
            WEDText() {
                return t("uni-calender.WED")
            },
            THUText() {
                return t("uni-calender.THU")
            },
            FRIText() {
                return t("uni-calender.FRI")
            },
            SATText() {
                return t("uni-calender.SAT")
            },
            SUNText() {
                return t("uni-calender.SUN")
            },
        },
        watch: {
            date(newVal) {
                // this.cale.setDate(newVal)
                this.init(newVal)
            },
            startDate(val){
                this.cale.resetSatrtDate(val)
                this.cale.setDate(this.nowDate.fullDate)
                this.weeks = this.cale.weeks
            },
            endDate(val){
                this.cale.resetEndDate(val)
                this.cale.setDate(this.nowDate.fullDate)
                this.weeks = this.cale.weeks
            },
            selected(newVal) {
                this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
                this.weeks = this.cale.weeks
            }
        },
        created() {
            this.cale = new Calendar({
                selected: this.selected,
                startDate: this.startDate,
                endDate: this.endDate,
                range: this.range,
            })
            this.init(this.date)
        },
        methods: {
            // 取消穿透
            clean() {},
            bindDateChange(e) {
                const value = e.detail.value + '-1'
                this.setDate(value)
                const { year,month } = this.cale.getDate(value)
        this.$emit('monthSwitch', {
            year,
            month
        })
            },
            /**
             * 初始化日期显示
             * @param {Object} date
             */
            init(date) {
                this.cale.setDate(date)
                this.weeks = this.cale.weeks
                this.nowDate = this.calendar = this.cale.getInfo(date)
            },
            /**
             * 打开日历弹窗
             */
            open() {
                // 弹窗模式并且清理数据
                if (this.clearDate && !this.insert) {
                    this.cale.cleanMultipleStatus()
                    // this.cale.setDate(this.date)
                    this.init(this.date)
                }
                this.show = true
                this.$nextTick(() => {
                    setTimeout(() => {
                        this.aniMaskShow = true
                    }, 50)
                })
            },
            /**
             * 关闭日历弹窗
             */
            close() {
                this.aniMaskShow = false
                this.$nextTick(() => {
                    setTimeout(() => {
                        this.show = false
                        this.$emit('close')
                    }, 300)
                })
            },
            /**
             * 确认按钮
             */
            confirm() {
                this.setEmit('confirm')
                this.close()
            },
            /**
             * 变化触发
             */
            change() {
                if (!this.insert) return
                this.setEmit('change')
            },
            /**
             * 选择月份触发
             */
            monthSwitch() {
                let {
                    year,
                    month
                } = this.nowDate
                this.$emit('monthSwitch', {
                    year,
                    month: Number(month)
                })
            },
            /**
             * 派发事件
             * @param {Object} name
             */
            setEmit(name) {
                let {
                    year,
                    month,
                    date,
                    fullDate,
                    lunar,
                    extraInfo
                } = this.calendar
                this.$emit(name, {
                    range: this.cale.multipleStatus,
                    year,
                    month,
                    date,
                    fulldate: fullDate,
                    lunar,
                    extraInfo: extraInfo || {}
                })
            },
            /**
             * 选择天触发
             * @param {Object} weeks
             */
            choiceDate(weeks) {
                if (weeks.disable) return
                this.calendar = weeks
                // 设置多选
                this.cale.setMultiple(this.calendar.fullDate)
                this.weeks = this.cale.weeks
                this.change()
            },
            /**
             * 回到今天
             */
            backToday() {
                const nowYearMonth = `${this.nowDate.year}-${this.nowDate.month}`
                const date = this.cale.getDate(new Date())
        const todayYearMonth = `${date.year}-${date.month}`
                this.init(date.fullDate)
        if(nowYearMonth !== todayYearMonth) {
          this.monthSwitch()
        }
                this.change()
            },
            /**
             * 上个月
             */
            pre() {
                const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
                this.setDate(preDate)
                this.monthSwitch()
            },
            /**
             * 下个月
             */
            next() {
                const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
                this.setDate(nextDate)
                this.monthSwitch()
            },
            /**
             * 设置日期
             * @param {Object} date
             */
            setDate(date) {
                this.cale.setDate(date)
                this.weeks = this.cale.weeks
                this.nowDate = this.cale.getInfo(date)
            }
        }
    }
</script>
<style lang="scss" scoped>
    $uni-bg-color-mask: rgba($color: #000000, $alpha: 0.4);
    $uni-border-color: #EDEDED;
    $uni-text-color: #333;
    $uni-bg-color-hover:#f1f1f1;
    $uni-font-size-base:14px;
    $uni-text-color-placeholder: #808080;
    $uni-color-subtitle: #555555;
    $uni-text-color-grey:#999;
    .uni-calendar {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: column;
    }
    .uni-calendar__mask {
        position: fixed;
        bottom: 0;
        top: 0;
        left: 0;
        right: 0;
        background-color: $uni-bg-color-mask;
        transition-property: opacity;
        transition-duration: 0.3s;
        opacity: 0;
        /* #ifndef APP-NVUE */
        z-index: 99;
        /* #endif */
    }
    .uni-calendar--mask-show {
        opacity: 1
    }
    .uni-calendar--fixed {
        position: fixed;
        /* #ifdef APP-NVUE */
        bottom: 0;
        /* #endif */
        left: 0;
        right: 0;
        transition-property: transform;
        transition-duration: 0.3s;
        transform: translateY(460px);
        /* #ifndef APP-NVUE */
        bottom: calc(var(--window-bottom));
        z-index: 99;
        /* #endif */
    }
    .uni-calendar--ani-show {
        transform: translateY(0);
    }
    .uni-calendar__content {
        background-color: #fff;
    }
    .uni-calendar__header {
        position: relative;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
        justify-content: center;
        align-items: center;
        height: 50px;
        border-bottom-color: $uni-border-color;
        border-bottom-style: solid;
        border-bottom-width: 1px;
    }
    .uni-calendar--fixed-top {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
        justify-content: space-between;
        border-top-color: $uni-border-color;
        border-top-style: solid;
        border-top-width: 1px;
    }
    .uni-calendar--fixed-width {
        width: 50px;
    }
    .uni-calendar__backtoday {
        position: absolute;
        right: 0;
        top: 25rpx;
        padding: 0 5px;
        padding-left: 10px;
        height: 25px;
        line-height: 25px;
        font-size: 12px;
        border-top-left-radius: 25px;
        border-bottom-left-radius: 25px;
        color: $uni-text-color;
        background-color: $uni-bg-color-hover;
    }
    .uni-calendar__header-text {
        text-align: center;
        width: 100px;
        font-size: $uni-font-size-base;
        color: $uni-text-color;
    }
    .uni-calendar__header-btn-box {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
        align-items: center;
        justify-content: center;
        width: 50px;
        height: 50px;
    }
    .uni-calendar__header-btn {
        width: 10px;
        height: 10px;
        border-left-color: $uni-text-color-placeholder;
        border-left-style: solid;
        border-left-width: 2px;
        border-top-color: $uni-color-subtitle;
        border-top-style: solid;
        border-top-width: 2px;
    }
    .uni-calendar--left {
        transform: rotate(-45deg);
    }
    .uni-calendar--right {
        transform: rotate(135deg);
    }
    .uni-calendar__weeks {
        position: relative;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
    }
    .uni-calendar__weeks-item {
        flex: 1;
    }
    .uni-calendar__weeks-day {
        flex: 1;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: column;
        justify-content: center;
        align-items: center;
        height: 45px;
        border-bottom-color: #F5F5F5;
        border-bottom-style: solid;
        border-bottom-width: 1px;
    }
    .uni-calendar__weeks-day-text {
        font-size: 14px;
    }
    .uni-calendar__box {
        position: relative;
    }
    .uni-calendar__box-bg {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        justify-content: center;
        align-items: center;
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
    }
    .uni-calendar__box-bg-text {
        font-size: 200px;
        font-weight: bold;
        color: $uni-text-color-grey;
        opacity: 0.1;
        text-align: center;
        /* #ifndef APP-NVUE */
        line-height: 1;
        /* #endif */
    }
</style>
uni_modules/uni-calendar/components/uni-calendar/util.js
对比新文件
@@ -0,0 +1,360 @@
import CALENDAR from './calendar.js'
class Calendar {
    constructor({
        date,
        selected,
        startDate,
        endDate,
        range
    } = {}) {
        // 当前日期
        this.date = this.getDate(new Date()) // 当前初入日期
        // 打点信息
        this.selected = selected || [];
        // 范围开始
        this.startDate = startDate
        // 范围结束
        this.endDate = endDate
        this.range = range
        // 多选状态
        this.cleanMultipleStatus()
        // 每周日期
        this.weeks = {}
        // this._getWeek(this.date.fullDate)
    }
    /**
     * 设置日期
     * @param {Object} date
     */
    setDate(date) {
        this.selectDate = this.getDate(date)
        this._getWeek(this.selectDate.fullDate)
    }
    /**
     * 清理多选状态
     */
    cleanMultipleStatus() {
        this.multipleStatus = {
            before: '',
            after: '',
            data: []
        }
    }
    /**
     * 重置开始日期
     */
    resetSatrtDate(startDate) {
        // 范围开始
        this.startDate = startDate
    }
    /**
     * 重置结束日期
     */
    resetEndDate(endDate) {
        // 范围结束
        this.endDate = endDate
    }
    /**
     * 获取任意时间
     */
    getDate(date, AddDayCount = 0, str = 'day') {
        if (!date) {
            date = new Date()
        }
        if (typeof date !== 'object') {
            date = date.replace(/-/g, '/')
        }
        const dd = new Date(date)
        switch (str) {
            case 'day':
                dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
                break
            case 'month':
                if (dd.getDate() === 31 && AddDayCount>0) {
                    dd.setDate(dd.getDate() + AddDayCount)
                } else {
                    const preMonth = dd.getMonth()
                    dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期
                    const nextMonth = dd.getMonth()
                    // 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
                    if(AddDayCount<0 && preMonth!==0 && nextMonth-preMonth>AddDayCount){
                        dd.setMonth(nextMonth+(nextMonth-preMonth+AddDayCount))
                    }
                    // 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
                    if(AddDayCount>0 && nextMonth-preMonth>AddDayCount){
                        dd.setMonth(nextMonth-(nextMonth-preMonth-AddDayCount))
                    }
                }
                break
            case 'year':
                dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
                break
        }
        const y = dd.getFullYear()
        const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
        const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
        return {
            fullDate: y + '-' + m + '-' + d,
            year: y,
            month: m,
            date: d,
            day: dd.getDay()
        }
    }
    /**
     * 获取上月剩余天数
     */
    _getLastMonthDays(firstDay, full) {
        let dateArr = []
        for (let i = firstDay; i > 0; i--) {
            const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
            dateArr.push({
                date: beforeDate,
                month: full.month - 1,
                lunar: this.getlunar(full.year, full.month - 1, beforeDate),
                disable: true
            })
        }
        return dateArr
    }
    /**
     * 获取本月天数
     */
    _currentMonthDys(dateData, full) {
        let dateArr = []
        let fullDate = this.date.fullDate
        for (let i = 1; i <= dateData; i++) {
            let nowDate = full.year + '-' + (full.month < 10 ?
                full.month : full.month) + '-' + (i < 10 ?
                '0' + i : i)
            // 是否今天
            let isDay = fullDate === nowDate
            // 获取打点信息
            let info = this.selected && this.selected.find((item) => {
                if (this.dateEqual(nowDate, item.date)) {
                    return item
                }
            })
            // 日期禁用
            let disableBefore = true
            let disableAfter = true
            if (this.startDate) {
                // let dateCompBefore = this.dateCompare(this.startDate, fullDate)
                // disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
                disableBefore = this.dateCompare(this.startDate, nowDate)
            }
            if (this.endDate) {
                // let dateCompAfter = this.dateCompare(fullDate, this.endDate)
                // disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
                disableAfter = this.dateCompare(nowDate, this.endDate)
            }
            let multiples = this.multipleStatus.data
            let checked = false
            let multiplesStatus = -1
            if (this.range) {
                if (multiples) {
                    multiplesStatus = multiples.findIndex((item) => {
                        return this.dateEqual(item, nowDate)
                    })
                }
                if (multiplesStatus !== -1) {
                    checked = true
                }
            }
            let data = {
                fullDate: nowDate,
                year: full.year,
                date: i,
                multiple: this.range ? checked : false,
                beforeMultiple: this.dateEqual(this.multipleStatus.before, nowDate),
                afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
                month: full.month,
                lunar: this.getlunar(full.year, full.month, i),
                disable: !(disableBefore && disableAfter),
                isDay
            }
            if (info) {
                data.extraInfo = info
            }
            dateArr.push(data)
        }
        return dateArr
    }
    /**
     * 获取下月天数
     */
    _getNextMonthDays(surplus, full) {
        let dateArr = []
        for (let i = 1; i < surplus + 1; i++) {
            dateArr.push({
                date: i,
                month: Number(full.month) + 1,
                lunar: this.getlunar(full.year, Number(full.month) + 1, i),
                disable: true
            })
        }
        return dateArr
    }
    /**
     * 获取当前日期详情
     * @param {Object} date
     */
    getInfo(date) {
        if (!date) {
            date = new Date()
        }
        const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
        return dateInfo
    }
    /**
     * 比较时间大小
     */
    dateCompare(startDate, endDate) {
        // 计算截止时间
        startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
        // 计算详细项的截止时间
        endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
        if (startDate <= endDate) {
            return true
        } else {
            return false
        }
    }
    /**
     * 比较时间是否相等
     */
    dateEqual(before, after) {
        // 计算截止时间
        before = new Date(before.replace('-', '/').replace('-', '/'))
        // 计算详细项的截止时间
        after = new Date(after.replace('-', '/').replace('-', '/'))
        if (before.getTime() - after.getTime() === 0) {
            return true
        } else {
            return false
        }
    }
    /**
     * 获取日期范围内所有日期
     * @param {Object} begin
     * @param {Object} end
     */
    geDateAll(begin, end) {
        var arr = []
        var ab = begin.split('-')
        var ae = end.split('-')
        var db = new Date()
        db.setFullYear(ab[0], ab[1] - 1, ab[2])
        var de = new Date()
        de.setFullYear(ae[0], ae[1] - 1, ae[2])
        var unixDb = db.getTime() - 24 * 60 * 60 * 1000
        var unixDe = de.getTime() - 24 * 60 * 60 * 1000
        for (var k = unixDb; k <= unixDe;) {
            k = k + 24 * 60 * 60 * 1000
            arr.push(this.getDate(new Date(parseInt(k))).fullDate)
        }
        return arr
    }
    /**
     * 计算阴历日期显示
     */
    getlunar(year, month, date) {
        return CALENDAR.solar2lunar(year, month, date)
    }
    /**
     * 设置打点
     */
    setSelectInfo(data, value) {
        this.selected = value
        this._getWeek(data)
    }
    /**
     *  获取多选状态
     */
    setMultiple(fullDate) {
        let {
            before,
            after
        } = this.multipleStatus
        if (!this.range) return
        if (before && after) {
            this.multipleStatus.before = fullDate
            this.multipleStatus.after = ''
            this.multipleStatus.data = []
        } else {
            if (!before) {
                this.multipleStatus.before = fullDate
            } else {
                this.multipleStatus.after = fullDate
                if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
                    this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
                } else {
                    this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
                }
            }
        }
        this._getWeek(fullDate)
    }
    /**
     * 获取每周数据
     * @param {Object} dateData
     */
    _getWeek(dateData) {
        const {
            year,
            month
        } = this.getDate(dateData)
        let firstDay = new Date(year, month - 1, 1).getDay()
        let currentDay = new Date(year, month, 0).getDate()
        let dates = {
            lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
            currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
            nextMonthDays: [], // 下个月开始几天
            weeks: []
        }
        let canlender = []
        const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
        dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
        canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
        let weeks = {}
        // 拼接数组  上个月开始几天 + 本月天数+ 下个月开始几天
        for (let i = 0; i < canlender.length; i++) {
            if (i % 7 === 0) {
                weeks[parseInt(i / 7)] = new Array(7)
            }
            weeks[parseInt(i / 7)][i % 7] = canlender[i]
        }
        this.canlender = canlender
        this.weeks = weeks
    }
    //静态方法
    // static init(date) {
    //     if (!this.instance) {
    //         this.instance = new Calendar(date);
    //     }
    //     return this.instance;
    // }
}
export default Calendar
uni_modules/uni-calendar/package.json
对比新文件
@@ -0,0 +1,86 @@
{
  "id": "uni-calendar",
  "displayName": "uni-calendar 日历",
  "version": "1.4.12",
  "description": "日历组件",
  "keywords": [
    "uni-ui",
    "uniui",
    "日历",
    "",
    "打卡",
    "日历选择"
],
  "repository": "https://github.com/dcloudio/uni-ui",
  "engines": {
    "HBuilderX": ""
  },
  "directories": {
    "example": "../../temps/example_temps"
  },
"dcloudext": {
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "无",
      "permissions": "无"
    },
    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
    "type": "component-vue"
  },
  "uni_modules": {
    "dependencies": [],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y",
        "alipay": "n"
      },
      "client": {
        "App": {
          "app-vue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        },
        "Vue": {
            "vue2": "y",
            "vue3": "y"
        }
      }
    }
  }
}
uni_modules/uni-calendar/readme.md
对比新文件
@@ -0,0 +1,103 @@
## Calendar 日历
> **组件名:uni-calendar**
> 代码块: `uCalendar`
日历组件
> **注意事项**
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 本组件农历转换使用的js是 [@1900-2100区间内的公历、农历互转](https://github.com/jjonline/calendar.js)
> - 仅支持自定义组件模式
> - `date`属性传入的应该是一个 String ,如: 2019-06-27 ,而不是 new Date()
> - 通过 `insert` 属性来确定当前的事件是 @change 还是 @confirm 。理应合并为一个事件,但是为了区分模式,现使用两个事件,这里需要注意
> - 弹窗模式下无法阻止后面的元素滚动,如有需要阻止,请在弹窗弹出后,手动设置滚动元素为不可滚动
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
### 基本用法
在 ``template`` 中使用组件
```html
<view>
    <uni-calendar
    :insert="true"
    :lunar="true"
    :start-date="'2019-3-2'"
    :end-date="'2019-5-20'"
    @change="change"
     />
</view>
```
### 通过方法打开日历
需要设置 `insert` 为 `false`
```html
<view>
    <uni-calendar
    ref="calendar"
    :insert="false"
    @confirm="confirm"
     />
     <button @click="open">打开日历</button>
</view>
```
```javascript
export default {
    data() {
        return {};
    },
    methods: {
        open(){
            this.$refs.calendar.open();
        },
        confirm(e) {
            console.log(e);
        }
    }
};
```
## API
### Calendar Props
|  属性名    |    类型    | 默认值| 说明                                                                                                                    |
| -    | -    | - | - |
| date        | String    |-        | 自定义当前时间,默认为今天                                                                                            |
| lunar        | Boolean    | false    | 显示农历                                                                                                                |
| startDate    | String    |-        | 日期选择范围-开始日期                                                                                                    |
| endDate    | String    |-        | 日期选择范围-结束日期                                                                                                    |
| range        | Boolean    | false    | 范围选择                                                                                                                |
| insert    | Boolean    | false    | 插入模式,可选值,ture:插入模式;false:弹窗模式;默认为插入模式                                                        |
|clearDate    |Boolean    |true    |弹窗模式是否清空上次选择内容    |
| selected    | Array        |-        | 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]    |
|showMonth    | Boolean    | true    | 是否显示月份为背景                                                                                                    |
### Calendar Events
|  事件名        | 说明                                |返回值|
| -    |    -    | -    |
| open    | 弹出日历组件,`insert :false` 时生效|-     |
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar](https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar)
uni_modules/uni-card/changelog.md
对比新文件
@@ -0,0 +1,26 @@
## 1.3.1(2021-12-20)
- 修复 在vue页面下略缩图显示不正常的bug
## 1.3.0(2021-11-19)
- 重构插槽的用法 ,header 替换为 title
- 新增 actions 插槽
- 新增 cover 封面图属性和插槽
- 新增 padding 内容默认内边距离
- 新增 margin 卡片默认外边距离
- 新增 spacing 卡片默认内边距
- 新增 shadow 卡片阴影属性
- 取消 mode 属性,可使用组合插槽代替
- 取消 note 属性 ,使用actions插槽代替
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-card](https://uniapp.dcloud.io/component/uniui/uni-card)
## 1.2.1(2021-07-30)
- 优化 vue3下事件警告的问题
## 1.2.0(2021-07-13)
- 组件兼容 vue3,如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.8(2021-07-01)
- 优化 图文卡片无图片加载时,提供占位图标
- 新增 header 插槽,自定义卡片头部( 图文卡片 mode="style" 时,不支持)
- 修复 thumbnail 不存在仍然占位的 bug
## 1.1.7(2021-05-12)
- 新增 组件示例地址
## 1.1.6(2021-02-04)
- 调整为uni_modules目录规范
uni_modules/uni-card/components/uni-card/uni-card.vue
对比新文件
@@ -0,0 +1,270 @@
<template>
    <view class="uni-card" :class="{ 'uni-card--full': isFull, 'uni-card--shadow': isShadow,'uni-card--border':border}"
        :style="{'margin':isFull?0:margin,'padding':spacing,'box-shadow':isShadow?shadow:''}">
        <!-- 封面 -->
        <slot name="cover">
            <view v-if="cover" class="uni-card__cover">
                <image class="uni-card__cover-image" mode="widthFix" @click="onClick('cover')" :src="cover"></image>
            </view>
        </slot>
        <slot name="title">
            <view v-if="title || extra" class="uni-card__header">
                <!-- 卡片标题 -->
                <view class="uni-card__header-box" @click="onClick('title')">
                    <view v-if="thumbnail" class="uni-card__header-avatar">
                        <image class="uni-card__header-avatar-image" :src="thumbnail" mode="aspectFit" />
                    </view>
                    <view class="uni-card__header-content">
                        <text class="uni-card__header-content-title uni-ellipsis">{{ title }}</text>
                        <text v-if="title&&subTitle"
                            class="uni-card__header-content-subtitle uni-ellipsis">{{ subTitle }}</text>
                    </view>
                </view>
                <view class="uni-card__header-extra" @click="onClick('extra')">
                    <text class="uni-card__header-extra-text">{{ extra }}</text>
                </view>
            </view>
        </slot>
        <!-- 卡片内容 -->
        <view class="uni-card__content" :style="{padding:padding}" @click="onClick('content')">
            <slot></slot>
        </view>
        <view class="uni-card__actions" @click="onClick('actions')">
            <slot name="actions"></slot>
        </view>
    </view>
</template>
<script>
    /**
     * Card 卡片
     * @description 卡片视图组件
     * @tutorial https://ext.dcloud.net.cn/plugin?id=22
     * @property {String} title 标题文字
     * @property {String} subTitle 副标题
     * @property {Number} padding 内容内边距
     * @property {Number} margin 卡片外边距
     * @property {Number} spacing 卡片内边距
     * @property {String} extra 标题额外信息
     * @property {String} cover 封面图(本地路径需要引入)
     * @property {String} thumbnail 标题左侧缩略图
     * @property {Boolean} is-full = [true | false] 卡片内容是否通栏,为 true 时将去除padding值
     * @property {Boolean} is-shadow = [true | false] 卡片内容是否开启阴影
     * @property {String} shadow 卡片阴影
     * @property {Boolean} border 卡片边框
     * @event {Function} click 点击 Card 触发事件
     */
    export default {
        name: 'UniCard',
        emits: ['click'],
        props: {
            title: {
                type: String,
                default: ''
            },
            subTitle: {
                type: String,
                default: ''
            },
            padding: {
                type: String,
                default: '10px'
            },
            margin: {
                type: String,
                default: '15px'
            },
            spacing: {
                type: String,
                default: '0 10px'
            },
            extra: {
                type: String,
                default: ''
            },
            cover: {
                type: String,
                default: ''
            },
            thumbnail: {
                type: String,
                default: ''
            },
            isFull: {
                // 内容区域是否通栏
                type: Boolean,
                default: false
            },
            isShadow: {
                // 是否开启阴影
                type: Boolean,
                default: true
            },
            shadow: {
                type: String,
                default: '0px 0px 3px 1px rgba(0, 0, 0, 0.08)'
            },
            border: {
                type: Boolean,
                default: true
            }
        },
        methods: {
            onClick(type) {
                this.$emit('click', type)
            }
        }
    }
</script>
<style lang="scss">
    $uni-border-3: #EBEEF5 !default;
    $uni-shadow-base:0 0px 6px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default;
    $uni-main-color: #3a3a3a !default;
    $uni-base-color: #6a6a6a !default;
    $uni-secondary-color: #909399 !default;
    $uni-spacing-sm: 8px !default;
    $uni-border-color:$uni-border-3;
    $uni-shadow: $uni-shadow-base;
    $uni-card-title: 15px;
    $uni-cart-title-color:$uni-main-color;
    $uni-card-subtitle: 12px;
    $uni-cart-subtitle-color:$uni-secondary-color;
    $uni-card-spacing: 10px;
    $uni-card-content-color: $uni-base-color;
    .uni-card {
        margin: $uni-card-spacing;
        padding: 0 $uni-spacing-sm;
        border-radius: 4px;
        overflow: hidden;
        font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
        background-color: #fff;
        flex: 1;
        .uni-card__cover {
            position: relative;
            margin-top: $uni-card-spacing;
            flex-direction: row;
            overflow: hidden;
            border-radius: 4px;
            .uni-card__cover-image {
                flex: 1;
                // width: 100%;
                /* #ifndef APP-PLUS */
                vertical-align: middle;
                /* #endif */
            }
        }
        .uni-card__header {
            display: flex;
            border-bottom: 1px $uni-border-color solid;
            flex-direction: row;
            align-items: center;
            padding: $uni-card-spacing;
            overflow: hidden;
            .uni-card__header-box {
                /* #ifndef APP-NVUE */
                display: flex;
                /* #endif */
                flex: 1;
                flex-direction: row;
                align-items: center;
                overflow: hidden;
            }
            .uni-card__header-avatar {
                width: 40px;
                height: 40px;
                overflow: hidden;
                border-radius: 5px;
                margin-right: $uni-card-spacing;
                .uni-card__header-avatar-image {
                    flex: 1;
                    width: 40px;
                    height: 40px;
                }
            }
            .uni-card__header-content {
                /* #ifndef APP-NVUE */
                display: flex;
                /* #endif */
                flex-direction: column;
                justify-content: center;
                flex: 1;
                // height: 40px;
                overflow: hidden;
                .uni-card__header-content-title {
                    font-size: $uni-card-title;
                    color: $uni-cart-title-color;
                    // line-height: 22px;
                }
                .uni-card__header-content-subtitle {
                    font-size: $uni-card-subtitle;
                    margin-top: 5px;
                    color: $uni-cart-subtitle-color;
                }
            }
            .uni-card__header-extra {
                line-height: 12px;
                .uni-card__header-extra-text {
                    font-size: 12px;
                    color: $uni-cart-subtitle-color;
                }
            }
        }
        .uni-card__content {
            padding: $uni-card-spacing;
            font-size: 14px;
            color: $uni-card-content-color;
            line-height: 22px;
        }
        .uni-card__actions {
            font-size: 12px;
        }
    }
    .uni-card--border {
        border: 1px solid $uni-border-color;
    }
    .uni-card--shadow {
        position: relative;
        /* #ifndef APP-NVUE */
        box-shadow: $uni-shadow;
        /* #endif */
    }
    .uni-card--full {
        margin: 0;
        border-left-width: 0;
        border-left-width: 0;
        border-radius: 0;
    }
    /* #ifndef APP-NVUE */
    .uni-card--full:after {
        border-radius: 0;
    }
    /* #endif */
    .uni-ellipsis {
        /* #ifndef APP-NVUE */
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        /* #endif */
        /* #ifdef APP-NVUE */
        lines: 1;
        /* #endif */
    }
</style>
uni_modules/uni-card/package.json
对比新文件
@@ -0,0 +1,90 @@
{
  "id": "uni-card",
  "displayName": "uni-card 卡片",
  "version": "1.3.1",
  "description": "Card 组件,提供常见的卡片样式。",
  "keywords": [
    "uni-ui",
    "uniui",
    "card",
    "",
    "卡片"
],
  "repository": "https://github.com/dcloudio/uni-ui",
  "engines": {
    "HBuilderX": ""
  },
  "directories": {
    "example": "../../temps/example_temps"
  },
  "dcloudext": {
    "category": [
      "前端组件",
      "通用组件"
    ],
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "无",
      "permissions": "无"
    },
    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
  },
  "uni_modules": {
    "dependencies": [
            "uni-icons",
            "uni-scss"
        ],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y"
      },
      "client": {
        "App": {
          "app-vue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        },
        "Vue": {
            "vue2": "y",
            "vue3": "y"
        }
      }
    }
  }
}
uni_modules/uni-card/readme.md
对比新文件
@@ -0,0 +1,12 @@
## Card 卡片
> **组件名:uni-card**
> 代码块: `uCard`
卡片视图组件。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-card)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
uni_modules/uni-collapse/changelog.md
对比新文件
@@ -0,0 +1,38 @@
## 1.4.4(2024-03-20)
- 修复 titleBorder类型修正
## 1.4.3(2022-01-25)
- 修复 初始化的时候 ,open 属性失效的bug
## 1.4.2(2022-01-21)
- 修复 微信小程序resize后组件收起的bug
## 1.4.1(2021-11-22)
- 修复 vue3中个别scss变量无法找到的问题
## 1.4.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-collapse](https://uniapp.dcloud.io/component/uniui/uni-collapse)
## 1.3.3(2021-08-17)
- 优化 show-arrow 属性默认为true
## 1.3.2(2021-08-17)
- 新增 show-arrow 属性,控制是否显示右侧箭头
## 1.3.1(2021-07-30)
- 优化 vue3下小程序事件警告的问题
## 1.3.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.2.2(2021-07-21)
- 修复 由1.2.0版本引起的 change 事件返回 undefined 的Bug
## 1.2.1(2021-07-21)
- 优化 组件示例
## 1.2.0(2021-07-21)
- 新增 组件折叠动画
- 新增 value\v-model 属性 ,动态修改面板折叠状态
- 新增 title 插槽 ,可定义面板标题
- 新增 border 属性 ,显示隐藏面板内容分隔线
- 新增 title-border 属性 ,显示隐藏面板标题分隔线
- 修复 resize 方法失效的Bug
- 修复 change 事件返回参数不正确的Bug
- 优化 H5、App 平台自动更具内容更新高度,无需调用 reszie() 方法
## 1.1.7(2021-05-12)
- 新增 组件示例地址
## 1.1.6(2021-02-05)
- 优化 组件引用关系,通过uni_modules引用组件
## 1.1.5(2021-02-05)
- 调整为uni_modules目录规范
uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue
对比新文件
@@ -0,0 +1,402 @@
<template>
    <view class="uni-collapse-item">
        <!-- onClick(!isOpen) -->
        <view @click="onClick(!isOpen)" class="uni-collapse-item__title"
            :class="{'is-open':isOpen &&titleBorder === 'auto' ,'uni-collapse-item-border':titleBorder !== 'none'}">
            <view class="uni-collapse-item__title-wrap">
                <slot name="title">
                    <view class="uni-collapse-item__title-box" :class="{'is-disabled':disabled}">
                        <image v-if="thumb" :src="thumb" class="uni-collapse-item__title-img" />
                        <text class="uni-collapse-item__title-text">{{ title }}</text>
                    </view>
                </slot>
            </view>
            <view v-if="showArrow"
                :class="{ 'uni-collapse-item__title-arrow-active': isOpen, 'uni-collapse-item--animation': showAnimation === true }"
                class="uni-collapse-item__title-arrow">
                <uni-icons :color="disabled?'#ddd':'#bbb'" size="14" type="bottom" />
            </view>
        </view>
        <view class="uni-collapse-item__wrap" :class="{'is--transition':showAnimation}"
            :style="{height: (isOpen?height:0) +'px'}">
            <view :id="elId" ref="collapse--hook" class="uni-collapse-item__wrap-content"
                :class="{open:isheight,'uni-collapse-item--border':border&&isOpen}">
                <slot></slot>
            </view>
        </view>
    </view>
</template>
<script>
    // #ifdef APP-NVUE
    const dom = weex.requireModule('dom')
    // #endif
    /**
     * CollapseItem 折叠面板子组件
     * @description 折叠面板子组件
     * @property {String} title 标题文字
     * @property {String} thumb 标题左侧缩略图
     * @property {String} name 唯一标志符
     * @property {Boolean} open = [true|false] 是否展开组件
     * @property {Boolean} titleBorder = [true|false] 是否显示标题分隔线
     * @property {String} border = ['auto'|'show'|'none'] 是否显示分隔线
     * @property {Boolean} disabled = [true|false] 是否展开面板
     * @property {Boolean} showAnimation = [true|false] 开启动画
     * @property {Boolean} showArrow = [true|false] 是否显示右侧箭头
     */
    export default {
        name: 'uniCollapseItem',
        props: {
            // 列表标题
            title: {
                type: String,
                default: ''
            },
            name: {
                type: [Number, String],
                default: ''
            },
            // 是否禁用
            disabled: {
                type: Boolean,
                default: false
            },
            // #ifdef APP-PLUS
            // 是否显示动画,app 端默认不开启动画,卡顿严重
            showAnimation: {
                type: Boolean,
                default: false
            },
            // #endif
            // #ifndef APP-PLUS
            // 是否显示动画
            showAnimation: {
                type: Boolean,
                default: true
            },
            // #endif
            // 是否展开
            open: {
                type: Boolean,
                default: false
            },
            // 缩略图
            thumb: {
                type: String,
                default: ''
            },
            // 标题分隔线显示类型
            titleBorder: {
                type: String,
                default: 'auto'
            },
            border: {
                type: Boolean,
                default: true
            },
            showArrow: {
                type: Boolean,
                default: true
            }
        },
        data() {
            // TODO 随机生生元素ID,解决百度小程序获取同一个元素位置信息的bug
            const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
            return {
                isOpen: false,
                isheight: null,
                height: 0,
                elId,
                nameSync: 0
            }
        },
        watch: {
            open(val) {
                this.isOpen = val
                this.onClick(val, 'init')
            }
        },
        updated(e) {
            this.$nextTick(() => {
                this.init(true)
            })
        },
        created() {
            this.collapse = this.getCollapse()
            this.oldHeight = 0
            this.onClick(this.open, 'init')
        },
        // #ifndef VUE3
        // TODO vue2
        destroyed() {
            if (this.__isUnmounted) return
            this.uninstall()
        },
        // #endif
        // #ifdef VUE3
        // TODO vue3
        unmounted() {
            this.__isUnmounted = true
            this.uninstall()
        },
        // #endif
        mounted() {
            if (!this.collapse) return
            if (this.name !== '') {
                this.nameSync = this.name
            } else {
                this.nameSync = this.collapse.childrens.length + ''
            }
            if (this.collapse.names.indexOf(this.nameSync) === -1) {
                this.collapse.names.push(this.nameSync)
            } else {
                console.warn(`name 值 ${this.nameSync} 重复`);
            }
            if (this.collapse.childrens.indexOf(this) === -1) {
                this.collapse.childrens.push(this)
            }
            this.init()
        },
        methods: {
            init(type) {
                // #ifndef APP-NVUE
                this.getCollapseHeight(type)
                // #endif
                // #ifdef APP-NVUE
                this.getNvueHwight(type)
                // #endif
            },
            uninstall() {
                if (this.collapse) {
                    this.collapse.childrens.forEach((item, index) => {
                        if (item === this) {
                            this.collapse.childrens.splice(index, 1)
                        }
                    })
                    this.collapse.names.forEach((item, index) => {
                        if (item === this.nameSync) {
                            this.collapse.names.splice(index, 1)
                        }
                    })
                }
            },
            onClick(isOpen, type) {
                if (this.disabled) return
                this.isOpen = isOpen
                if (this.isOpen && this.collapse) {
                    this.collapse.setAccordion(this)
                }
                if (type !== 'init') {
                    this.collapse.onChange(isOpen, this)
                }
            },
            getCollapseHeight(type, index = 0) {
                const views = uni.createSelectorQuery().in(this)
                views
                    .select(`#${this.elId}`)
                    .fields({
                        size: true
                    }, data => {
                        // TODO 百度中可能获取不到节点信息 ,需要循环获取
                        if (index >= 10) return
                        if (!data) {
                            index++
                            this.getCollapseHeight(false, index)
                            return
                        }
                        // #ifdef APP-NVUE
                        this.height = data.height + 1
                        // #endif
                        // #ifndef APP-NVUE
                        this.height = data.height
                        // #endif
                        this.isheight = true
                        if (type) return
                        this.onClick(this.isOpen, 'init')
                    })
                    .exec()
            },
            getNvueHwight(type) {
                const result = dom.getComponentRect(this.$refs['collapse--hook'], option => {
                    if (option && option.result && option.size) {
                        // #ifdef APP-NVUE
                        this.height = option.size.height + 1
                        // #endif
                        // #ifndef APP-NVUE
                        this.height = option.size.height
                        // #endif
                        this.isheight = true
                        if (type) return
                        this.onClick(this.open, 'init')
                    }
                })
            },
            /**
             * 获取父元素实例
             */
            getCollapse(name = 'uniCollapse') {
                let parent = this.$parent;
                let parentName = parent.$options.name;
                while (parentName !== name) {
                    parent = parent.$parent;
                    if (!parent) return false;
                    parentName = parent.$options.name;
                }
                return parent;
            }
        }
    }
</script>
<style lang="scss">
    .uni-collapse-item {
        /* #ifndef APP-NVUE */
        box-sizing: border-box;
        /* #endif */
        &__title {
            /* #ifndef APP-NVUE */
            display: flex;
            width: 100%;
            box-sizing: border-box;
            /* #endif */
            flex-direction: row;
            align-items: center;
            transition: border-bottom-color .3s;
            // transition-property: border-bottom-color;
            // transition-duration: 5s;
            &-wrap {
                width: 100%;
                flex: 1;
            }
            &-box {
                padding: 0 15px;
                /* #ifndef APP-NVUE */
                display: flex;
                width: 100%;
                box-sizing: border-box;
                /* #endif */
                flex-direction: row;
                justify-content: space-between;
                align-items: center;
                height: 48px;
                line-height: 48px;
                background-color: #fff;
                color: #303133;
                font-size: 13px;
                font-weight: 500;
                /* #ifdef H5 */
                cursor: pointer;
                outline: none;
                /* #endif */
                &.is-disabled {
                    .uni-collapse-item__title-text {
                        color: #999;
                    }
                }
            }
            &.uni-collapse-item-border {
                border-bottom: 1px solid #ebeef5;
            }
            &.is-open {
                border-bottom-color: transparent;
            }
            &-img {
                height: 22px;
                width: 22px;
                margin-right: 10px;
            }
            &-text {
                flex: 1;
                font-size: 14px;
                /* #ifndef APP-NVUE */
                white-space: nowrap;
                color: inherit;
                /* #endif */
                /* #ifdef APP-NVUE */
                lines: 1;
                /* #endif */
                overflow: hidden;
                text-overflow: ellipsis;
            }
            &-arrow {
                /* #ifndef APP-NVUE */
                display: flex;
                box-sizing: border-box;
                /* #endif */
                align-items: center;
                justify-content: center;
                width: 20px;
                height: 20px;
                margin-right: 10px;
                transform: rotate(0deg);
                &-active {
                    transform: rotate(-180deg);
                }
            }
        }
        &__wrap {
            /* #ifndef APP-NVUE */
            will-change: height;
            box-sizing: border-box;
            /* #endif */
            background-color: #fff;
            overflow: hidden;
            position: relative;
            height: 0;
            &.is--transition {
                // transition: all 0.3s;
                transition-property: height, border-bottom-width;
                transition-duration: 0.3s;
                /* #ifndef APP-NVUE */
                will-change: height;
                /* #endif */
            }
            &-content {
                position: absolute;
                font-size: 13px;
                color: #303133;
                // transition: height 0.3s;
                border-bottom-color: transparent;
                border-bottom-style: solid;
                border-bottom-width: 0;
                &.uni-collapse-item--border {
                    border-bottom-width: 1px;
                    border-bottom-color: red;
                    border-bottom-color: #ebeef5;
                }
                &.open {
                    position: relative;
                }
            }
        }
        &--animation {
            transition-property: transform;
            transition-duration: 0.3s;
            transition-timing-function: ease;
        }
    }
</style>
uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue
对比新文件
@@ -0,0 +1,147 @@
<template>
    <view class="uni-collapse">
        <slot />
    </view>
</template>
<script>
    /**
     * Collapse 折叠面板
     * @description 展示可以折叠 / 展开的内容区域
     * @tutorial https://ext.dcloud.net.cn/plugin?id=23
     * @property {String|Array} value 当前激活面板改变时触发(如果是手风琴模式,参数类型为string,否则为array)
     * @property {Boolean} accordion = [true|false] 是否开启手风琴效果是否开启手风琴效果
     * @event {Function} change 切换面板时触发,如果是手风琴模式,返回类型为string,否则为array
     */
    export default {
        name: 'uniCollapse',
        emits:['change','activeItem','input','update:modelValue'],
        props: {
            value: {
                type: [String, Array],
                default: ''
            },
            modelValue: {
                type: [String, Array],
                default: ''
            },
            accordion: {
                // 是否开启手风琴效果
                type: [Boolean, String],
                default: false
            },
        },
        data() {
            return {}
        },
        computed: {
            // TODO 兼容 vue2 和 vue3
            dataValue() {
                let value = (typeof this.value === 'string' && this.value === '') ||
                    (Array.isArray(this.value) && this.value.length === 0)
                let modelValue = (typeof this.modelValue === 'string' && this.modelValue === '') ||
                    (Array.isArray(this.modelValue) && this.modelValue.length === 0)
                if (value) {
                    return this.modelValue
                }
                if (modelValue) {
                    return this.value
                }
                return this.value
            }
        },
        watch: {
            dataValue(val) {
                this.setOpen(val)
            }
        },
        created() {
            this.childrens = []
            this.names = []
        },
        mounted() {
            this.$nextTick(()=>{
                this.setOpen(this.dataValue)
            })
        },
        methods: {
            setOpen(val) {
                let str = typeof val === 'string'
                let arr = Array.isArray(val)
                this.childrens.forEach((vm, index) => {
                    if (str) {
                        if (val === vm.nameSync) {
                            if (!this.accordion) {
                                console.warn('accordion 属性为 false ,v-model 类型应该为 array')
                                return
                            }
                            vm.isOpen = true
                        }
                    }
                    if (arr) {
                        val.forEach(v => {
                            if (v === vm.nameSync) {
                                if (this.accordion) {
                                    console.warn('accordion 属性为 true ,v-model 类型应该为 string')
                                    return
                                }
                                vm.isOpen = true
                            }
                        })
                    }
                })
                this.emit(val)
            },
            setAccordion(self) {
                if (!this.accordion) return
                this.childrens.forEach((vm, index) => {
                    if (self !== vm) {
                        vm.isOpen = false
                    }
                })
            },
            resize() {
                this.childrens.forEach((vm, index) => {
                    // #ifndef APP-NVUE
                    vm.getCollapseHeight()
                    // #endif
                    // #ifdef APP-NVUE
                    vm.getNvueHwight()
                    // #endif
                })
            },
            onChange(isOpen, self) {
                let activeItem = []
                if (this.accordion) {
                    activeItem = isOpen ? self.nameSync : ''
                } else {
                    this.childrens.forEach((vm, index) => {
                        if (vm.isOpen) {
                            activeItem.push(vm.nameSync)
                        }
                    })
                }
                this.$emit('change', activeItem)
                this.emit(activeItem)
            },
            emit(val){
                this.$emit('input', val)
                this.$emit('update:modelValue', val)
            }
        }
    }
</script>
<style lang="scss" >
    .uni-collapse {
        /* #ifndef APP-NVUE */
        width: 100%;
        display: flex;
        /* #endif */
        /* #ifdef APP-NVUE */
        flex: 1;
        /* #endif */
        flex-direction: column;
        background-color: #fff;
    }
</style>
uni_modules/uni-collapse/package.json
对比新文件
@@ -0,0 +1,86 @@
{
  "id": "uni-collapse",
  "displayName": "uni-collapse 折叠面板",
  "version": "1.4.4",
  "description": "Collapse 组件,可以折叠 / 展开的内容区域。",
  "keywords": [
    "uni-ui",
    "折叠",
    "折叠面板",
    "手风琴"
],
  "repository": "https://github.com/dcloudio/uni-ui",
  "engines": {
    "HBuilderX": ""
  },
  "directories": {
    "example": "../../temps/example_temps"
  },
"dcloudext": {
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "无",
      "permissions": "无"
    },
    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
    "type": "component-vue"
  },
  "uni_modules": {
    "dependencies": [
            "uni-scss",
      "uni-icons"
    ],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y"
      },
      "client": {
        "App": {
          "app-vue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        },
        "Vue": {
            "vue2": "y",
            "vue3": "y"
        }
      }
    }
  }
}
uni_modules/uni-collapse/readme.md
对比新文件
@@ -0,0 +1,12 @@
## Collapse 折叠面板
> **组件名:uni-collapse**
> 代码块: `uCollapse`
> 关联组件:`uni-collapse-item`、`uni-icons`。
折叠面板用来折叠/显示过长的内容或者是列表。通常是在多内容分类项使用,折叠不重要的内容,显示重要内容。点击可以展开折叠部分。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-collapse)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
uni_modules/uni-combox/changelog.md
对比新文件
@@ -0,0 +1,17 @@
## 1.0.2(2024-09-21)
- 新增 clearAble属性
## 1.0.1(2021-11-23)
- 优化 label、label-width 属性
## 1.0.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-combox](https://uniapp.dcloud.io/component/uniui/uni-combox)
## 0.1.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.0.6(2021-05-12)
- 新增 组件示例地址
## 0.0.5(2021-04-21)
- 优化 添加依赖 uni-icons, 导入后自动下载依赖
## 0.0.4(2021-02-05)
- 优化 组件引用关系,通过uni_modules引用组件
## 0.0.3(2021-02-04)
- 调整为uni_modules目录规范
uni_modules/uni-combox/components/uni-combox/uni-combox.vue
对比新文件
@@ -0,0 +1,284 @@
<template>
    <view class="uni-combox" :class="border ? '' : 'uni-combox__no-border'">
        <view v-if="label" class="uni-combox__label" :style="labelStyle">
            <text>{{label}}</text>
        </view>
        <view class="uni-combox__input-box">
            <input class="uni-combox__input" type="text" :placeholder="placeholder" placeholder-class="uni-combox__input-plac"
                v-model="inputVal" @input="onInput" @focus="onFocus" @blur="onBlur" />
            <uni-icons v-if="!inputVal || !clearAble" :type="showSelector? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector">
            </uni-icons>
            <uni-icons v-if="inputVal && clearAble" type="clear" size="24" color="#999" @click="clean">
            </uni-icons>
        </view>
        <view class="uni-combox__selector" v-if="showSelector">
            <view class="uni-popper__arrow"></view>
            <scroll-view scroll-y="true" class="uni-combox__selector-scroll">
                <view class="uni-combox__selector-empty" v-if="filterCandidatesLength === 0">
                    <text>{{emptyTips}}</text>
                </view>
                <view class="uni-combox__selector-item" v-for="(item,index) in filterCandidates" :key="index"
                    @click="onSelectorClick(index)">
                    <text>{{item}}</text>
                </view>
            </scroll-view>
        </view>
    </view>
</template>
<script>
    /**
     * Combox 组合输入框
     * @description 组合输入框一般用于既可以输入也可以选择的场景
     * @tutorial https://ext.dcloud.net.cn/plugin?id=1261
     * @property {String} label 左侧文字
     * @property {String} labelWidth 左侧内容宽度
     * @property {String} placeholder 输入框占位符
     * @property {Array} candidates 候选项列表
     * @property {String} emptyTips 筛选结果为空时显示的文字
     * @property {String} value 组合框的值
     */
    export default {
        name: 'uniCombox',
        emits: ['input', 'update:modelValue'],
        props: {
            clearAble: {
                type: Boolean,
                default: false
            },
            border: {
                type: Boolean,
                default: true
            },
            label: {
                type: String,
                default: ''
            },
            labelWidth: {
                type: String,
                default: 'auto'
            },
            placeholder: {
                type: String,
                default: ''
            },
            candidates: {
                type: Array,
                default () {
                    return []
                }
            },
            emptyTips: {
                type: String,
                default: '无匹配项'
            },
            // #ifndef VUE3
            value: {
                type: [String, Number],
                default: ''
            },
            // #endif
            // #ifdef VUE3
            modelValue: {
                type: [String, Number],
                default: ''
            },
            // #endif
        },
        data() {
            return {
                showSelector: false,
                inputVal: ''
            }
        },
        computed: {
            labelStyle() {
                if (this.labelWidth === 'auto') {
                    return ""
                }
                return `width: ${this.labelWidth}`
            },
            filterCandidates() {
                return this.candidates.filter((item) => {
                    return item.toString().indexOf(this.inputVal) > -1
                })
            },
            filterCandidatesLength() {
                return this.filterCandidates.length
            }
        },
        watch: {
            // #ifndef VUE3
            value: {
                handler(newVal) {
                    this.inputVal = newVal
                },
                immediate: true
            },
            // #endif
            // #ifdef VUE3
            modelValue: {
                handler(newVal) {
                    this.inputVal = newVal
                },
                immediate: true
            },
            // #endif
        },
        methods: {
            toggleSelector() {
                this.showSelector = !this.showSelector
            },
            onFocus() {
                this.showSelector = true
            },
            onBlur() {
                setTimeout(() => {
                    this.showSelector = false
                }, 153)
            },
            onSelectorClick(index) {
                this.inputVal = this.filterCandidates[index]
                this.showSelector = false
                this.$emit('input', this.inputVal)
                this.$emit('update:modelValue', this.inputVal)
            },
            onInput() {
                setTimeout(() => {
                    this.$emit('input', this.inputVal)
                    this.$emit('update:modelValue', this.inputVal)
                })
            },
            clean() {
                this.inputVal = ''
                this.onInput()
            }
        }
    }
</script>
<style lang="scss" scoped>
    .uni-combox {
        font-size: 14px;
        border: 1px solid #DCDFE6;
        border-radius: 4px;
        padding: 6px 10px;
        position: relative;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        // height: 40px;
        flex-direction: row;
        align-items: center;
        // border-bottom: solid 1px #DDDDDD;
    }
    .uni-combox__label {
        font-size: 16px;
        line-height: 22px;
        padding-right: 10px;
        color: #999999;
    }
    .uni-combox__input-box {
        position: relative;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex: 1;
        flex-direction: row;
        align-items: center;
    }
    .uni-combox__input {
        flex: 1;
        font-size: 14px;
        height: 22px;
        line-height: 22px;
    }
    .uni-combox__input-plac {
        font-size: 14px;
        color: #999;
    }
    .uni-combox__selector {
        /* #ifndef APP-NVUE */
        box-sizing: border-box;
        /* #endif */
        position: absolute;
        top: calc(100% + 12px);
        left: 0;
        width: 100%;
        background-color: #FFFFFF;
        border: 1px solid #EBEEF5;
        border-radius: 6px;
        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
        z-index: 2;
        padding: 4px 0;
    }
    .uni-combox__selector-scroll {
        /* #ifndef APP-NVUE */
        max-height: 200px;
        box-sizing: border-box;
        /* #endif */
    }
    .uni-combox__selector-empty,
    .uni-combox__selector-item {
        /* #ifndef APP-NVUE */
        display: flex;
        cursor: pointer;
        /* #endif */
        line-height: 36px;
        font-size: 14px;
        text-align: center;
        // border-bottom: solid 1px #DDDDDD;
        padding: 0px 10px;
    }
    .uni-combox__selector-item:hover {
        background-color: #f9f9f9;
    }
    .uni-combox__selector-empty:last-child,
    .uni-combox__selector-item:last-child {
        /* #ifndef APP-NVUE */
        border-bottom: none;
        /* #endif */
    }
    // picker 弹出层通用的指示小三角
    .uni-popper__arrow,
    .uni-popper__arrow::after {
        position: absolute;
        display: block;
        width: 0;
        height: 0;
        border-color: transparent;
        border-style: solid;
        border-width: 6px;
    }
    .uni-popper__arrow {
        filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
        top: -6px;
        left: 10%;
        margin-right: 3px;
        border-top-width: 0;
        border-bottom-color: #EBEEF5;
    }
    .uni-popper__arrow::after {
        content: " ";
        top: 1px;
        margin-left: -6px;
        border-top-width: 0;
        border-bottom-color: #fff;
    }
    .uni-combox__no-border {
        border: none;
    }
</style>
uni_modules/uni-combox/package.json
对比新文件
@@ -0,0 +1,88 @@
{
  "id": "uni-combox",
  "displayName": "uni-combox 组合框",
  "version": "1.0.2",
  "description": "可以选择也可以输入的表单项 ",
  "keywords": [
    "uni-ui",
    "uniui",
    "combox",
    "组合框",
    "select"
],
  "repository": "https://github.com/dcloudio/uni-ui",
  "engines": {
    "HBuilderX": ""
  },
  "directories": {
    "example": "../../temps/example_temps"
  },
"dcloudext": {
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "无",
      "permissions": "无"
    },
    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
    "type": "component-vue"
  },
  "uni_modules": {
    "dependencies": [
            "uni-scss",
            "uni-icons"
        ],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y",
        "alipay": "n"
      },
      "client": {
        "App": {
          "app-vue": "y",
          "app-nvue": "n"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        },
        "Vue": {
            "vue2": "y",
            "vue3": "y"
        }
      }
    }
  }
}
uni_modules/uni-combox/readme.md
对比新文件
@@ -0,0 +1,11 @@
## Combox 组合框
> **组件名:uni-combox**
> 代码块: `uCombox`
组合框组件。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-combox)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
uni_modules/uni-countdown/changelog.md
对比新文件
@@ -0,0 +1,28 @@
## 1.2.4(2024-09-21)
- 新增 支持控制显示位数 默认显示2位
## 1.2.3(2024-02-20)
- 新增 支持控制小时,分钟的显隐:showHour showMinute
## 1.2.2(2022-01-19)
- 修复 在微信小程序中样式不生效的bug
## 1.2.1(2022-01-18)
- 新增 update 方法 ,在动态更新时间后,刷新组件
## 1.2.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-countdown](https://uniapp.dcloud.io/component/uniui/uni-countdown)
## 1.1.3(2021-10-18)
- 重构
- 新增 font-size 支持自定义字体大小
## 1.1.2(2021-08-24)
- 新增 支持国际化
## 1.1.1(2021-07-30)
- 优化 vue3下小程序事件警告的问题
## 1.1.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.5(2021-06-18)
- 修复 uni-countdown 重复赋值跳两秒的 bug
## 1.0.4(2021-05-12)
- 新增 组件示例地址
## 1.0.3(2021-05-08)
- 修复 uni-countdown 不能控制倒计时的 bug
## 1.0.2(2021-02-04)
- 调整为uni_modules目录规范
uni_modules/uni-countdown/components/uni-countdown/i18n/en.json
对比新文件
@@ -0,0 +1,6 @@
{
    "uni-countdown.day": "day",
    "uni-countdown.h": "h",
    "uni-countdown.m": "m",
    "uni-countdown.s": "s"
}
uni_modules/uni-countdown/components/uni-countdown/i18n/index.js
对比新文件
@@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
    en,
    'zh-Hans': zhHans,
    'zh-Hant': zhHant
}
uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json
对比新文件
@@ -0,0 +1,6 @@
{
    "uni-countdown.day": "天",
    "uni-countdown.h": "时",
    "uni-countdown.m": "分",
    "uni-countdown.s": "秒"
}
uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json
对比新文件
@@ -0,0 +1,6 @@
{
    "uni-countdown.day": "天",
    "uni-countdown.h": "時",
    "uni-countdown.m": "分",
    "uni-countdown.s": "秒"
}
uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue
对比新文件
@@ -0,0 +1,276 @@
<template>
    <view class="uni-countdown">
        <text v-if="showDay" :style="[timeStyle]" class="uni-countdown__number">{{ d }}</text>
        <text v-if="showDay" :style="[splitorStyle]" class="uni-countdown__splitor">{{dayText}}</text>
        <text v-if="showHour" :style="[timeStyle]" class="uni-countdown__number">{{ h }}</text>
        <text v-if="showHour" :style="[splitorStyle]" class="uni-countdown__splitor">{{ showColon ? ':' : hourText }}</text>
        <text v-if="showMinute" :style="[timeStyle]" class="uni-countdown__number">{{ i }}</text>
        <text v-if="showMinute" :style="[splitorStyle]" class="uni-countdown__splitor">{{ showColon ? ':' : minuteText }}</text>
        <text :style="[timeStyle]" class="uni-countdown__number">{{ s }}</text>
        <text v-if="!showColon" :style="[splitorStyle]" class="uni-countdown__splitor">{{secondText}}</text>
    </view>
</template>
<script>
    import {
        initVueI18n
    } from '@dcloudio/uni-i18n'
    import messages from './i18n/index.js'
    const {
        t
    } = initVueI18n(messages)
    /**
     * Countdown 倒计时
     * @description 倒计时组件
     * @tutorial https://ext.dcloud.net.cn/plugin?id=25
     * @property {String} backgroundColor 背景色
     * @property {String} color 文字颜色
     * @property {Number} day 天数
     * @property {Number} hour 小时
     * @property {Number} minute 分钟
     * @property {Number} second 秒
     * @property {Number} timestamp 时间戳
     * @property {Boolean} showDay = [true|false] 是否显示天数
     * @property {Boolean} showHour = [true|false] 是否显示小时
     * @property {Boolean} showMinute = [true|false] 是否显示分钟
     * @property {Boolean} show-colon = [true|false] 是否以冒号为分隔符
     * @property {String} splitorColor 分割符号颜色
     * @event {Function} timeup 倒计时时间到触发事件
     * @example <uni-countdown :day="1" :hour="1" :minute="12" :second="40"></uni-countdown>
     */
    export default {
        name: 'UniCountdown',
        emits: ['timeup'],
        props: {
            showDay: {
                type: Boolean,
                default: true
            },
            showHour: {
                type: Boolean,
                default: true
            },
            showMinute: {
                type: Boolean,
                default: true
            },
            showColon: {
                type: Boolean,
                default: true
            },
            start: {
                type: Boolean,
                default: true
            },
            backgroundColor: {
                type: String,
                default: ''
            },
            color: {
                type: String,
                default: '#333'
            },
            fontSize: {
                type: Number,
                default: 14
            },
            splitorColor: {
                type: String,
                default: '#333'
            },
            day: {
                type: Number,
                default: 0
            },
            hour: {
                type: Number,
                default: 0
            },
            minute: {
                type: Number,
                default: 0
            },
            second: {
                type: Number,
                default: 0
            },
            timestamp: {
                type: Number,
                default: 0
            },
            filterShow : {
                type:Object,
                default:{}
            }
        },
        data() {
            return {
                timer: null,
                syncFlag: false,
                d: '00',
                h: '00',
                i: '00',
                s: '00',
                leftTime: 0,
                seconds: 0
            }
        },
        computed: {
            dayText() {
                return t("uni-countdown.day")
            },
            hourText(val) {
                return t("uni-countdown.h")
            },
            minuteText(val) {
                return t("uni-countdown.m")
            },
            secondText(val) {
                return t("uni-countdown.s")
            },
            timeStyle() {
                const {
                    color,
                    backgroundColor,
                    fontSize
                } = this
                return {
                    color,
                    backgroundColor,
                    fontSize: `${fontSize}px`,
                    width: `${fontSize * 22 / 14}px`, // 按字体大小为 14px 时的比例缩放
                     lineHeight: `${fontSize * 20 / 14}px`,
                    borderRadius: `${fontSize * 3 / 14}px`,
                }
            },
            splitorStyle() {
                const { splitorColor, fontSize, backgroundColor } = this
                return {
                    color: splitorColor,
                    fontSize: `${fontSize * 12 / 14}px`,
                    margin: backgroundColor ? `${fontSize * 4 / 14}px` : ''
                }
            }
        },
        watch: {
            day(val) {
                this.changeFlag()
            },
            hour(val) {
                this.changeFlag()
            },
            minute(val) {
                this.changeFlag()
            },
            second(val) {
                this.changeFlag()
            },
            start: {
                immediate: true,
                handler(newVal, oldVal) {
                    if (newVal) {
                        this.startData();
                    } else {
                        if (!oldVal) return
                        clearInterval(this.timer)
                    }
                }
            }
        },
        created: function(e) {
            this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
            this.countDown()
        },
        // #ifndef VUE3
        destroyed() {
            clearInterval(this.timer)
        },
        // #endif
        // #ifdef VUE3
        unmounted() {
            clearInterval(this.timer)
        },
        // #endif
        methods: {
            toSeconds(timestamp, day, hours, minutes, seconds) {
                if (timestamp) {
                    return timestamp - parseInt(new Date().getTime() / 1000, 10)
                }
                return day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds
            },
            timeUp() {
                clearInterval(this.timer)
                this.$emit('timeup')
            },
            countDown() {
                let seconds = this.seconds
                let [day, hour, minute, second] = [0, 0, 0, 0]
                if (seconds > 0) {
                    day = Math.floor(seconds / (60 * 60 * 24))
                    hour = Math.floor(seconds / (60 * 60)) - (day * 24)
                    minute = Math.floor(seconds / 60) - (day * 24 * 60) - (hour * 60)
                    second = Math.floor(seconds) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60)
                } else {
                    this.timeUp()
                }
                this.d  = String(day).padStart(this.validFilterShow(this.filterShow.d), '0')
                this.h = String(hour).padStart(this.validFilterShow(this.filterShow.h), '0')
                this.i = String(minute).padStart(this.validFilterShow(this.filterShow.m), '0')
                this.s = String(second).padStart(this.validFilterShow(this.filterShow.s), '0')
            },
            validFilterShow(filter){
                return (filter && filter > 0) ? filter : 2;
            },
            startData() {
                this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
                if (this.seconds <= 0) {
                    this.seconds = this.toSeconds(0, 0, 0, 0, 0)
                    this.countDown()
                    return
                }
                clearInterval(this.timer)
                this.countDown()
                this.timer = setInterval(() => {
                    this.seconds--
                    if (this.seconds < 0) {
                        this.timeUp()
                        return
                    }
                    this.countDown()
                }, 1000)
            },
            update(){
                this.startData();
            },
            changeFlag() {
                if (!this.syncFlag) {
                    this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
                    this.startData();
                    this.syncFlag = true;
                }
            }
        }
    }
</script>
<style lang="scss" scoped>
    $font-size: 14px;
    .uni-countdown {
        display: flex;
        flex-direction: row;
        justify-content: flex-start;
        align-items: center;
        &__splitor {
            margin: 0 2px;
            font-size: $font-size;
            color: #333;
        }
        &__number {
            border-radius: 3px;
            text-align: center;
            font-size: $font-size;
        }
    }
</style>
uni_modules/uni-countdown/package.json
对比新文件
@@ -0,0 +1,84 @@
{
  "id": "uni-countdown",
  "displayName": "uni-countdown 倒计时",
  "version": "1.2.4",
  "description": "CountDown 倒计时组件",
  "keywords": [
    "uni-ui",
    "uniui",
    "countdown",
    "倒计时"
],
  "repository": "https://github.com/dcloudio/uni-ui",
  "engines": {
    "HBuilderX": ""
  },
  "directories": {
    "example": "../../temps/example_temps"
  },
"dcloudext": {
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "无",
      "permissions": "无"
    },
    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
    "type": "component-vue"
  },
  "uni_modules": {
    "dependencies": ["uni-scss"],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y",
        "alipay": "n"
      },
      "client": {
        "App": {
          "app-vue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        },
        "Vue": {
            "vue2": "y",
            "vue3": "y"
        }
      }
    }
  }
}
uni_modules/uni-countdown/readme.md
对比新文件
@@ -0,0 +1,10 @@
## CountDown 倒计时
> **组件名:uni-countdown**
> 代码块: `uCountDown`
倒计时组件。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-countdown)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
uni_modules/uni-data-checkbox/changelog.md
对比新文件
@@ -0,0 +1,49 @@
## 1.0.5(2024-03-20)
- 修复 单选模式下选中样式不生效的bug
## 1.0.4(2024-01-27)
- 修复 修复错别字chagne为change
## 1.0.3(2022-09-16)
- 可以使用 uni-scss 控制主题色
## 1.0.2(2022-06-30)
- 优化 在 uni-forms 中的依赖注入方式
## 1.0.1(2022-02-07)
- 修复 multiple 为 true 时,v-model 的值为 null 报错的 bug
## 1.0.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-checkbox](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
## 0.2.5(2021-08-23)
- 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题
## 0.2.4(2021-08-17)
- 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题
## 0.2.3(2021-08-11)
- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
## 0.2.2(2021-07-30)
- 优化 在uni-forms组件,与label不对齐的问题
## 0.2.1(2021-07-27)
- 修复 单选默认值为0不能选中的Bug
## 0.2.0(2021-07-13)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.1.11(2021-07-06)
- 优化 删除无用日志
## 0.1.10(2021-07-05)
- 修复 由 0.1.9 引起的非 nvue 端图标不显示的问题
## 0.1.9(2021-07-05)
- 修复 nvue 黑框样式问题
## 0.1.8(2021-06-28)
- 修复 selectedTextColor 属性不生效的Bug
## 0.1.7(2021-06-02)
- 新增 map 属性,可以方便映射text/value属性
## 0.1.6(2021-05-26)
- 修复 不关联服务空间的情况下组件报错的Bug
## 0.1.5(2021-05-12)
- 新增 组件示例地址
## 0.1.4(2021-04-09)
- 修复 nvue 下无法选中的问题
## 0.1.3(2021-03-22)
- 新增 disabled属性
## 0.1.2(2021-02-24)
- 优化 默认颜色显示
## 0.1.1(2021-02-24)
- 新增 支持nvue
## 0.1.0(2021-02-18)
- “暂无数据”显示居中
uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue
对比新文件
@@ -0,0 +1,849 @@
<template>
    <view class="uni-data-checklist" :style="{'margin-top':isTop+'px'}">
        <template v-if="!isLocal">
            <view class="uni-data-loading">
                <uni-load-more v-if="!mixinDatacomErrorMessage" status="loading" iconType="snow" :iconSize="18"
                    :content-text="contentText"></uni-load-more>
                <text v-else>{{mixinDatacomErrorMessage}}</text>
            </view>
        </template>
        <template v-else>
            <checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list' || wrap}"
                @change="change">
                <label class="checklist-box"
                    :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
                    :style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
                    <checkbox class="hidden" hidden :disabled="disabled || !!item.disabled" :value="item[map.value]+''"
                        :checked="item.selected" />
                    <view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')"
                        class="checkbox__inner" :style="item.styleIcon">
                        <view class="checkbox__inner-icon"></view>
                    </view>
                    <view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
                        <text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
                        <view v-if="mode === 'list' && icon === 'right'" class="checkobx__list" :style="item.styleBackgroud"></view>
                    </view>
                </label>
            </checkbox-group>
            <radio-group v-else class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="change">
                <label class="checklist-box"
                    :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
                    :style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
                    <radio class="hidden" hidden :disabled="disabled || item.disabled" :value="item[map.value]+''"
                        :checked="item.selected" />
                    <view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="radio__inner"
                        :style="item.styleBackgroud">
                        <view class="radio__inner-icon" :style="item.styleIcon"></view>
                    </view>
                    <view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
                        <text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
                        <view v-if="mode === 'list' && icon === 'right'" :style="item.styleRightIcon" class="checkobx__list"></view>
                    </view>
                </label>
            </radio-group>
        </template>
    </view>
</template>
<script>
    /**
     * DataChecklist 数据选择器
     * @description 通过数据渲染 checkbox 和 radio
     * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
     * @property {String} mode = [default| list | button | tag] 显示模式
     * @value default      默认横排模式
     * @value list        列表模式
     * @value button    按钮模式
     * @value tag         标签模式
     * @property {Boolean} multiple = [true|false] 是否多选
     * @property {Array|String|Number} value 默认值
     * @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
     * @property {Number|String} min 最小选择个数 ,multiple为true时生效
     * @property {Number|String} max 最大选择个数 ,multiple为true时生效
     * @property {Boolean} wrap 是否换行显示
     * @property {String} icon = [left|right]  list 列表模式下icon显示位置
     * @property {Boolean} selectedColor 选中颜色
     * @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效
     * @property {Boolean} selectedTextColor 选中文本颜色,如不填写则自动显示
     * @property {Object} map 字段映射, 默认 map={text:'text',value:'value'}
     * @value left 左侧显示
     * @value right 右侧显示
     * @event {Function} change  选中发生变化触发
     */
    export default {
        name: 'uniDataChecklist',
        mixins: [uniCloud.mixinDatacom || {}],
        emits: ['input', 'update:modelValue', 'change'],
        props: {
            mode: {
                type: String,
                default: 'default'
            },
            multiple: {
                type: Boolean,
                default: false
            },
            value: {
                type: [Array, String, Number],
                default () {
                    return ''
                }
            },
            // TODO vue3
            modelValue: {
                type: [Array, String, Number],
                default () {
                    return '';
                }
            },
            localdata: {
                type: Array,
                default () {
                    return []
                }
            },
            min: {
                type: [Number, String],
                default: ''
            },
            max: {
                type: [Number, String],
                default: ''
            },
            wrap: {
                type: Boolean,
                default: false
            },
            icon: {
                type: String,
                default: 'left'
            },
            selectedColor: {
                type: String,
                default: ''
            },
            selectedTextColor: {
                type: String,
                default: ''
            },
            emptyText: {
                type: String,
                default: '暂无数据'
            },
            disabled: {
                type: Boolean,
                default: false
            },
            map: {
                type: Object,
                default () {
                    return {
                        text: 'text',
                        value: 'value'
                    }
                }
            }
        },
        watch: {
            localdata: {
                handler(newVal) {
                    this.range = newVal
                    this.dataList = this.getDataList(this.getSelectedValue(newVal))
                },
                deep: true
            },
            mixinDatacomResData(newVal) {
                this.range = newVal
                this.dataList = this.getDataList(this.getSelectedValue(newVal))
            },
            value(newVal) {
                this.dataList = this.getDataList(newVal)
                // fix by mehaotian is_reset 在 uni-forms 中定义
                // if(!this.is_reset){
                //     this.is_reset = false
                //     this.formItem && this.formItem.setValue(newVal)
                // }
            },
            modelValue(newVal) {
                this.dataList = this.getDataList(newVal);
                // if(!this.is_reset){
                //     this.is_reset = false
                //     this.formItem && this.formItem.setValue(newVal)
                // }
            }
        },
        data() {
            return {
                dataList: [],
                range: [],
                contentText: {
                    contentdown: '查看更多',
                    contentrefresh: '加载中',
                    contentnomore: '没有更多'
                },
                isLocal: true,
                styles: {
                    selectedColor: '#2979ff',
                    selectedTextColor: '#666',
                },
                isTop: 0
            };
        },
        computed: {
            dataValue() {
                if (this.value === '') return this.modelValue
                if (this.modelValue === '') return this.value
                return this.value
            }
        },
        created() {
            // this.form = this.getForm('uniForms')
            // this.formItem = this.getForm('uniFormsItem')
            // this.formItem && this.formItem.setValue(this.value)
            // if (this.formItem) {
            //     this.isTop = 6
            //     if (this.formItem.name) {
            //         // 如果存在name添加默认值,否则formData 中不存在这个字段不校验
            //         if(!this.is_reset){
            //             this.is_reset = false
            //             this.formItem.setValue(this.dataValue)
            //         }
            //         this.rename = this.formItem.name
            //         this.form.inputChildrens.push(this)
            //     }
            // }
            if (this.localdata && this.localdata.length !== 0) {
                this.isLocal = true
                this.range = this.localdata
                this.dataList = this.getDataList(this.getSelectedValue(this.range))
            } else {
                if (this.collection) {
                    this.isLocal = false
                    this.loadData()
                }
            }
        },
        methods: {
            loadData() {
                this.mixinDatacomGet().then(res => {
                    this.mixinDatacomResData = res.result.data
                    if (this.mixinDatacomResData.length === 0) {
                        this.isLocal = false
                        this.mixinDatacomErrorMessage = this.emptyText
                    } else {
                        this.isLocal = true
                    }
                }).catch(err => {
                    this.mixinDatacomErrorMessage = err.message
                })
            },
            /**
             * 获取父元素实例
             */
            getForm(name = 'uniForms') {
                let parent = this.$parent;
                let parentName = parent.$options.name;
                while (parentName !== name) {
                    parent = parent.$parent;
                    if (!parent) return false
                    parentName = parent.$options.name;
                }
                return parent;
            },
            change(e) {
                const values = e.detail.value
                let detail = {
                    value: [],
                    data: []
                }
                if (this.multiple) {
                    this.range.forEach(item => {
                        if (values.includes(item[this.map.value] + '')) {
                            detail.value.push(item[this.map.value])
                            detail.data.push(item)
                        }
                    })
                } else {
                    const range = this.range.find(item => (item[this.map.value] + '') === values)
                    if (range) {
                        detail = {
                            value: range[this.map.value],
                            data: range
                        }
                    }
                }
                // this.formItem && this.formItem.setValue(detail.value)
                // TODO 兼容 vue2
                this.$emit('input', detail.value);
                // // TOTO 兼容 vue3
                this.$emit('update:modelValue', detail.value);
                this.$emit('change', {
                    detail
                })
                if (this.multiple) {
                    // 如果 v-model 没有绑定 ,则走内部逻辑
                    // if (this.value.length === 0) {
                    this.dataList = this.getDataList(detail.value, true)
                    // }
                } else {
                    this.dataList = this.getDataList(detail.value)
                }
            },
            /**
             * 获取渲染的新数组
             * @param {Object} value 选中内容
             */
            getDataList(value) {
                // 解除引用关系,破坏原引用关系,避免污染源数据
                let dataList = JSON.parse(JSON.stringify(this.range))
                let list = []
                if (this.multiple) {
                    if (!Array.isArray(value)) {
                        value = []
                    }
                }
                dataList.forEach((item, index) => {
                    item.disabled = item.disable || item.disabled || false
                    if (this.multiple) {
                        if (value.length > 0) {
                            let have = value.find(val => val === item[this.map.value])
                            item.selected = have !== undefined
                        } else {
                            item.selected = false
                        }
                    } else {
                        item.selected = value === item[this.map.value]
                    }
                    list.push(item)
                })
                return this.setRange(list)
            },
            /**
             * 处理最大最小值
             * @param {Object} list
             */
            setRange(list) {
                let selectList = list.filter(item => item.selected)
                let min = Number(this.min) || 0
                let max = Number(this.max) || ''
                list.forEach((item, index) => {
                    if (this.multiple) {
                        if (selectList.length <= min) {
                            let have = selectList.find(val => val[this.map.value] === item[this.map.value])
                            if (have !== undefined) {
                                item.disabled = true
                            }
                        }
                        if (selectList.length >= max && max !== '') {
                            let have = selectList.find(val => val[this.map.value] === item[this.map.value])
                            if (have === undefined) {
                                item.disabled = true
                            }
                        }
                    }
                    this.setStyles(item, index)
                    list[index] = item
                })
                return list
            },
            /**
             * 设置 class
             * @param {Object} item
             * @param {Object} index
             */
            setStyles(item, index) {
                //  设置自定义样式
                item.styleBackgroud = this.setStyleBackgroud(item)
                item.styleIcon = this.setStyleIcon(item)
                item.styleIconText = this.setStyleIconText(item)
                item.styleRightIcon = this.setStyleRightIcon(item)
            },
            /**
             * 获取选中值
             * @param {Object} range
             */
            getSelectedValue(range) {
                if (!this.multiple) return this.dataValue
                let selectedArr = []
                range.forEach((item) => {
                    if (item.selected) {
                        selectedArr.push(item[this.map.value])
                    }
                })
                return this.dataValue.length > 0 ? this.dataValue : selectedArr
            },
            /**
             * 设置背景样式
             */
            setStyleBackgroud(item) {
                let styles = {}
                let selectedColor = this.selectedColor ? this.selectedColor : '#2979ff'
                if (this.selectedColor) {
                    if (this.mode !== 'list') {
                        styles['border-color'] = item.selected ? selectedColor : '#DCDFE6'
                    }
                    if (this.mode === 'tag') {
                        styles['background-color'] = item.selected ? selectedColor : '#f5f5f5'
                    }
                }
                let classles = ''
                for (let i in styles) {
                    classles += `${i}:${styles[i]};`
                }
                return classles
            },
            setStyleIcon(item) {
                let styles = {}
                let classles = ''
                if (this.selectedColor) {
                    let selectedColor = this.selectedColor ? this.selectedColor : '#2979ff'
                    styles['background-color'] = item.selected ? selectedColor : '#fff'
                    styles['border-color'] = item.selected ? selectedColor : '#DCDFE6'
                    if (!item.selected && item.disabled) {
                        styles['background-color'] = '#F2F6FC'
                        styles['border-color'] = item.selected ? selectedColor : '#DCDFE6'
                    }
                }
                for (let i in styles) {
                    classles += `${i}:${styles[i]};`
                }
                return classles
            },
            setStyleIconText(item) {
                let styles = {}
                let classles = ''
                if (this.selectedColor) {
                    let selectedColor = this.selectedColor ? this.selectedColor : '#2979ff'
                    if (this.mode === 'tag') {
                        styles.color = item.selected ? (this.selectedTextColor ? this.selectedTextColor : '#fff') : '#666'
                    } else {
                        styles.color = item.selected ? (this.selectedTextColor ? this.selectedTextColor : selectedColor) : '#666'
                    }
                    if (!item.selected && item.disabled) {
                        styles.color = '#999'
                    }
                }
                for (let i in styles) {
                    classles += `${i}:${styles[i]};`
                }
                return classles
            },
            setStyleRightIcon(item) {
                let styles = {}
                let classles = ''
                if (this.mode === 'list') {
                    styles['border-color'] = item.selected ? this.styles.selectedColor : '#DCDFE6'
                }
                for (let i in styles) {
                    classles += `${i}:${styles[i]};`
                }
                return classles
            }
        }
    }
</script>
<style lang="scss">
    $uni-primary: #2979ff !default;
    $border-color: #DCDFE6;
    $disable: 0.4;
    @mixin flex {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
    }
    .uni-data-loading {
        @include flex;
        flex-direction: row;
        justify-content: center;
        align-items: center;
        height: 36px;
        padding-left: 10px;
        color: #999;
    }
    .uni-data-checklist {
        position: relative;
        z-index: 0;
        flex: 1;
        // 多选样式
        .checklist-group {
            @include flex;
            flex-direction: row;
            flex-wrap: wrap;
            &.is-list {
                flex-direction: column;
            }
            .checklist-box {
                @include flex;
                flex-direction: row;
                align-items: center;
                position: relative;
                margin: 5px 0;
                margin-right: 25px;
                .hidden {
                    position: absolute;
                    opacity: 0;
                }
                // 文字样式
                .checklist-content {
                    @include flex;
                    flex: 1;
                    flex-direction: row;
                    align-items: center;
                    justify-content: space-between;
                    .checklist-text {
                        font-size: 14px;
                        color: #666;
                        margin-left: 5px;
                        line-height: 14px;
                    }
                    .checkobx__list {
                        border-right-width: 1px;
                        border-right-color: #007aff;
                        border-right-style: solid;
                        border-bottom-width: 1px;
                        border-bottom-color: #007aff;
                        border-bottom-style: solid;
                        height: 12px;
                        width: 6px;
                        left: -5px;
                        transform-origin: center;
                        transform: rotate(45deg);
                        opacity: 0;
                    }
                }
                // 多选样式
                .checkbox__inner {
                    /* #ifndef APP-NVUE */
                    flex-shrink: 0;
                    box-sizing: border-box;
                    /* #endif */
                    position: relative;
                    width: 16px;
                    height: 16px;
                    border: 1px solid $border-color;
                    border-radius: 4px;
                    background-color: #fff;
                    z-index: 1;
                    .checkbox__inner-icon {
                        position: absolute;
                        /* #ifdef APP-NVUE */
                        top: 2px;
                        /* #endif */
                        /* #ifndef APP-NVUE */
                        top: 1px;
                        /* #endif */
                        left: 5px;
                        height: 8px;
                        width: 4px;
                        border-right-width: 1px;
                        border-right-color: #fff;
                        border-right-style: solid;
                        border-bottom-width: 1px;
                        border-bottom-color: #fff;
                        border-bottom-style: solid;
                        opacity: 0;
                        transform-origin: center;
                        transform: rotate(40deg);
                    }
                }
                // 单选样式
                .radio__inner {
                    @include flex;
                    /* #ifndef APP-NVUE */
                    flex-shrink: 0;
                    box-sizing: border-box;
                    /* #endif */
                    justify-content: center;
                    align-items: center;
                    position: relative;
                    width: 16px;
                    height: 16px;
                    border: 1px solid $border-color;
                    border-radius: 16px;
                    background-color: #fff;
                    z-index: 1;
                    .radio__inner-icon {
                        width: 8px;
                        height: 8px;
                        border-radius: 10px;
                        opacity: 0;
                    }
                }
                // 默认样式
                &.is--default {
                    // 禁用
                    &.is-disable {
                        /* #ifdef H5 */
                        cursor: not-allowed;
                        /* #endif */
                        .checkbox__inner {
                            background-color: #F2F6FC;
                            border-color: $border-color;
                            /* #ifdef H5 */
                            cursor: not-allowed;
                            /* #endif */
                        }
                        .radio__inner {
                            background-color: #F2F6FC;
                            border-color: $border-color;
                        }
                        .checklist-text {
                            color: #999;
                        }
                    }
                    // 选中
                    &.is-checked {
                        .checkbox__inner {
                            border-color: $uni-primary;
                            background-color: $uni-primary;
                            .checkbox__inner-icon {
                                opacity: 1;
                                transform: rotate(45deg);
                            }
                        }
                        .radio__inner {
                            border-color: $uni-primary;
                            .radio__inner-icon {
                                opacity: 1;
                                background-color: $uni-primary;
                            }
                        }
                        .checklist-text {
                            color: $uni-primary;
                        }
                        // 选中禁用
                        &.is-disable {
                            .checkbox__inner {
                                opacity: $disable;
                            }
                            .checklist-text {
                                opacity: $disable;
                            }
                            .radio__inner {
                                opacity: $disable;
                            }
                        }
                    }
                }
                // 按钮样式
                &.is--button {
                    margin-right: 10px;
                    padding: 5px 10px;
                    border: 1px $border-color solid;
                    border-radius: 3px;
                    transition: border-color 0.2s;
                    // 禁用
                    &.is-disable {
                        /* #ifdef H5 */
                        cursor: not-allowed;
                        /* #endif */
                        border: 1px #eee solid;
                        opacity: $disable;
                        .checkbox__inner {
                            background-color: #F2F6FC;
                            border-color: $border-color;
                            /* #ifdef H5 */
                            cursor: not-allowed;
                            /* #endif */
                        }
                        .radio__inner {
                            background-color: #F2F6FC;
                            border-color: $border-color;
                            /* #ifdef H5 */
                            cursor: not-allowed;
                            /* #endif */
                        }
                        .checklist-text {
                            color: #999;
                        }
                    }
                    &.is-checked {
                        border-color: $uni-primary;
                        .checkbox__inner {
                            border-color: $uni-primary;
                            background-color: $uni-primary;
                            .checkbox__inner-icon {
                                opacity: 1;
                                transform: rotate(45deg);
                            }
                        }
                        .radio__inner {
                            border-color: $uni-primary;
                            .radio__inner-icon {
                                opacity: 1;
                                background-color: $uni-primary;
                            }
                        }
                        .checklist-text {
                            color: $uni-primary;
                        }
                        // 选中禁用
                        &.is-disable {
                            opacity: $disable;
                        }
                    }
                }
                // 标签样式
                &.is--tag {
                    margin-right: 10px;
                    padding: 5px 10px;
                    border: 1px $border-color solid;
                    border-radius: 3px;
                    background-color: #f5f5f5;
                    .checklist-text {
                        margin: 0;
                        color: #666;
                    }
                    // 禁用
                    &.is-disable {
                        /* #ifdef H5 */
                        cursor: not-allowed;
                        /* #endif */
                        opacity: $disable;
                    }
                    &.is-checked {
                        background-color: $uni-primary;
                        border-color: $uni-primary;
                        .checklist-text {
                            color: #fff;
                        }
                    }
                }
                // 列表样式
                &.is--list {
                    /* #ifndef APP-NVUE */
                    display: flex;
                    /* #endif */
                    padding: 10px 15px;
                    padding-left: 0;
                    margin: 0;
                    &.is-list-border {
                        border-top: 1px #eee solid;
                    }
                    // 禁用
                    &.is-disable {
                        /* #ifdef H5 */
                        cursor: not-allowed;
                        /* #endif */
                        .checkbox__inner {
                            background-color: #F2F6FC;
                            border-color: $border-color;
                            /* #ifdef H5 */
                            cursor: not-allowed;
                            /* #endif */
                        }
                        .checklist-text {
                            color: #999;
                        }
                    }
                    &.is-checked {
                        .checkbox__inner {
                            border-color: $uni-primary;
                            background-color: $uni-primary;
                            .checkbox__inner-icon {
                                opacity: 1;
                                transform: rotate(45deg);
                            }
                        }
                        .radio__inner {
                            border-color: $uni-primary;
                            .radio__inner-icon {
                                opacity: 1;
                                background-color: $uni-primary;
                            }
                        }
                        .checklist-text {
                            color: $uni-primary;
                        }
                        .checklist-content {
                            .checkobx__list {
                                opacity: 1;
                                border-color: $uni-primary;
                            }
                        }
                        // 选中禁用
                        &.is-disable {
                            .checkbox__inner {
                                opacity: $disable;
                            }
                            .checklist-text {
                                opacity: $disable;
                            }
                        }
                    }
                }
            }
        }
    }
</style>
uni_modules/uni-data-checkbox/package.json
对比新文件
@@ -0,0 +1,84 @@
{
  "id": "uni-data-checkbox",
  "displayName": "uni-data-checkbox 数据选择器",
  "version": "1.0.5",
  "description": "通过数据驱动的单选框和复选框",
  "keywords": [
    "uni-ui",
    "checkbox",
    "单选",
    "多选",
    "单选多选"
],
  "repository": "https://github.com/dcloudio/uni-ui",
  "engines": {
    "HBuilderX": "^3.1.1"
  },
  "directories": {
    "example": "../../temps/example_temps"
  },
"dcloudext": {
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "无",
      "permissions": "无"
    },
    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
    "type": "component-vue"
  },
  "uni_modules": {
    "dependencies": ["uni-load-more","uni-scss"],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y"
      },
      "client": {
        "App": {
          "app-vue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        },
        "Vue": {
            "vue2": "y",
            "vue3": "y"
        }
      }
    }
  }
}
uni_modules/uni-data-checkbox/readme.md
对比新文件
@@ -0,0 +1,18 @@
## DataCheckbox 数据驱动的单选复选框
> **组件名:uni-data-checkbox**
> 代码块: `uDataCheckbox`
本组件是基于uni-app基础组件checkbox的封装。本组件要解决问题包括:
1. 数据绑定型组件:给本组件绑定一个data,会自动渲染一组候选内容。再以往,开发者需要编写不少代码实现类似功能
2. 自动的表单校验:组件绑定了data,且符合[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)组件的表单校验规范,搭配使用会自动实现表单校验
3. 本组件合并了单选多选
4. 本组件有若干风格选择,如普通的单选多选框、并列button风格、tag风格。开发者可以快速选择需要的风格。但作为一个封装组件,样式代码虽然不用自己写了,却会牺牲一定的样式自定义性
在uniCloud开发中,`DB Schema`中配置了enum枚举等类型后,在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
uni_modules/uni-data-picker/changelog.md
对比新文件
@@ -0,0 +1,79 @@
## 2.0.1(2024-08-22)
- 修复 uni-app-x v-model 没有更新传入值的 bug
## 2.0.0(2023-12-11)
- 新增 支持 uni-app-x
## 1.1.2(2023-04-11)
- 修复 更改 modelValue 报错的 bug
- 修复 v-for 未使用 key 值控制台 warning
## 1.1.1(2023-02-21)
- 修复代码合并时引发 value 属性为空时不渲染数据的问题
## 1.1.0(2023-02-15)
- 修复 localdata 不支持动态更新的bug
## 1.0.9(2023-02-15)
- 修复 localdata 不支持动态更新的bug
## 1.0.8(2022-09-16)
- 可以使用 uni-scss 控制主题色
## 1.0.7(2022-07-06)
- 优化 pc端图标位置不正确的问题
## 1.0.6(2022-07-05)
- 优化 显示样式
## 1.0.5(2022-07-04)
- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug
## 1.0.4(2022-04-19)
- 修复 字节小程序 本地数据无法选择下一级的Bug
## 1.0.3(2022-02-25)
- 修复 nvue 不支持的 v-show 的 bug
## 1.0.2(2022-02-25)
- 修复 条件编译 nvue 不支持的 css 样式
## 1.0.1(2021-11-23)
- 修复 由上个版本引发的map、v-model等属性不生效的bug
## 1.0.0(2021-11-19)
- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-picker](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
## 0.4.9(2021-10-28)
- 修复 VUE2 v-model 概率无效的 bug
## 0.4.8(2021-10-27)
- 修复 v-model 概率无效的 bug
## 0.4.7(2021-10-25)
- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+
- 修复 树型 uniCloud 数据类型为 int 时报错的 bug
## 0.4.6(2021-10-19)
- 修复 非 VUE3 v-model 为 0 时无法选中的 bug
## 0.4.5(2021-09-26)
- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效
- 修复 readonly 为 true 时报错的 bug
## 0.4.4(2021-09-26)
- 修复 上一版本造成的 map 属性失效的 bug
- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略
## 0.4.3(2021-09-24)
- 修复 某些情况下级联未触发的 bug
## 0.4.2(2021-09-23)
- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用
- 新增 选项内容过长自动添加省略号
## 0.4.1(2021-09-15)
- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段
## 0.4.0(2021-07-13)
- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.3.5(2021-06-04)
- 修复 无法加载云端数据的问题
## 0.3.4(2021-05-28)
- 修复 v-model 无效问题
- 修复 loaddata 为空数据组时加载时间过长问题
- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点
## 0.3.3(2021-05-12)
- 新增 组件示例地址
## 0.3.2(2021-04-22)
- 修复 非树形数据有 where 属性查询报错的问题
## 0.3.1(2021-04-15)
- 修复 本地数据概率无法回显时问题
## 0.3.0(2021-04-07)
- 新增 支持云端非树形表结构数据
- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题
## 0.2.0(2021-03-15)
- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题
## 0.1.9(2021-03-09)
- 修复 微信小程序某些情况下无法选择的问题
## 0.1.8(2021-02-05)
- 优化 部分样式在 nvue 上的兼容表现
## 0.1.7(2021-02-05)
- 调整为 uni_modules 目录规范
uni_modules/uni-data-picker/components/uni-data-picker/keypress.js
对比新文件
@@ -0,0 +1,45 @@
// #ifdef H5
export default {
  name: 'Keypress',
  props: {
    disable: {
      type: Boolean,
      default: false
    }
  },
  mounted () {
    const keyNames = {
      esc: ['Esc', 'Escape'],
      tab: 'Tab',
      enter: 'Enter',
      space: [' ', 'Spacebar'],
      up: ['Up', 'ArrowUp'],
      left: ['Left', 'ArrowLeft'],
      right: ['Right', 'ArrowRight'],
      down: ['Down', 'ArrowDown'],
      delete: ['Backspace', 'Delete', 'Del']
    }
    const listener = ($event) => {
      if (this.disable) {
        return
      }
      const keyName = Object.keys(keyNames).find(key => {
        const keyName = $event.key
        const value = keyNames[key]
        return value === keyName || (Array.isArray(value) && value.includes(keyName))
      })
      if (keyName) {
        // 避免和其他按键事件冲突
        setTimeout(() => {
          this.$emit(keyName, {})
        }, 0)
      }
    }
    document.addEventListener('keyup', listener)
    this.$once('hook:beforeDestroy', () => {
      document.removeEventListener('keyup', listener)
    })
  },
    render: () => {}
}
// #endif
uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.uvue
对比新文件
@@ -0,0 +1,381 @@
<template>
  <view class="uni-data-tree">
    <view class="uni-data-tree-input" @click="handleInput">
      <slot :data="selectedPaths" :error="error">
        <view class="input-value" :class="{'input-value-border': border}">
          <text v-if="error!=null" class="error-text">{{error!.errMsg}}</text>
          <scroll-view v-if="selectedPaths.length" class="selected-path" scroll-x="true">
            <view class="selected-list">
              <template v-for="(item, index) in selectedPaths">
                <text class="text-color">{{item[mappingTextName]}}</text>
                <text v-if="index<selectedPaths.length-1" class="input-split-line">{{split}}</text>
              </template>
            </view>
          </scroll-view>
          <text v-else-if="error==null&&!loading" class="placeholder">{{placeholder}}</text>
          <view v-if="!readonly" class="arrow-area">
            <view class="input-arrow"></view>
          </view>
        </view>
      </slot>
      <view v-if="loading && !isOpened" class="selected-loading">
        <slot name="picker-loading" :loading="loading"></slot>
      </view>
    </view>
    <view class="uni-data-tree-cover" v-if="isOpened" @click="handleClose"></view>
    <view class="uni-data-tree-dialog" v-if="isOpened">
      <view class="uni-popper__arrow"></view>
      <view class="dialog-caption">
        <view class="dialog-title-view">
          <text class="dialog-title">{{popupTitle}}</text>
        </view>
        <view class="dialog-close" @click="handleClose">
          <view class="dialog-close-plus" data-id="close"></view>
          <view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
        </view>
      </view>
      <view ref="pickerView" class="uni-data-pickerview">
        <view v-if="error!=null" class="error">
          <text class="error-text">{{error!.errMsg}}</text>
        </view>
        <scroll-view v-if="!isCloudDataList" :scroll-x="true">
          <view class="selected-node-list">
            <template v-for="(item, index) in selectedNodes">
              <text class="selected-node-item" :class="{'selected-node-item-active':index==selectedIndex}"
                @click="onTabSelect(index)">
                {{item[mappingTextName]}}
              </text>
            </template>
          </view>
        </scroll-view>
        <list-view class="list-view" :scroll-y="true">
          <list-item class="list-item" v-for="(item, _) in currentDataList" @click="onNodeClick(item)">
            <text class="item-text" :class="{'item-text-disabled': item['disable']}">{{item[mappingTextName]}}</text>
            <text class="check" v-if="item[mappingValueName] == selectedNodes[selectedIndex][mappingValueName]"></text>
          </list-item>
        </list-view>
        <view class="loading-cover" v-if="loading">
          <slot name="pickerview-loading" :loading="loading"></slot>
        </view>
      </view>
    </view>
  </view>
</template>
<script>
  import { dataPicker } from "../uni-data-pickerview/uni-data-picker.uts"
  /**
   * DataPicker 级联选择
   * @description 支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
   * @tutorial https://ext.dcloud.net.cn/plugin?id=3796
   * @property {String} popup-title 弹出窗口标题
   * @property {Array} localdata 本地数据,参考
   * @property {Boolean} border = [true|false] 是否有边框
   * @property {Boolean} readonly = [true|false] 是否仅读
   * @property {Boolean} preload = [true|false] 是否预加载数据
   * @value true 开启预加载数据,点击弹出窗口后显示已加载数据
   * @value false 关闭预加载数据,点击弹出窗口后开始加载数据
   * @property {Boolean} step-searh = [true|false] 是否分布查询
   * @value true 启用分布查询,仅查询当前选中节点
   * @value false 关闭分布查询,一次查询出所有数据
   * @property {String|DBFieldString} self-field 分布查询当前字段名称
   * @property {String|DBFieldString} parent-field 分布查询父字段名称
   * @property {String|DBCollectionString} collection 表名
   * @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
   * @property {String} orderby 排序字段及正序倒叙设置
   * @property {String|JQLString} where 查询条件
   * @event {Function} popupshow 弹出的选择窗口打开时触发此事件
   * @event {Function} popuphide 弹出的选择窗口关闭时触发此事件
   */
  export default {
    name: 'UniDataPicker',
    emits: ['popupopened', 'popupclosed', 'nodeclick', 'change', 'input', 'update:modelValue', 'inputclick'],
    mixins: [dataPicker],
    props: {
      popupTitle: {
        type: String,
        default: '请选择'
      },
      placeholder: {
        type: String,
        default: '请选择'
      },
      heightMobile: {
        type: String,
        default: ''
      },
      readonly: {
        type: Boolean,
        default: false
      },
      clearIcon: {
        type: Boolean,
        default: true
      },
      border: {
        type: Boolean,
        default: true
      },
      split: {
        type: String,
        default: '/'
      },
      ellipsis: {
        type: Boolean,
        default: true
      }
    },
    data() {
      return {
        isOpened: false
      }
    },
    computed: {
      isShowClearIcon() : boolean {
        if (this.readonly) {
          return false
        }
        if (this.clearIcon && this.selectedPaths.length > 0) {
          return true
        }
        return false
      }
    },
    created() {
      this.load()
    },
    methods: {
      clear() {
      },
      load() {
        if (this.isLocalData) {
          this.loadLocalData()
        } else if (this.isCloudDataList || this.isCloudDataTree) {
          this.loadCloudDataPath()
        }
      },
      show() {
        this.isOpened = true
        this.$emit('popupopened')
        if (!this.hasCloudTreeData) {
          this.loadData()
        }
      },
      hide() {
        this.isOpened = false
        this.$emit('popupclosed')
      },
      handleInput() {
        if (this.readonly) {
          this.$emit('inputclick')
        } else {
          this.show()
        }
      },
      handleClose() {
        this.hide()
      },
      onFinish() {
        this.selectedPaths = this.getChangeNodes()
        this.$emit('update:modelValue', this.selectedPaths)
        this.$emit('change', this.selectedPaths)
        this.hide()
      }
    }
  }
</script>
<style>
  @import url("../uni-data-pickerview/uni-data-pickerview.css");
  .uni-data-tree {
    position: relative;
  }
  .uni-data-tree-input {
    position: relative;
  }
  .selected-loading {
    display: flex;
    justify-content: center;
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
  }
  .error-text {
    flex: 1;
    font-size: 12px;
    color: #DD524D;
  }
  .input-value {
    flex-direction: row;
    align-items: center;
    flex-wrap: nowrap;
    padding: 5px 5px;
    padding-right: 5px;
    overflow: hidden;
    min-height: 28px;
  }
  .input-value-border {
    border: 1px solid #e5e5e5;
    border-radius: 5px;
  }
  .selected-path {
    flex: 1;
    flex-direction: row;
    overflow: hidden;
  }
  .load-more {
    width: 40px;
  }
  .selected-list {
    flex-direction: row;
    flex-wrap: nowrap;
  }
  .selected-item {
    flex-direction: row;
    flex-wrap: nowrap;
  }
  .text-color {
    font-size: 14px;
    color: #333;
  }
  .placeholder {
    color: grey;
    font-size: 14px;
  }
  .input-split-line {
    opacity: .5;
    margin-left: 1px;
    margin-right: 1px;
  }
  .arrow-area {
    position: relative;
    padding: 0 12px;
    margin-left: auto;
    justify-content: center;
    transform: rotate(-45deg);
    transform-origin: center;
  }
  .input-arrow {
    width: 8px;
    height: 8px;
    border-left: 2px solid #999;
    border-bottom: 2px solid #999;
  }
  .uni-data-tree-cover {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, .4);
    flex-direction: column;
    z-index: 100;
  }
  .uni-data-tree-dialog {
    position: fixed;
    left: 0;
    top: 20%;
    right: 0;
    bottom: 0;
    background-color: #FFFFFF;
    border-top-left-radius: 10px;
    border-top-right-radius: 10px;
    flex-direction: column;
    z-index: 102;
    overflow: hidden;
  }
  .dialog-caption {
    position: relative;
    flex-direction: row;
  }
  .dialog-title-view {
    flex: 1;
  }
  .dialog-title {
    align-self: center;
    padding: 0 10px;
    line-height: 44px;
  }
  .dialog-close {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    flex-direction: row;
    align-items: center;
    padding: 0 15px;
  }
  .dialog-close-plus {
    width: 16px;
    height: 2px;
    background-color: #666;
    border-radius: 2px;
    transform: rotate(45deg);
  }
  .dialog-close-rotate {
    position: absolute;
    transform: rotate(-45deg);
  }
  .uni-data-pickerview {
    flex: 1;
  }
  .icon-clear {
    display: flex;
    align-items: center;
  }
  /* #ifdef H5 */
  @media all and (min-width: 768px) {
    .uni-data-tree-cover {
      background-color: transparent;
    }
    .uni-data-tree-dialog {
      position: absolute;
      top: 55px;
      height: auto;
      min-height: 400px;
      max-height: 50vh;
      background-color: #fff;
      border: 1px solid #EBEEF5;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      border-radius: 4px;
      overflow: unset;
    }
    .dialog-caption {
      display: none;
    }
  }
  /* #endif */
</style>
uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue
对比新文件
@@ -0,0 +1,551 @@
<template>
  <view class="uni-data-tree">
    <view class="uni-data-tree-input" @click="handleInput">
      <slot :options="options" :data="inputSelected" :error="errorMessage">
        <view class="input-value" :class="{'input-value-border': border}">
          <text v-if="errorMessage" class="selected-area error-text">{{errorMessage}}</text>
          <view v-else-if="loading && !isOpened" class="selected-area">
            <uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
          </view>
          <scroll-view v-else-if="inputSelected.length" class="selected-area" scroll-x="true">
            <view class="selected-list">
              <view class="selected-item" v-for="(item,index) in inputSelected" :key="index">
                <text class="text-color">{{item.text}}</text><text v-if="index<inputSelected.length-1"
                  class="input-split-line">{{split}}</text>
              </view>
            </view>
          </scroll-view>
          <text v-else class="selected-area placeholder">{{placeholder}}</text>
          <view v-if="clearIcon && !readonly && inputSelected.length" class="icon-clear" @click.stop="clear">
            <uni-icons type="clear" color="#c0c4cc" size="24"></uni-icons>
          </view>
          <view class="arrow-area" v-if="(!clearIcon || !inputSelected.length) && !readonly ">
            <view class="input-arrow"></view>
          </view>
        </view>
      </slot>
    </view>
    <view class="uni-data-tree-cover" v-if="isOpened" @click="handleClose"></view>
    <view class="uni-data-tree-dialog" v-if="isOpened">
      <view class="uni-popper__arrow"></view>
      <view class="dialog-caption">
        <view class="title-area">
          <text class="dialog-title">{{popupTitle}}</text>
        </view>
        <view class="dialog-close" @click="handleClose">
          <view class="dialog-close-plus" data-id="close"></view>
          <view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
        </view>
      </view>
      <data-picker-view class="picker-view" ref="pickerView" v-model="dataValue" :localdata="localdata"
        :preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where"
        :step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true" :map="map"
        :ellipsis="ellipsis" @change="onchange" @datachange="ondatachange" @nodeclick="onnodeclick">
      </data-picker-view>
    </view>
  </view>
</template>
<script>
  import dataPicker from "../uni-data-pickerview/uni-data-picker.js"
  import DataPickerView from "../uni-data-pickerview/uni-data-pickerview.vue"
  /**
   * DataPicker 级联选择
   * @description 支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
   * @tutorial https://ext.dcloud.net.cn/plugin?id=3796
   * @property {String} popup-title 弹出窗口标题
   * @property {Array} localdata 本地数据,参考
   * @property {Boolean} border = [true|false] 是否有边框
   * @property {Boolean} readonly = [true|false] 是否仅读
   * @property {Boolean} preload = [true|false] 是否预加载数据
   * @value true 开启预加载数据,点击弹出窗口后显示已加载数据
   * @value false 关闭预加载数据,点击弹出窗口后开始加载数据
   * @property {Boolean} step-searh = [true|false] 是否分布查询
   * @value true 启用分布查询,仅查询当前选中节点
   * @value false 关闭分布查询,一次查询出所有数据
   * @property {String|DBFieldString} self-field 分布查询当前字段名称
   * @property {String|DBFieldString} parent-field 分布查询父字段名称
   * @property {String|DBCollectionString} collection 表名
   * @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
   * @property {String} orderby 排序字段及正序倒叙设置
   * @property {String|JQLString} where 查询条件
   * @event {Function} popupshow 弹出的选择窗口打开时触发此事件
   * @event {Function} popuphide 弹出的选择窗口关闭时触发此事件
   */
  export default {
    name: 'UniDataPicker',
    emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change', 'update:modelValue','inputclick'],
    mixins: [dataPicker],
    components: {
      DataPickerView
    },
    props: {
      options: {
        type: [Object, Array],
        default () {
          return {}
        }
      },
      popupTitle: {
        type: String,
        default: '请选择'
      },
      placeholder: {
        type: String,
        default: '请选择'
      },
      heightMobile: {
        type: String,
        default: ''
      },
      readonly: {
        type: Boolean,
        default: false
      },
      clearIcon: {
        type: Boolean,
        default: true
      },
      border: {
        type: Boolean,
        default: true
      },
      split: {
        type: String,
        default: '/'
      },
      ellipsis: {
        type: Boolean,
        default: true
      }
    },
    data() {
      return {
        isOpened: false,
        inputSelected: []
      }
    },
    created() {
      this.$nextTick(() => {
        this.load();
      })
    },
    watch: {
            localdata: {
                handler() {
                    this.load()
                },
        deep: true
            },
    },
    methods: {
      clear() {
        this._dispatchEvent([]);
      },
      onPropsChange() {
        this._treeData = [];
        this.selectedIndex = 0;
        this.load();
      },
      load() {
        if (this.readonly) {
          this._processReadonly(this.localdata, this.dataValue);
          return;
        }
        // 回显本地数据
        if (this.isLocalData) {
          this.loadData();
          this.inputSelected = this.selected.slice(0);
        } else if (this.isCloudDataList || this.isCloudDataTree) { // 回显 Cloud 数据
          this.loading = true;
          this.getCloudDataValue().then((res) => {
            this.loading = false;
            this.inputSelected = res;
          }).catch((err) => {
            this.loading = false;
            this.errorMessage = err;
          })
        }
      },
      show() {
        this.isOpened = true
        setTimeout(() => {
          this.$refs.pickerView.updateData({
            treeData: this._treeData,
            selected: this.selected,
            selectedIndex: this.selectedIndex
          })
        }, 200)
        this.$emit('popupopened')
      },
      hide() {
        this.isOpened = false
        this.$emit('popupclosed')
      },
      handleInput() {
        if (this.readonly) {
                    this.$emit('inputclick')
          return
        }
        this.show()
      },
      handleClose(e) {
        this.hide()
      },
      onnodeclick(e) {
        this.$emit('nodeclick', e)
      },
      ondatachange(e) {
        this._treeData = this.$refs.pickerView._treeData
      },
      onchange(e) {
        this.hide()
        this.$nextTick(() => {
          this.inputSelected = e;
        })
        this._dispatchEvent(e)
      },
      _processReadonly(dataList, value) {
        var isTree = dataList.findIndex((item) => {
          return item.children
        })
        if (isTree > -1) {
          let inputValue
          if (Array.isArray(value)) {
            inputValue = value[value.length - 1]
            if (typeof inputValue === 'object' && inputValue.value) {
              inputValue = inputValue.value
            }
          } else {
            inputValue = value
          }
          this.inputSelected = this._findNodePath(inputValue, this.localdata)
          return
        }
        if (!this.hasValue) {
          this.inputSelected = []
          return
        }
        let result = []
        for (let i = 0; i < value.length; i++) {
          var val = value[i]
          var item = dataList.find((v) => {
            return v.value == val
          })
          if (item) {
            result.push(item)
          }
        }
        if (result.length) {
          this.inputSelected = result
        }
      },
      _filterForArray(data, valueArray) {
        var result = []
        for (let i = 0; i < valueArray.length; i++) {
          var value = valueArray[i]
          var found = data.find((item) => {
            return item.value == value
          })
          if (found) {
            result.push(found)
          }
        }
        return result
      },
      _dispatchEvent(selected) {
        let item = {}
        if (selected.length) {
          var value = new Array(selected.length)
          for (var i = 0; i < selected.length; i++) {
            value[i] = selected[i].value
          }
          item = selected[selected.length - 1]
        } else {
          item.value = ''
        }
        if (this.formItem) {
          this.formItem.setValue(item.value)
        }
        this.$emit('input', item.value)
        this.$emit('update:modelValue', item.value)
        this.$emit('change', {
          detail: {
            value: selected
          }
        })
      }
    }
  }
</script>
<style>
  .uni-data-tree {
    flex: 1;
    position: relative;
    font-size: 14px;
  }
  .error-text {
    color: #DD524D;
  }
  .input-value {
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: row;
    align-items: center;
    flex-wrap: nowrap;
    font-size: 14px;
    /* line-height: 35px; */
    padding: 0 10px;
    padding-right: 5px;
    overflow: hidden;
    height: 35px;
    /* #ifndef APP-NVUE */
    box-sizing: border-box;
    /* #endif */
  }
  .input-value-border {
    border: 1px solid #e5e5e5;
    border-radius: 5px;
  }
  .selected-area {
    flex: 1;
    overflow: hidden;
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: row;
  }
  .load-more {
    /* #ifndef APP-NVUE */
    margin-right: auto;
    /* #endif */
    /* #ifdef APP-NVUE */
    width: 40px;
    /* #endif */
  }
  .selected-list {
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: row;
    flex-wrap: nowrap;
    /* padding: 0 5px; */
  }
  .selected-item {
    flex-direction: row;
    /* padding: 0 1px; */
    /* #ifndef APP-NVUE */
    white-space: nowrap;
    /* #endif */
  }
  .text-color {
    color: #333;
  }
  .placeholder {
    color: grey;
    font-size: 12px;
  }
  .input-split-line {
    opacity: .5;
  }
  .arrow-area {
    position: relative;
    width: 20px;
    /* #ifndef APP-NVUE */
    margin-bottom: 5px;
    margin-left: auto;
    display: flex;
    /* #endif */
    justify-content: center;
    transform: rotate(-45deg);
    transform-origin: center;
  }
  .input-arrow {
    width: 7px;
    height: 7px;
    border-left: 1px solid #999;
    border-bottom: 1px solid #999;
  }
  .uni-data-tree-cover {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, .4);
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: column;
    z-index: 100;
  }
  .uni-data-tree-dialog {
    position: fixed;
    left: 0;
    /* #ifndef APP-NVUE */
    top: 20%;
    /* #endif */
    /* #ifdef APP-NVUE */
    top: 200px;
    /* #endif */
    right: 0;
    bottom: 0;
    background-color: #FFFFFF;
    border-top-left-radius: 10px;
    border-top-right-radius: 10px;
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: column;
    z-index: 102;
    overflow: hidden;
    /* #ifdef APP-NVUE */
    width: 750rpx;
    /* #endif */
  }
  .dialog-caption {
    position: relative;
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: row;
    /* border-bottom: 1px solid #f0f0f0; */
  }
  .title-area {
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    align-items: center;
    /* #ifndef APP-NVUE */
    margin: auto;
    /* #endif */
    padding: 0 10px;
  }
  .dialog-title {
    /* font-weight: bold; */
    line-height: 44px;
  }
  .dialog-close {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: row;
    align-items: center;
    padding: 0 15px;
  }
  .dialog-close-plus {
    width: 16px;
    height: 2px;
    background-color: #666;
    border-radius: 2px;
    transform: rotate(45deg);
  }
  .dialog-close-rotate {
    position: absolute;
    transform: rotate(-45deg);
  }
  .picker-view {
    flex: 1;
    overflow: hidden;
  }
  .icon-clear {
    display: flex;
    align-items: center;
  }
  /* #ifdef H5 */
  @media all and (min-width: 768px) {
    .uni-data-tree-cover {
      background-color: transparent;
    }
    .uni-data-tree-dialog {
      position: absolute;
      top: 55px;
      height: auto;
      min-height: 400px;
      max-height: 50vh;
      background-color: #fff;
      border: 1px solid #EBEEF5;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      border-radius: 4px;
      overflow: unset;
    }
    .dialog-caption {
      display: none;
    }
    .icon-clear {
      /* margin-right: 5px; */
    }
  }
  /* #endif */
  /* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */
  /* #ifndef APP-NVUE */
  .uni-popper__arrow,
  .uni-popper__arrow::after {
    position: absolute;
    display: block;
    width: 0;
    height: 0;
    border-color: transparent;
    border-style: solid;
    border-width: 6px;
  }
  .uni-popper__arrow {
    filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
    top: -6px;
    left: 10%;
    margin-right: 3px;
    border-top-width: 0;
    border-bottom-color: #EBEEF5;
  }
  .uni-popper__arrow::after {
    content: " ";
    top: 1px;
    margin-left: -6px;
    border-top-width: 0;
    border-bottom-color: #fff;
  }
  /* #endif */
</style>
uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js
对比新文件
@@ -0,0 +1,622 @@
export default {
  props: {
    localdata: {
      type: [Array, Object],
      default () {
        return []
      }
    },
    spaceInfo: {
      type: Object,
      default () {
        return {}
      }
    },
    collection: {
      type: String,
      default: ''
    },
    action: {
      type: String,
      default: ''
    },
    field: {
      type: String,
      default: ''
    },
    orderby: {
      type: String,
      default: ''
    },
    where: {
      type: [String, Object],
      default: ''
    },
    pageData: {
      type: String,
      default: 'add'
    },
    pageCurrent: {
      type: Number,
      default: 1
    },
    pageSize: {
      type: Number,
      default: 500
    },
    getcount: {
      type: [Boolean, String],
      default: false
    },
    getone: {
      type: [Boolean, String],
      default: false
    },
    gettree: {
      type: [Boolean, String],
      default: false
    },
    manual: {
      type: Boolean,
      default: false
    },
    value: {
      type: [Array, String, Number],
      default () {
        return []
      }
    },
    modelValue: {
      type: [Array, String, Number],
      default () {
        return []
      }
    },
    preload: {
      type: Boolean,
      default: false
    },
    stepSearh: {
      type: Boolean,
      default: true
    },
    selfField: {
      type: String,
      default: ''
    },
    parentField: {
      type: String,
      default: ''
    },
    multiple: {
      type: Boolean,
      default: false
    },
    map: {
      type: Object,
      default () {
        return {
          text: "text",
          value: "value"
        }
      }
    }
  },
  data() {
    return {
      loading: false,
      errorMessage: '',
      loadMore: {
        contentdown: '',
        contentrefresh: '',
        contentnomore: ''
      },
      dataList: [],
      selected: [],
      selectedIndex: 0,
      page: {
        current: this.pageCurrent,
        size: this.pageSize,
        count: 0
      }
    }
  },
  computed: {
    isLocalData() {
      return !this.collection.length;
    },
    isCloudData() {
      return this.collection.length > 0;
    },
    isCloudDataList() {
      return (this.isCloudData && (!this.parentField && !this.selfField));
    },
    isCloudDataTree() {
      return (this.isCloudData && this.parentField && this.selfField);
    },
    dataValue() {
      let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null ||
        this.modelValue !== undefined);
      return isModelValue ? this.modelValue : this.value;
    },
    hasValue() {
      if (typeof this.dataValue === 'number') {
        return true
      }
      return (this.dataValue != null) && (this.dataValue.length > 0)
    }
  },
  created() {
    this.$watch(() => {
      var al = [];
      ['pageCurrent',
        'pageSize',
        'spaceInfo',
        'value',
        'modelValue',
        'localdata',
        'collection',
        'action',
        'field',
        'orderby',
        'where',
        'getont',
        'getcount',
        'gettree'
      ].forEach(key => {
        al.push(this[key])
      });
      return al
    }, (newValue, oldValue) => {
      let needReset = false
      for (let i = 2; i < newValue.length; i++) {
        if (newValue[i] != oldValue[i]) {
          needReset = true
          break
        }
      }
      if (newValue[0] != oldValue[0]) {
        this.page.current = this.pageCurrent
      }
      this.page.size = this.pageSize
      this.onPropsChange()
    })
    this._treeData = []
  },
  methods: {
    onPropsChange() {
      this._treeData = [];
    },
    // 填充 pickview 数据
    async loadData() {
      if (this.isLocalData) {
        this.loadLocalData();
      } else if (this.isCloudDataList) {
        this.loadCloudDataList();
      } else if (this.isCloudDataTree) {
        this.loadCloudDataTree();
      }
    },
    // 加载本地数据
    async loadLocalData() {
      this._treeData = [];
      this._extractTree(this.localdata, this._treeData);
      let inputValue = this.dataValue;
      if (inputValue === undefined) {
        return;
      }
      if (Array.isArray(inputValue)) {
        inputValue = inputValue[inputValue.length - 1];
        if (typeof inputValue === 'object' && inputValue[this.map.value]) {
          inputValue = inputValue[this.map.value];
        }
      }
      this.selected = this._findNodePath(inputValue, this.localdata);
    },
    // 加载 Cloud 数据 (单列)
    async loadCloudDataList() {
      if (this.loading) {
        return;
      }
      this.loading = true;
      try {
        let response = await this.getCommand();
        let responseData = response.result.data;
        this._treeData = responseData;
        this._updateBindData();
        this._updateSelected();
        this.onDataChange();
      } catch (e) {
        this.errorMessage = e;
      } finally {
        this.loading = false;
      }
    },
    // 加载 Cloud 数据 (树形)
    async loadCloudDataTree() {
      if (this.loading) {
        return;
      }
      this.loading = true;
      try {
        let commandOptions = {
          field: this._cloudDataPostField(),
          where: this._cloudDataTreeWhere()
        };
        if (this.gettree) {
          commandOptions.startwith = `${this.selfField}=='${this.dataValue}'`;
        }
        let response = await this.getCommand(commandOptions);
        let responseData = response.result.data;
        this._treeData = responseData;
        this._updateBindData();
        this._updateSelected();
        this.onDataChange();
      } catch (e) {
        this.errorMessage = e;
      } finally {
        this.loading = false;
      }
    },
    // 加载 Cloud 数据 (节点)
    async loadCloudDataNode(callback) {
      if (this.loading) {
        return;
      }
      this.loading = true;
      try {
        let commandOptions = {
          field: this._cloudDataPostField(),
          where: this._cloudDataNodeWhere()
        };
        let response = await this.getCommand(commandOptions);
        let responseData = response.result.data;
        callback(responseData);
      } catch (e) {
        this.errorMessage = e;
      } finally {
        this.loading = false;
      }
    },
    // 回显 Cloud 数据
    getCloudDataValue() {
      if (this.isCloudDataList) {
        return this.getCloudDataListValue();
      }
      if (this.isCloudDataTree) {
        return this.getCloudDataTreeValue();
      }
    },
    // 回显 Cloud 数据 (单列)
    getCloudDataListValue() {
      // 根据 field's as value标识匹配 where 条件
      let where = [];
      let whereField = this._getForeignKeyByField();
      if (whereField) {
        where.push(`${whereField} == '${this.dataValue}'`)
      }
      where = where.join(' || ');
      if (this.where) {
        where = `(${this.where}) && (${where})`
      }
      return this.getCommand({
        field: this._cloudDataPostField(),
        where
      }).then((res) => {
        this.selected = res.result.data;
        return res.result.data;
      });
    },
    // 回显 Cloud 数据 (树形)
    getCloudDataTreeValue() {
      return this.getCommand({
        field: this._cloudDataPostField(),
        getTreePath: {
          startWith: `${this.selfField}=='${this.dataValue}'`
        }
      }).then((res) => {
        let treePath = [];
        this._extractTreePath(res.result.data, treePath);
        this.selected = treePath;
        return treePath;
      });
    },
    getCommand(options = {}) {
      /* eslint-disable no-undef */
      let db = uniCloud.database(this.spaceInfo)
      const action = options.action || this.action
      if (action) {
        db = db.action(action)
      }
      const collection = options.collection || this.collection
      db = db.collection(collection)
      const where = options.where || this.where
      if (!(!where || !Object.keys(where).length)) {
        db = db.where(where)
      }
      const field = options.field || this.field
      if (field) {
        db = db.field(field)
      }
      const orderby = options.orderby || this.orderby
      if (orderby) {
        db = db.orderBy(orderby)
      }
      const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current
      const size = options.pageSize !== undefined ? options.pageSize : this.page.size
      const getCount = options.getcount !== undefined ? options.getcount : this.getcount
      const getTree = options.gettree !== undefined ? options.gettree : this.gettree
      const getOptions = {
        getCount,
        getTree
      }
      if (options.getTreePath) {
        getOptions.getTreePath = options.getTreePath
      }
      db = db.skip(size * (current - 1)).limit(size).get(getOptions)
      return db
    },
    _cloudDataPostField() {
      let fields = [this.field];
      if (this.parentField) {
        fields.push(`${this.parentField} as parent_value`);
      }
      return fields.join(',');
    },
    _cloudDataTreeWhere() {
      let result = []
      let selected = this.selected
      let parentField = this.parentField
      if (parentField) {
        result.push(`${parentField} == null || ${parentField} == ""`)
      }
      if (selected.length) {
        for (var i = 0; i < selected.length - 1; i++) {
          result.push(`${parentField} == '${selected[i].value}'`)
        }
      }
      let where = []
      if (this.where) {
        where.push(`(${this.where})`)
      }
      if (result.length) {
        where.push(`(${result.join(' || ')})`)
      }
      return where.join(' && ')
    },
    _cloudDataNodeWhere() {
      let where = []
      let selected = this.selected;
      if (selected.length) {
        where.push(`${this.parentField} == '${selected[selected.length - 1].value}'`);
      }
      where = where.join(' || ');
      if (this.where) {
        return `(${this.where}) && (${where})`
      }
      return where
    },
    _getWhereByForeignKey() {
      let result = []
      let whereField = this._getForeignKeyByField();
      if (whereField) {
        result.push(`${whereField} == '${this.dataValue}'`)
      }
      if (this.where) {
        return `(${this.where}) && (${result.join(' || ')})`
      }
      return result.join(' || ')
    },
    _getForeignKeyByField() {
      let fields = this.field.split(',');
      let whereField = null;
      for (let i = 0; i < fields.length; i++) {
        const items = fields[i].split('as');
        if (items.length < 2) {
          continue;
        }
        if (items[1].trim() === 'value') {
          whereField = items[0].trim();
          break;
        }
      }
      return whereField;
    },
    _updateBindData(node) {
      const {
        dataList,
        hasNodes
      } = this._filterData(this._treeData, this.selected)
      let isleaf = this._stepSearh === false && !hasNodes
      if (node) {
        node.isleaf = isleaf
      }
      this.dataList = dataList
      this.selectedIndex = dataList.length - 1
      if (!isleaf && this.selected.length < dataList.length) {
        this.selected.push({
          value: null,
          text: "请选择"
        })
      }
      return {
        isleaf,
        hasNodes
      }
    },
    _updateSelected() {
      let dl = this.dataList
      let sl = this.selected
      let textField = this.map.text
      let valueField = this.map.value
      for (let i = 0; i < sl.length; i++) {
        let value = sl[i].value
        let dl2 = dl[i]
        for (let j = 0; j < dl2.length; j++) {
          let item2 = dl2[j]
          if (item2[valueField] === value) {
            sl[i].text = item2[textField]
            break
          }
        }
      }
    },
    _filterData(data, paths) {
      let dataList = []
      let hasNodes = true
      dataList.push(data.filter((item) => {
        return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '')
      }))
      for (let i = 0; i < paths.length; i++) {
        let value = paths[i].value
        let nodes = data.filter((item) => {
          return item.parent_value === value
        })
        if (nodes.length) {
          dataList.push(nodes)
        } else {
          hasNodes = false
        }
      }
      return {
        dataList,
        hasNodes
      }
    },
    _extractTree(nodes, result, parent_value) {
      let list = result || []
      let valueField = this.map.value
      for (let i = 0; i < nodes.length; i++) {
        let node = nodes[i]
        let child = {}
        for (let key in node) {
          if (key !== 'children') {
            child[key] = node[key]
          }
        }
        if (parent_value !== null && parent_value !== undefined && parent_value !== '') {
          child.parent_value = parent_value
        }
        result.push(child)
        let children = node.children
        if (children) {
          this._extractTree(children, result, node[valueField])
        }
      }
    },
    _extractTreePath(nodes, result) {
      let list = result || []
      for (let i = 0; i < nodes.length; i++) {
        let node = nodes[i]
        let child = {}
        for (let key in node) {
          if (key !== 'children') {
            child[key] = node[key]
          }
        }
        result.push(child)
        let children = node.children
        if (children) {
          this._extractTreePath(children, result)
        }
      }
    },
    _findNodePath(key, nodes, path = []) {
      let textField = this.map.text
      let valueField = this.map.value
      for (let i = 0; i < nodes.length; i++) {
        let node = nodes[i]
        let children = node.children
        let text = node[textField]
        let value = node[valueField]
        path.push({
          value,
          text
        })
        if (value === key) {
          return path
        }
        if (children) {
          const p = this._findNodePath(key, children, path)
          if (p.length) {
            return p
          }
        }
        path.pop()
      }
      return []
    }
  }
}
uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts
对比新文件
@@ -0,0 +1,692 @@
export type PaginationType = {
  current : number,
  size : number,
  count : number
}
export type LoadMoreType = {
  contentdown : string,
  contentrefresh : string,
  contentnomore : string
}
export type SelectedItemType = {
  name : string,
  value : string,
}
export type GetCommandOptions = {
  collection ?: UTSJSONObject,
  field ?: string,
  orderby ?: string,
  where ?: any,
  pageData ?: string,
  pageCurrent ?: number,
  pageSize ?: number,
  getCount ?: boolean,
  getTree ?: any,
  getTreePath ?: UTSJSONObject,
  startwith ?: string,
  limitlevel ?: number,
  groupby ?: string,
  groupField ?: string,
  distinct ?: boolean,
  pageIndistinct ?: boolean,
  foreignKey ?: string,
  loadtime ?: string,
  manual ?: boolean
}
const DefaultSelectedNode = {
  text: '请选择',
  value: ''
}
export const dataPicker = defineMixin({
  props: {
    localdata: {
      type: Array as PropType<Array<UTSJSONObject>>,
      default: [] as Array<UTSJSONObject>
    },
    collection: {
      type: Object,
      default: ''
    },
    field: {
      type: String,
      default: ''
    },
    orderby: {
      type: String,
      default: ''
    },
    where: {
      type: Object,
      default: ''
    },
    pageData: {
      type: String,
      default: 'add'
    },
    pageCurrent: {
      type: Number,
      default: 1
    },
    pageSize: {
      type: Number,
      default: 20
    },
    getcount: {
      type: Boolean,
      default: false
    },
    gettree: {
      type: Object,
      default: ''
    },
    gettreepath: {
      type: Object,
      default: ''
    },
    startwith: {
      type: String,
      default: ''
    },
    limitlevel: {
      type: Number,
      default: 10
    },
    groupby: {
      type: String,
      default: ''
    },
    groupField: {
      type: String,
      default: ''
    },
    distinct: {
      type: Boolean,
      default: false
    },
    pageIndistinct: {
      type: Boolean,
      default: false
    },
    foreignKey: {
      type: String,
      default: ''
    },
    loadtime: {
      type: String,
      default: 'auto'
    },
    manual: {
      type: Boolean,
      default: false
    },
    preload: {
      type: Boolean,
      default: false
    },
    stepSearh: {
      type: Boolean,
      default: true
    },
    selfField: {
      type: String,
      default: ''
    },
    parentField: {
      type: String,
      default: ''
    },
    multiple: {
      type: Boolean,
      default: false
    },
    value: {
      type: Object,
      default: ''
    },
    modelValue: {
      type: Object,
      default: ''
    },
    defaultProps: {
      type: Object as PropType<UTSJSONObject>,
    }
  },
  data() {
    return {
      loading: false,
      error: null as UniCloudError | null,
      treeData: [] as Array<UTSJSONObject>,
      selectedIndex: 0,
      selectedNodes: [] as Array<UTSJSONObject>,
      selectedPages: [] as Array<UTSJSONObject>[],
      selectedValue: '',
      selectedPaths: [] as Array<UTSJSONObject>,
      pagination: {
        current: 1,
        size: 20,
        count: 0
      } as PaginationType
    }
  },
  computed: {
    mappingTextName() : string {
      // TODO
      return (this.defaultProps != null) ? this.defaultProps!.getString('text', 'text') : 'text'
    },
    mappingValueName() : string {
      // TODO
      return (this.defaultProps != null) ? this.defaultProps!.getString('value', 'value') : 'value'
    },
    currentDataList() : Array<UTSJSONObject> {
      if (this.selectedIndex > this.selectedPages.length - 1) {
        return [] as Array<UTSJSONObject>
      }
      return this.selectedPages[this.selectedIndex]
    },
    isLocalData() : boolean {
      return this.localdata.length > 0
    },
    isCloudData() : boolean {
      return this._checkIsNotNull(this.collection)
    },
    isCloudDataList() : boolean {
      return (this.isCloudData && (this.parentField.length == 0 && this.selfField.length == 0))
    },
    isCloudDataTree() : boolean {
      return (this.isCloudData && this.parentField.length > 0 && this.selfField.length > 0)
    },
    dataValue() : any {
      return this.hasModelValue ? this.modelValue : this.value
    },
    hasCloudTreeData() : boolean {
      return this.treeData.length > 0
    },
    hasModelValue() : boolean {
      if (typeof this.modelValue == 'string') {
        const valueString = this.modelValue as string
        return (valueString.length > 0)
      } else if (Array.isArray(this.modelValue)) {
        const valueArray = this.modelValue as Array<string>
        return (valueArray.length > 0)
      }
      return false
    },
    hasCloudDataValue() : boolean {
      if (typeof this.dataValue == 'string') {
        const valueString = this.dataValue as string
        return (valueString.length > 0)
      }
      return false
    }
  },
  created() {
    this.pagination.current = this.pageCurrent
    this.pagination.size = this.pageSize
    this.$watch(
      () : any => [
        this.pageCurrent,
        this.pageSize,
        this.localdata,
        this.value,
        this.collection,
        this.field,
        this.getcount,
        this.orderby,
        this.where,
        this.groupby,
        this.groupField,
        this.distinct
      ],
      (newValue : Array<any>, oldValue : Array<any>) => {
        this.pagination.size = this.pageSize
        if (newValue[0] !== oldValue[0]) {
          this.pagination.current = this.pageCurrent
        }
        this.onPropsChange()
      }
    )
  },
  methods: {
    onPropsChange() {
      this.selectedIndex = 0
      this.selectedNodes.length = 0
      this.selectedPages.length = 0
      this.selectedPaths.length = 0
      // 加载数据
      this.$nextTick(() => {
        this.loadData()
      })
    },
    onTabSelect(index : number) {
      this.selectedIndex = index
    },
    onNodeClick(nodeData : UTSJSONObject) {
      if (nodeData.getBoolean('disable', false)) {
        return
      }
      const isLeaf = this._checkIsLeafNode(nodeData)
      this._trimSelectedNodes(nodeData)
      this.$emit('nodeclick', nodeData)
      if (this.isLocalData) {
        if (isLeaf || !this._checkHasChildren(nodeData)) {
          this.onFinish()
        }
      } else if (this.isCloudDataList) {
        this.onFinish()
      } else if (this.isCloudDataTree) {
        if (isLeaf) {
          this.onFinish()
        } else if (!this._checkHasChildren(nodeData)) {
          // 尝试请求一次,如果没有返回数据标记为叶子节点
          this.loadCloudDataNode(nodeData)
        }
      }
    },
    getChangeNodes(): Array<UTSJSONObject> {
      const nodes: Array<UTSJSONObject> = []
      this.selectedNodes.forEach((node : UTSJSONObject) => {
        const newNode: UTSJSONObject = {}
        newNode[this.mappingTextName] = node.getString(this.mappingTextName)
        newNode[this.mappingValueName] = node.getString(this.mappingValueName)
        nodes.push(newNode)
      })
      return nodes
    },
    onFinish() { },
    // 加载数据(自动判定环境)
    loadData() {
      if (this.isLocalData) {
        this.loadLocalData()
      } else if (this.isCloudDataList) {
        this.loadCloudDataList()
      } else if (this.isCloudDataTree) {
        this.loadCloudDataTree()
      }
    },
    // 加载本地数据
    loadLocalData() {
      this.treeData = this.localdata
      if (Array.isArray(this.dataValue)) {
        const value = this.dataValue as Array<UTSJSONObject>
        this.selectedPaths = value.slice(0)
        this._pushSelectedTreeNodes(value, this.localdata)
      } else {
        this._pushSelectedNodes(this.localdata)
      }
    },
    // 加载 Cloud 数据 (单列)
    loadCloudDataList() {
      this._loadCloudData(null, (data : Array<UTSJSONObject>) => {
        this.treeData = data
        this._pushSelectedNodes(data)
      })
    },
    // 加载 Cloud 数据 (树形)
    loadCloudDataTree() {
      let commandOptions = {
        field: this._cloudDataPostField(),
        where: this._cloudDataTreeWhere(),
        getTree: true
      } as GetCommandOptions
      if (this._checkIsNotNull(this.gettree)) {
        commandOptions.startwith = `${this.selfField}=='${this.dataValue as string}'`
      }
      this._loadCloudData(commandOptions, (data : Array<UTSJSONObject>) => {
        this.treeData = data
        if (this.selectedPaths.length > 0) {
          this._pushSelectedTreeNodes(this.selectedPaths, data)
        } else {
          this._pushSelectedNodes(data)
        }
      })
    },
    // 加载 Cloud 数据 (节点)
    loadCloudDataNode(nodeData : UTSJSONObject) {
      const commandOptions = {
        field: this._cloudDataPostField(),
        where: this._cloudDataNodeWhere()
      } as GetCommandOptions
      this._loadCloudData(commandOptions, (data : Array<UTSJSONObject>) => {
        nodeData['children'] = data
        if (data.length == 0) {
          nodeData['isleaf'] = true
          this.onFinish()
        } else {
          this._pushSelectedNodes(data)
        }
      })
    },
    // 回显 Cloud Tree Path
    loadCloudDataPath() {
      if (!this.hasCloudDataValue) {
        return
      }
      const command : GetCommandOptions = {}
      // 单列
      if (this.isCloudDataList) {
        // 根据 field's as value标识匹配 where 条件
        let where : Array<string> = [];
        let whereField = this._getForeignKeyByField();
        if (whereField.length > 0) {
          where.push(`${whereField} == '${this.dataValue as string}'`)
        }
        let whereString = where.join(' || ')
        if (this._checkIsNotNull(this.where)) {
          whereString = `(${this.where}) && (${whereString})`
        }
        command.field = this._cloudDataPostField()
        command.where = whereString
      }
      // 树形
      if (this.isCloudDataTree) {
        command.field = this._cloudDataPostField()
        command.getTreePath = {
          startWith: `${this.selfField}=='${this.dataValue as string}'`
        }
      }
      this._loadCloudData(command, (data : Array<UTSJSONObject>) => {
        this._extractTreePath(data, this.selectedPaths)
      })
    },
    _loadCloudData(options ?: GetCommandOptions, callback ?: ((data : Array<UTSJSONObject>) => void)) {
      if (this.loading) {
        return
      }
      this.loading = true
      this.error = null
      this._getCommand(options).then((response : UniCloudDBGetResult) => {
        callback?.(response.data)
      }).catch((err : any | null) => {
        this.error = err as UniCloudError
      }).finally(() => {
        this.loading = false
      })
    },
    _cloudDataPostField() : string {
      let fields = [this.field];
      if (this.parentField.length > 0) {
        fields.push(`${this.parentField} as parent_value`)
      }
      return fields.join(',')
    },
    _cloudDataTreeWhere() : string {
      let result : Array<string> = []
      let selectedNodes = this.selectedNodes.length > 0 ? this.selectedNodes : this.selectedPaths
      let parentField = this.parentField
      if (parentField.length > 0) {
        result.push(`${parentField} == null || ${parentField} == ""`)
      }
      if (selectedNodes.length > 0) {
        for (var i = 0; i < selectedNodes.length - 1; i++) {
          const parentFieldValue = selectedNodes[i].getString('value', '')
          result.push(`${parentField} == '${parentFieldValue}'`)
        }
      }
      let where : Array<string> = []
      if (this._checkIsNotNull(this.where)) {
        where.push(`(${this.where as string})`)
      }
      if (result.length > 0) {
        where.push(`(${result.join(' || ')})`)
      }
      return where.join(' && ')
    },
    _cloudDataNodeWhere() : string {
      const where : Array<string> = []
      if (this.selectedNodes.length > 0) {
        const value = this.selectedNodes[this.selectedNodes.length - 1].getString('value', '')
        where.push(`${this.parentField} == '${value}'`)
      }
      let whereString = where.join(' || ')
      if (this._checkIsNotNull(this.where)) {
        return `(${this.where as string}) && (${whereString})`
      }
      return whereString
    },
    _getWhereByForeignKey() : string {
      let result : Array<string> = []
      let whereField = this._getForeignKeyByField();
      if (whereField.length > 0) {
        result.push(`${whereField} == '${this.dataValue as string}'`)
      }
      if (this._checkIsNotNull(this.where)) {
        return `(${this.where}) && (${result.join(' || ')})`
      }
      return result.join(' || ')
    },
    _getForeignKeyByField() : string {
      const fields = this.field.split(',')
      let whereField = ''
      for (let i = 0; i < fields.length; i++) {
        const items = fields[i].split('as')
        if (items.length < 2) {
          continue
        }
        if (items[1].trim() === 'value') {
          whereField = items[0].trim()
          break
        }
      }
      return whereField
    },
    _getCommand(options ?: GetCommandOptions) : Promise<UniCloudDBGetResult> {
      let db = uniCloud.databaseForJQL()
      let collection = Array.isArray(this.collection) ? db.collection(...(this.collection as Array<any>)) : db.collection(this.collection)
      let filter : UniCloudDBFilter | null = null
      if (this.foreignKey.length > 0) {
        filter = collection.foreignKey(this.foreignKey)
      }
      const where : any = options?.where ?? this.where
      if (typeof where == 'string') {
        const whereString = where as string
        if (whereString.length > 0) {
          filter = (filter != null) ? filter.where(where) : collection.where(where)
        }
      } else {
        filter = (filter != null) ? filter.where(where) : collection.where(where)
      }
      let query : UniCloudDBQuery | null = null
      if (this.field.length > 0) {
        query = (filter != null) ? filter.field(this.field) : collection.field(this.field)
      }
      if (this.groupby.length > 0) {
        if (query != null) {
          query = query.groupBy(this.groupby)
        } else if (filter != null) {
          query = filter.groupBy(this.groupby)
        }
      }
      if (this.groupField.length > 0) {
        if (query != null) {
          query = query.groupField(this.groupField)
        } else if (filter != null) {
          query = filter.groupField(this.groupField)
        }
      }
      if (this.distinct == true) {
        if (query != null) {
          query = query.distinct(this.field)
        } else if (filter != null) {
          query = filter.distinct(this.field)
        }
      }
      if (this.orderby.length > 0) {
        if (query != null) {
          query = query.orderBy(this.orderby)
        } else if (filter != null) {
          query = filter.orderBy(this.orderby)
        }
      }
      const size = this.pagination.size
      const current = this.pagination.current
      if (query != null) {
        query = query.skip(size * (current - 1)).limit(size)
      } else if (filter != null) {
        query = filter.skip(size * (current - 1)).limit(size)
      } else {
        query = collection.skip(size * (current - 1)).limit(size)
      }
      const getOptions = {}
      const treeOptions = {
        limitLevel: this.limitlevel,
        startWith: this.startwith
      }
      if (this.getcount == true) {
        getOptions['getCount'] = this.getcount
      }
      const getTree : any = options?.getTree ?? this.gettree
      if (typeof getTree == 'string') {
        const getTreeString = getTree as string
        if (getTreeString.length > 0) {
          getOptions['getTree'] = treeOptions
        }
      } else if (typeof getTree == 'object') {
        getOptions['getTree'] = treeOptions
      } else {
        getOptions['getTree'] = getTree
      }
      const getTreePath = options?.getTreePath ?? this.gettreepath
      if (typeof getTreePath == 'string') {
        const getTreePathString = getTreePath as string
        if (getTreePathString.length > 0) {
          getOptions['getTreePath'] = getTreePath
        }
      } else {
        getOptions['getTreePath'] = getTreePath
      }
      return query.get(getOptions)
    },
    _checkIsNotNull(value : any) : boolean {
      if (typeof value == 'string') {
        const valueString = value as string
        return (valueString.length > 0)
      } else if (value instanceof UTSJSONObject) {
        return true
      }
      return false
    },
    _checkIsLeafNode(nodeData : UTSJSONObject) : boolean {
      if (this.selectedIndex >= this.limitlevel) {
        return true
      }
      if (nodeData.getBoolean('isleaf', false)) {
        return true
      }
      return false
    },
    _checkHasChildren(nodeData : UTSJSONObject) : boolean {
      const children = nodeData.getArray('children') ?? ([] as Array<any>)
      return children.length > 0
    },
    _pushSelectedNodes(nodes : Array<UTSJSONObject>) {
      this.selectedNodes.push(DefaultSelectedNode)
      this.selectedPages.push(nodes)
      this.selectedIndex = this.selectedPages.length - 1
    },
    _trimSelectedNodes(nodeData : UTSJSONObject) {
      this.selectedNodes.splice(this.selectedIndex)
      this.selectedNodes.push(nodeData)
      if (this.selectedPages.length > 0) {
        this.selectedPages.splice(this.selectedIndex + 1)
      }
      const children = nodeData.getArray<UTSJSONObject>('children') ?? ([] as Array<UTSJSONObject>)
      if (children.length > 0) {
        this.selectedNodes.push(DefaultSelectedNode)
        this.selectedPages.push(children)
      }
      this.selectedIndex = this.selectedPages.length - 1
    },
    _pushSelectedTreeNodes(paths : Array<UTSJSONObject>, nodes : Array<UTSJSONObject>) {
      let children : Array<UTSJSONObject> = nodes
      paths.forEach((node : UTSJSONObject) => {
        const findNode = children.find((item : UTSJSONObject) : boolean => {
          return (item.getString(this.mappingValueName) == node.getString(this.mappingValueName))
        })
        if (findNode != null) {
          this.selectedPages.push(children)
          this.selectedNodes.push(node)
          children = findNode.getArray<UTSJSONObject>('children') ?? ([] as Array<UTSJSONObject>)
        }
      })
      this.selectedIndex = this.selectedPages.length - 1
    },
    _extractTreePath(nodes : Array<UTSJSONObject>, result : Array<UTSJSONObject>) {
      if (nodes.length == 0) {
        return
      }
      const node = nodes[0]
      result.push(node)
      const children = node.getArray<UTSJSONObject>('children')
      if (Array.isArray(children) && children!.length > 0) {
        this._extractTreePath(children, result)
      }
    }
  }
})
uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.css
对比新文件
@@ -0,0 +1,76 @@
.uni-data-pickerview {
  position: relative;
  flex-direction: column;
  overflow: hidden;
}
.loading-cover {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  align-items: center;
  justify-content: center;
  background-color: rgba(150, 150, 150, .1);
}
.error {
  background-color: #fff;
  padding: 15px;
}
.error-text {
  color: #DD524D;
}
.selected-node-list {
  flex-direction: row;
  flex-wrap: nowrap;
}
.selected-node-item {
  margin-left: 10px;
  margin-right: 10px;
  padding: 8px 10px 8px 10px;
  border-bottom: 2px solid transparent;
}
.selected-node-item-active {
  color: #007aff;
  border-bottom-color: #007aff;
}
.list-view {
  flex: 1;
}
.list-item {
  flex-direction: row;
  justify-content: space-between;
  padding: 12px 15px;
  border-bottom: 1px solid #f0f0f0;
}
.item-text {
  color: #333333;
}
.item-text-disabled {
  opacity: .5;
}
.item-text-overflow {
  overflow: hidden;
}
.check {
  margin-right: 5px;
  border: 2px solid #007aff;
  border-left: 0;
  border-top: 0;
  height: 12px;
  width: 6px;
  transform-origin: center;
  transform: rotate(45deg);
}
uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.uvue
对比新文件
@@ -0,0 +1,69 @@
<template>
  <view class="uni-data-pickerview">
    <view v-if="error!=null" class="error">
      <text class="error-text">{{error!.errMsg}}</text>
    </view>
    <scroll-view v-if="!isCloudDataList" :scroll-x="true">
      <view class="selected-node-list">
        <template v-for="(item, index) in selectedNodes">
          <text class="selected-node-item" :class="{'selected-node-item-active':index==selectedIndex}"
            @click="onTabSelect(index)">
            {{item[mappingTextName]}}
          </text>
        </template>
      </view>
    </scroll-view>
    <list-view class="list-view" :scroll-y="true">
      <list-item class="list-item" v-for="(item, _) in currentDataList" @click="onNodeClick(item)">
        <text class="item-text" :class="{'item-text-disabled': item['disable']}">{{item[mappingTextName]}}</text>
        <text class="check" v-if="item[mappingValueName] == selectedNodes[selectedIndex][mappingValueName]"></text>
      </list-item>
    </list-view>
    <view class="loading-cover" v-if="loading">
      <slot name="pickerview-loading" :loading="loading"></slot>
    </view>
  </view>
</template>
<script>
  import { dataPicker } from "./uni-data-picker.uts"
  /**
   * DataPickerview
   * @description uni-data-pickerview
   * @tutorial https://ext.dcloud.net.cn/plugin?id=3796
   * @property {Array} localdata 本地数据,参考
   * @property {Boolean} step-searh = [true|false] 是否分布查询
   * @value true 启用分布查询,仅查询当前选中节点
   * @value false 关闭分布查询,一次查询出所有数据
   * @property {String|DBFieldString} self-field 分布查询当前字段名称
   * @property {String|DBFieldString} parent-field 分布查询父字段名称
   * @property {String|DBCollectionString} collection 表名
   * @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
   * @property {String} orderby 排序字段及正序倒叙设置
   * @property {String|JQLString} where 查询条件
   */
  export default {
    name: 'UniDataPickerView',
    emits: ['nodeclick', 'change', 'update:modelValue'],
    mixins: [dataPicker],
    props: {
      ellipsis: {
        type: Boolean,
        default: true
      }
    },
    created() {
      this.loadData()
    },
    methods: {
      onFinish() {
        this.$emit('change', this.getChangeNodes())
      }
    }
  }
</script>
<style>
  @import url("uni-data-pickerview.css");
</style>
uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue
对比新文件
@@ -0,0 +1,323 @@
<template>
  <view class="uni-data-pickerview">
    <scroll-view v-if="!isCloudDataList" class="selected-area" scroll-x="true">
      <view class="selected-list">
          <view
            class="selected-item"
            v-for="(item,index) in selected"
            :key="index"
            :class="{
              'selected-item-active':index == selectedIndex
            }"
            @click="handleSelect(index)"
          >
            <text>{{item.text || ''}}</text>
          </view>
      </view>
    </scroll-view>
    <view class="tab-c">
      <scroll-view class="list" :scroll-y="true">
        <view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in dataList[selectedIndex]" :key="j"
          @click="handleNodeClick(item, selectedIndex, j)">
          <text class="item-text">{{item[map.text]}}</text>
          <view class="check" v-if="selected.length > selectedIndex && item[map.value] == selected[selectedIndex].value"></view>
        </view>
      </scroll-view>
      <view class="loading-cover" v-if="loading">
        <uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
      </view>
      <view class="error-message" v-if="errorMessage">
        <text class="error-text">{{errorMessage}}</text>
      </view>
    </view>
  </view>
</template>
<script>
  import dataPicker from "./uni-data-picker.js"
  /**
   * DataPickerview
   * @description uni-data-pickerview
   * @tutorial https://ext.dcloud.net.cn/plugin?id=3796
   * @property {Array} localdata 本地数据,参考
   * @property {Boolean} step-searh = [true|false] 是否分布查询
   * @value true 启用分布查询,仅查询当前选中节点
   * @value false 关闭分布查询,一次查询出所有数据
   * @property {String|DBFieldString} self-field 分布查询当前字段名称
   * @property {String|DBFieldString} parent-field 分布查询父字段名称
   * @property {String|DBCollectionString} collection 表名
   * @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
   * @property {String} orderby 排序字段及正序倒叙设置
   * @property {String|JQLString} where 查询条件
   */
  export default {
    name: 'UniDataPickerView',
    emits: ['nodeclick', 'change', 'datachange', 'update:modelValue'],
    mixins: [dataPicker],
    props: {
      managedMode: {
        type: Boolean,
        default: false
      },
      ellipsis: {
        type: Boolean,
        default: true
      }
    },
    created() {
      if (!this.managedMode) {
        this.$nextTick(() => {
          this.loadData();
        })
      }
    },
    methods: {
      onPropsChange() {
        this._treeData = [];
        this.selectedIndex = 0;
        this.$nextTick(() => {
          this.loadData();
        })
      },
      handleSelect(index) {
        this.selectedIndex = index;
      },
      handleNodeClick(item, i, j) {
        if (item.disable) {
          return;
        }
        const node = this.dataList[i][j];
        const text = node[this.map.text];
        const value = node[this.map.value];
        if (i < this.selected.length - 1) {
          this.selected.splice(i, this.selected.length - i)
          this.selected.push({
            text,
            value
          })
        } else if (i === this.selected.length - 1) {
          this.selected.splice(i, 1, {
            text,
            value
          })
        }
        if (node.isleaf) {
          this.onSelectedChange(node, node.isleaf)
          return
        }
        const {
          isleaf,
          hasNodes
        } = this._updateBindData()
        // 本地数据
        if (this.isLocalData) {
          this.onSelectedChange(node, (!hasNodes || isleaf))
        } else if (this.isCloudDataList) { // Cloud 数据 (单列)
          this.onSelectedChange(node, true)
        } else if (this.isCloudDataTree) { // Cloud 数据 (树形)
          if (isleaf) {
            this.onSelectedChange(node, node.isleaf)
          } else if (!hasNodes) { // 请求一次服务器以确定是否为叶子节点
            this.loadCloudDataNode((data) => {
              if (!data.length) {
                node.isleaf = true
              } else {
                this._treeData.push(...data)
                this._updateBindData(node)
              }
              this.onSelectedChange(node, node.isleaf)
            })
          }
        }
      },
      updateData(data) {
        this._treeData = data.treeData
        this.selected = data.selected
        if (!this._treeData.length) {
          this.loadData()
        } else {
          //this.selected = data.selected
          this._updateBindData()
        }
      },
      onDataChange() {
        this.$emit('datachange');
      },
      onSelectedChange(node, isleaf) {
        if (isleaf) {
          this._dispatchEvent()
        }
        if (node) {
          this.$emit('nodeclick', node)
        }
      },
      _dispatchEvent() {
        this.$emit('change', this.selected.slice(0))
      }
    }
  }
</script>
<style lang="scss">
    $uni-primary: #007aff !default;
    .uni-data-pickerview {
        flex: 1;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: column;
        overflow: hidden;
        height: 100%;
    }
  .error-text {
    color: #DD524D;
  }
  .loading-cover {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(255, 255, 255, .5);
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: column;
    align-items: center;
    z-index: 1001;
  }
  .load-more {
    /* #ifndef APP-NVUE */
    margin: auto;
    /* #endif */
  }
  .error-message {
    background-color: #fff;
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    padding: 15px;
    opacity: .9;
    z-index: 102;
  }
  /* #ifdef APP-NVUE */
  .selected-area {
    width: 750rpx;
  }
  /* #endif */
  .selected-list {
    /* #ifndef APP-NVUE */
    display: flex;
    flex-wrap: nowrap;
    /* #endif */
    flex-direction: row;
    padding: 0 5px;
    border-bottom: 1px solid #f8f8f8;
  }
  .selected-item {
    margin-left: 10px;
    margin-right: 10px;
    padding: 12px 0;
    text-align: center;
    /* #ifndef APP-NVUE */
    white-space: nowrap;
    /* #endif */
  }
  .selected-item-text-overflow {
    width: 168px;
    /* fix nvue */
    overflow: hidden;
    /* #ifndef APP-NVUE */
    width: 6em;
    white-space: nowrap;
    text-overflow: ellipsis;
    -o-text-overflow: ellipsis;
    /* #endif */
  }
    .selected-item-active {
        border-bottom: 2px solid $uni-primary;
    }
    .selected-item-text {
        color: $uni-primary;
    }
  .tab-c {
    position: relative;
    flex: 1;
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: row;
    overflow: hidden;
  }
  .list {
    flex: 1;
  }
  .item {
    padding: 12px 15px;
    /* border-bottom: 1px solid #f0f0f0; */
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: row;
    justify-content: space-between;
  }
  .is-disabled {
    opacity: .5;
  }
  .item-text {
    /* flex: 1; */
    color: #333333;
  }
  .item-text-overflow {
    width: 280px;
    /* fix nvue */
    overflow: hidden;
    /* #ifndef APP-NVUE */
    width: 20em;
    white-space: nowrap;
    text-overflow: ellipsis;
    -o-text-overflow: ellipsis;
    /* #endif */
  }
    .check {
        margin-right: 5px;
        border: 2px solid $uni-primary;
        border-left: 0;
        border-top: 0;
        height: 12px;
        width: 6px;
        transform-origin: center;
        /* #ifndef APP-NVUE */
        transition: all 0.3s;
        /* #endif */
        transform: rotate(45deg);
    }
</style>
uni_modules/uni-data-picker/package.json
对比新文件
@@ -0,0 +1,91 @@
{
  "id": "uni-data-picker",
  "displayName": "uni-data-picker 数据驱动的picker选择器",
  "version": "2.0.1",
  "description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
  "keywords": [
    "uni-ui",
    "uniui",
    "picker",
    "级联",
    "省市区",
    ""
],
  "repository": "https://github.com/dcloudio/uni-ui",
  "engines": {
    "HBuilderX": ""
  },
  "directories": {
    "example": "../../temps/example_temps"
  },
"dcloudext": {
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "无",
      "permissions": "无"
    },
    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
    "type": "component-vue"
  },
  "uni_modules": {
    "dependencies": [
      "uni-load-more",
            "uni-icons",
            "uni-scss"
    ],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y",
        "alipay": "n"
      },
      "client": {
        "App": {
          "app-vue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
        "QQ": "y",
        "京东": "u"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        },
        "Vue": {
            "vue2": "y",
            "vue3": "y"
        }
      }
    }
  }
}
uni_modules/uni-data-picker/readme.md
对比新文件
@@ -0,0 +1,22 @@
## DataPicker 级联选择
> **组件名:uni-data-picker**
> 代码块: `uDataPicker`
> 关联组件:`uni-data-pickerview`、`uni-load-more`。
`<uni-data-picker>` 是一个选择类[datacom组件](https://uniapp.dcloud.net.cn/component/datacom)。
支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
候选数据支持一次性加载完毕,也支持懒加载,比如示例图中,选择了“北京”后,动态加载北京的区县数据。
`<uni-data-picker>` 组件尤其适用于地址选择、分类选择等选择类。
`<uni-data-picker>` 支持本地数据、云端静态数据(json),uniCloud云数据库数据。
`<uni-data-picker>` 可以通过JQL直连uniCloud云数据库,配套[DB Schema](https://uniapp.dcloud.net.cn/uniCloud/schema),可在schema2code中自动生成前端页面,还支持服务器端校验。
在uniCloud数据表中新建表“uni-id-address”和“opendb-city-china”,这2个表的schema自带foreignKey关联。在“uni-id-address”表的表结构页面使用schema2code生成前端页面,会自动生成地址管理的维护页面,自动从“opendb-city-china”表包含的中国所有省市区信息里选择地址。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
uni_modules/uni-data-select/changelog.md
对比新文件
@@ -0,0 +1,39 @@
## 1.0.8(2024-03-28)
- 修复 在vue2下:style动态绑定导致编译失败的bug
## 1.0.7(2024-01-20)
- 修复 长文本回显超过容器的bug,超过容器部分显示省略号
## 1.0.6(2023-04-12)
- 修复 微信小程序点击时会改变背景颜色的 bug
## 1.0.5(2023-02-03)
- 修复 禁用时会显示清空按钮
## 1.0.4(2023-02-02)
- 优化 查询条件短期内多次变更只查询最后一次变更后的结果
- 调整 内部缓存键名调整为 uni-data-select-lastSelectedValue
## 1.0.3(2023-01-16)
- 修复 不关联服务空间报错的问题
## 1.0.2(2023-01-14)
- 新增  属性 `format` 可用于格式化显示选项内容
## 1.0.1(2022-12-06)
- 修复  当where变化时,数据不会自动更新的问题
## 0.1.9(2022-09-05)
- 修复 微信小程序下拉框出现后选择会点击到蒙板后面的输入框
## 0.1.8(2022-08-29)
- 修复 点击的位置不准确
## 0.1.7(2022-08-12)
- 新增 支持 disabled 属性
## 0.1.6(2022-07-06)
- 修复 pc端宽度异常的bug
## 0.1.5
- 修复 pc端宽度异常的bug
## 0.1.4(2022-07-05)
- 优化 显示样式
## 0.1.3(2022-06-02)
- 修复 localdata 赋值不生效的 bug
- 新增 支持  uni.scss 修改颜色
- 新增 支持选项禁用(数据选项设置 disabled: true 即禁用)
## 0.1.2(2022-05-08)
- 修复 当 value 为 0 时选择不生效的 bug
## 0.1.1(2022-05-07)
- 新增 记住上次的选项(仅 collection 存在时有效)
## 0.1.0(2022-04-22)
- 初始化
uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue
对比新文件
@@ -0,0 +1,562 @@
<template>
    <view class="uni-stat__select">
        <span v-if="label" class="uni-label-text hide-on-phone">{{label + ':'}}</span>
        <view class="uni-stat-box" :class="{'uni-stat__actived': current}">
            <view class="uni-select" :class="{'uni-select--disabled':disabled}">
                <view class="uni-select__input-box" @click="toggleSelector">
                    <view v-if="current" class="uni-select__input-text">{{textShow}}</view>
                    <view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view>
                    <view v-if="current && clear && !disabled" @click.stop="clearVal">
                        <uni-icons type="clear" color="#c0c4cc" size="24" />
                    </view>
                    <view v-else>
                        <uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
                    </view>
                </view>
                <view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
                <view class="uni-select__selector" :style="getOffsetByPlacement" v-if="showSelector">
                    <view :class="placement=='bottom'?'uni-popper__arrow_bottom':'uni-popper__arrow_top'"></view>
                    <scroll-view scroll-y="true" class="uni-select__selector-scroll">
                        <view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0">
                            <text>{{emptyTips}}</text>
                        </view>
                        <view v-else class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData" :key="index"
                            @click="change(item)">
                            <text :class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text>
                        </view>
                    </scroll-view>
                </view>
            </view>
        </view>
    </view>
</template>
<script>
    /**
     * DataChecklist 数据选择器
     * @description 通过数据渲染的下拉框组件
     * @tutorial https://uniapp.dcloud.io/component/uniui/uni-data-select
     * @property {String} value 默认值
     * @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
     * @property {Boolean} clear 是否可以清空已选项
     * @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效
     * @property {String} label 左侧标题
     * @property {String} placeholder 输入框的提示文字
     * @property {Boolean} disabled 是否禁用
     * @property {String} placement 弹出位置
     *     @value top           顶部弹出
     *     @value bottom        底部弹出(default)
     * @event {Function} change  选中发生变化触发
     */
    export default {
        name: "uni-data-select",
        mixins: [uniCloud.mixinDatacom || {}],
        props: {
            localdata: {
                type: Array,
                default () {
                    return []
                }
            },
            value: {
                type: [String, Number],
                default: ''
            },
            modelValue: {
                type: [String, Number],
                default: ''
            },
            label: {
                type: String,
                default: ''
            },
            placeholder: {
                type: String,
                default: '请选择'
            },
            emptyTips: {
                type: String,
                default: '无选项'
            },
            clear: {
                type: Boolean,
                default: true
            },
            defItem: {
                type: Number,
                default: 0
            },
            disabled: {
                type: Boolean,
                default: false
            },
            // 格式化输出 用法 field="_id as value, version as text, uni_platform as label" format="{label} - {text}"
            format: {
                type: String,
                default: ''
            },
            placement: {
                type: String,
                default: 'bottom'
            }
        },
        data() {
            return {
                showSelector: false,
                current: '',
                mixinDatacomResData: [],
                apps: [],
                channels: [],
                cacheKey: "uni-data-select-lastSelectedValue",
            };
        },
        created() {
            this.debounceGet = this.debounce(() => {
                this.query();
            }, 300);
            if (this.collection && !this.localdata.length) {
                this.debounceGet();
            }
        },
        computed: {
            typePlaceholder() {
                const text = {
                    'opendb-stat-app-versions': '版本',
                    'opendb-app-channels': '渠道',
                    'opendb-app-list': '应用'
                }
                const common = this.placeholder
                const placeholder = text[this.collection]
                return placeholder ?
                    common + placeholder :
                    common
            },
            valueCom() {
                // #ifdef VUE3
                return this.modelValue;
                // #endif
                // #ifndef VUE3
                return this.value;
                // #endif
            },
            textShow() {
                // 长文本显示
                let text = this.current;
                if (text.length > 10) {
                    return text.slice(0, 25) + '...';
                }
                return text;
            },
            getOffsetByPlacement() {
                switch (this.placement) {
                    case 'top':
                        return "bottom:calc(100% + 12px);";
                    case 'bottom':
                        return "top:calc(100% + 12px);";
                }
            }
        },
        watch: {
            localdata: {
                immediate: true,
                handler(val, old) {
                    if (Array.isArray(val) && old !== val) {
                        this.mixinDatacomResData = val
                    }
                }
            },
            valueCom(val, old) {
                this.initDefVal()
            },
            mixinDatacomResData: {
                immediate: true,
                handler(val) {
                    if (val.length) {
                        this.initDefVal()
                    }
                }
            },
        },
        methods: {
            debounce(fn, time = 100) {
                let timer = null
                return function(...args) {
                    if (timer) clearTimeout(timer)
                    timer = setTimeout(() => {
                        fn.apply(this, args)
                    }, time)
                }
            },
            // 执行数据库查询
            query() {
                this.mixinDatacomEasyGet();
            },
            // 监听查询条件变更事件
            onMixinDatacomPropsChange() {
                if (this.collection) {
                    this.debounceGet();
                }
            },
            initDefVal() {
                let defValue = ''
                if ((this.valueCom || this.valueCom === 0) && !this.isDisabled(this.valueCom)) {
                    defValue = this.valueCom
                } else {
                    let strogeValue
                    if (this.collection) {
                        strogeValue = this.getCache()
                    }
                    if (strogeValue || strogeValue === 0) {
                        defValue = strogeValue
                    } else {
                        let defItem = ''
                        if (this.defItem > 0 && this.defItem <= this.mixinDatacomResData.length) {
                            defItem = this.mixinDatacomResData[this.defItem - 1].value
                        }
                        defValue = defItem
                    }
                    if (defValue || defValue === 0) {
                        this.emit(defValue)
                    }
                }
                const def = this.mixinDatacomResData.find(item => item.value === defValue)
                this.current = def ? this.formatItemName(def) : ''
            },
            /**
             * @param {[String, Number]} value
             * 判断用户给的 value 是否同时为禁用状态
             */
            isDisabled(value) {
                let isDisabled = false;
                this.mixinDatacomResData.forEach(item => {
                    if (item.value === value) {
                        isDisabled = item.disable
                    }
                })
                return isDisabled;
            },
            clearVal() {
                this.emit('')
                if (this.collection) {
                    this.removeCache()
                }
            },
            change(item) {
                if (!item.disable) {
                    this.showSelector = false
                    this.current = this.formatItemName(item)
                    this.emit(item.value)
                }
            },
            emit(val) {
                this.$emit('input', val)
                this.$emit('update:modelValue', val)
                this.$emit('change', val)
                if (this.collection) {
                    this.setCache(val);
                }
            },
            toggleSelector() {
                if (this.disabled) {
                    return
                }
                this.showSelector = !this.showSelector
            },
            formatItemName(item) {
                let {
                    text,
                    value,
                    channel_code
                } = item
                channel_code = channel_code ? `(${channel_code})` : ''
                if (this.format) {
                    // 格式化输出
                    let str = "";
                    str = this.format;
                    for (let key in item) {
                        str = str.replace(new RegExp(`{${key}}`, "g"), item[key]);
                    }
                    return str;
                } else {
                    return this.collection.indexOf('app-list') > 0 ?
                        `${text}(${value})` :
                        (
                            text ?
                            text :
                            `未命名${channel_code}`
                        )
                }
            },
            // 获取当前加载的数据
            getLoadData() {
                return this.mixinDatacomResData;
            },
            // 获取当前缓存key
            getCurrentCacheKey() {
                return this.collection;
            },
            // 获取缓存
            getCache(name = this.getCurrentCacheKey()) {
                let cacheData = uni.getStorageSync(this.cacheKey) || {};
                return cacheData[name];
            },
            // 设置缓存
            setCache(value, name = this.getCurrentCacheKey()) {
                let cacheData = uni.getStorageSync(this.cacheKey) || {};
                cacheData[name] = value;
                uni.setStorageSync(this.cacheKey, cacheData);
            },
            // 删除缓存
            removeCache(name = this.getCurrentCacheKey()) {
                let cacheData = uni.getStorageSync(this.cacheKey) || {};
                delete cacheData[name];
                uni.setStorageSync(this.cacheKey, cacheData);
            },
        }
    }
</script>
<style lang="scss">
    $uni-base-color: #6a6a6a !default;
    $uni-main-color: #333 !default;
    $uni-secondary-color: #909399 !default;
    $uni-border-3: #e5e5e5;
    /* #ifndef APP-NVUE */
    @media screen and (max-width: 500px) {
        .hide-on-phone {
            display: none;
        }
    }
    /* #endif */
    .uni-stat__select {
        display: flex;
        align-items: center;
        // padding: 15px;
        /* #ifdef H5 */
        cursor: pointer;
        /* #endif */
        width: 100%;
        flex: 1;
        box-sizing: border-box;
    }
    .uni-stat-box {
        width: 100%;
        flex: 1;
    }
    .uni-stat__actived {
        width: 100%;
        flex: 1;
        // outline: 1px solid #2979ff;
    }
    .uni-label-text {
        font-size: 14px;
        font-weight: bold;
        color: $uni-base-color;
        margin: auto 0;
        margin-right: 5px;
    }
    .uni-select {
        font-size: 14px;
        border: 1px solid $uni-border-3;
        box-sizing: border-box;
        border-radius: 4px;
        padding: 0 5px;
        padding-left: 10px;
        position: relative;
        /* #ifndef APP-NVUE */
        display: flex;
        user-select: none;
        /* #endif */
        flex-direction: row;
        align-items: center;
        border-bottom: solid 1px $uni-border-3;
        width: 100%;
        flex: 1;
        height: 35px;
        &--disabled {
            background-color: #f5f7fa;
            cursor: not-allowed;
        }
    }
    .uni-select__label {
        font-size: 16px;
        // line-height: 22px;
        height: 35px;
        padding-right: 10px;
        color: $uni-secondary-color;
    }
    .uni-select__input-box {
        height: 35px;
        position: relative;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex: 1;
        flex-direction: row;
        align-items: center;
    }
    .uni-select__input {
        flex: 1;
        font-size: 14px;
        height: 22px;
        line-height: 22px;
    }
    .uni-select__input-plac {
        font-size: 14px;
        color: $uni-secondary-color;
    }
    .uni-select__selector {
        /* #ifndef APP-NVUE */
        box-sizing: border-box;
        /* #endif */
        position: absolute;
        left: 0;
        width: 100%;
        background-color: #FFFFFF;
        border: 1px solid #EBEEF5;
        border-radius: 6px;
        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
        z-index: 3;
        padding: 4px 0;
    }
    .uni-select__selector-scroll {
        /* #ifndef APP-NVUE */
        max-height: 200px;
        box-sizing: border-box;
        /* #endif */
    }
    /* #ifdef H5 */
    @media (min-width: 768px) {
        .uni-select__selector-scroll {
            max-height: 600px;
        }
    }
    /* #endif */
    .uni-select__selector-empty,
    .uni-select__selector-item {
        /* #ifndef APP-NVUE */
        display: flex;
        cursor: pointer;
        /* #endif */
        line-height: 35px;
        font-size: 14px;
        text-align: center;
        /* border-bottom: solid 1px $uni-border-3; */
        padding: 0px 10px;
    }
    .uni-select__selector-item:hover {
        background-color: #f9f9f9;
    }
    .uni-select__selector-empty:last-child,
    .uni-select__selector-item:last-child {
        /* #ifndef APP-NVUE */
        border-bottom: none;
        /* #endif */
    }
    .uni-select__selector__disabled {
        opacity: 0.4;
        cursor: default;
    }
    /* picker 弹出层通用的指示小三角 */
    .uni-popper__arrow_bottom,
    .uni-popper__arrow_bottom::after,
    .uni-popper__arrow_top,
    .uni-popper__arrow_top::after,
    {
    position: absolute;
    display: block;
    width: 0;
    height: 0;
    border-color: transparent;
    border-style: solid;
    border-width: 6px;
    }
    .uni-popper__arrow_bottom {
        filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
        top: -6px;
        left: 10%;
        margin-right: 3px;
        border-top-width: 0;
        border-bottom-color: #EBEEF5;
    }
    .uni-popper__arrow_bottom::after {
        content: " ";
        top: 1px;
        margin-left: -6px;
        border-top-width: 0;
        border-bottom-color: #fff;
    }
    .uni-popper__arrow_top {
        filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
        bottom: -6px;
        left: 10%;
        margin-right: 3px;
        border-bottom-width: 0;
        border-top-color: #EBEEF5;
    }
    .uni-popper__arrow_top::after {
        content: " ";
        bottom: 1px;
        margin-left: -6px;
        border-bottom-width: 0;
        border-top-color: #fff;
    }
    .uni-select__input-text {
        // width: 280px;
        width: 100%;
        color: $uni-main-color;
        white-space: nowrap;
        text-overflow: ellipsis;
        -o-text-overflow: ellipsis;
        overflow: hidden;
    }
    .uni-select__input-placeholder {
        color: $uni-base-color;
        font-size: 12px;
    }
    .uni-select--mask {
        position: fixed;
        top: 0;
        bottom: 0;
        right: 0;
        left: 0;
        z-index: 2;
    }
</style>
uni_modules/uni-data-select/package.json
对比新文件
@@ -0,0 +1,86 @@
{
  "id": "uni-data-select",
  "displayName": "uni-data-select 下拉框选择器",
  "version": "1.0.8",
  "description": "通过数据驱动的下拉框选择器",
  "keywords": [
    "uni-ui",
    "select",
    "uni-data-select",
    "下拉框",
    "下拉选"
],
  "repository": "https://github.com/dcloudio/uni-ui",
  "engines": {
    "HBuilderX": "^3.1.1"
  },
  "directories": {
    "example": "../../temps/example_temps"
  },
"dcloudext": {
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "无",
      "permissions": "无"
    },
    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
    "type": "component-vue"
  },
  "uni_modules": {
    "dependencies": ["uni-load-more"],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y",
        "alipay": "n"
      },
      "client": {
        "App": {
          "app-vue": "u",
          "app-nvue": "n"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "u",
          "百度": "u",
          "字节跳动": "u",
        "QQ": "u",
        "京东": "u"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        },
        "Vue": {
            "vue2": "y",
            "vue3": "y"
        }
      }
    }
  }
}
uni_modules/uni-data-select/readme.md
对比新文件
@@ -0,0 +1,8 @@
## DataSelect 下拉框选择器
> **组件名:uni-data-select**
> 代码块: `uDataSelect`
当选项过多时,使用下拉菜单展示并选择内容
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-select)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
uni_modules/uni-dateformat/changelog.md
对比新文件
@@ -0,0 +1,10 @@
## 1.0.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-dateformat](https://uniapp.dcloud.io/component/uniui/uni-dateformat)
## 0.0.5(2021-07-08)
- 调整 默认时间不再是当前时间,而是显示'-'字符
## 0.0.4(2021-05-12)
- 新增 组件示例地址
## 0.0.3(2021-02-04)
- 调整为uni_modules目录规范
- 修复 iOS 平台日期格式化出错的问题
uni_modules/uni-dateformat/components/uni-dateformat/date-format.js
对比新文件
@@ -0,0 +1,200 @@
// yyyy-MM-dd hh:mm:ss.SSS 所有支持的类型
function pad(str, length = 2) {
    str += ''
    while (str.length < length) {
        str = '0' + str
    }
    return str.slice(-length)
}
const parser = {
    yyyy: (dateObj) => {
        return pad(dateObj.year, 4)
    },
    yy: (dateObj) => {
        return pad(dateObj.year)
    },
    MM: (dateObj) => {
        return pad(dateObj.month)
    },
    M: (dateObj) => {
        return dateObj.month
    },
    dd: (dateObj) => {
        return pad(dateObj.day)
    },
    d: (dateObj) => {
        return dateObj.day
    },
    hh: (dateObj) => {
        return pad(dateObj.hour)
    },
    h: (dateObj) => {
        return dateObj.hour
    },
    mm: (dateObj) => {
        return pad(dateObj.minute)
    },
    m: (dateObj) => {
        return dateObj.minute
    },
    ss: (dateObj) => {
        return pad(dateObj.second)
    },
    s: (dateObj) => {
        return dateObj.second
    },
    SSS: (dateObj) => {
        return pad(dateObj.millisecond, 3)
    },
    S: (dateObj) => {
        return dateObj.millisecond
    },
}
// 这都n年了iOS依然不认识2020-12-12,需要转换为2020/12/12
function getDate(time) {
    if (time instanceof Date) {
        return time
    }
    switch (typeof time) {
        case 'string':
            {
                // 2020-12-12T12:12:12.000Z、2020-12-12T12:12:12.000
                if (time.indexOf('T') > -1) {
                    return new Date(time)
                }
                return new Date(time.replace(/-/g, '/'))
            }
        default:
            return new Date(time)
    }
}
export function formatDate(date, format = 'yyyy/MM/dd hh:mm:ss') {
    if (!date && date !== 0) {
        return ''
    }
    date = getDate(date)
    const dateObj = {
        year: date.getFullYear(),
        month: date.getMonth() + 1,
        day: date.getDate(),
        hour: date.getHours(),
        minute: date.getMinutes(),
        second: date.getSeconds(),
        millisecond: date.getMilliseconds()
    }
    const tokenRegExp = /yyyy|yy|MM|M|dd|d|hh|h|mm|m|ss|s|SSS|SS|S/
    let flag = true
    let result = format
    while (flag) {
        flag = false
        result = result.replace(tokenRegExp, function(matched) {
            flag = true
            return parser[matched](dateObj)
        })
    }
    return result
}
export function friendlyDate(time, {
    locale = 'zh',
    threshold = [60000, 3600000],
    format = 'yyyy/MM/dd hh:mm:ss'
}) {
    if (time === '-') {
        return time
    }
    if (!time && time !== 0) {
        return ''
    }
    const localeText = {
        zh: {
            year: '年',
            month: '月',
            day: '天',
            hour: '小时',
            minute: '分钟',
            second: '秒',
            ago: '前',
            later: '后',
            justNow: '刚刚',
            soon: '马上',
            template: '{num}{unit}{suffix}'
        },
        en: {
            year: 'year',
            month: 'month',
            day: 'day',
            hour: 'hour',
            minute: 'minute',
            second: 'second',
            ago: 'ago',
            later: 'later',
            justNow: 'just now',
            soon: 'soon',
            template: '{num} {unit} {suffix}'
        }
    }
    const text = localeText[locale] || localeText.zh
    let date = getDate(time)
    let ms = date.getTime() - Date.now()
    let absMs = Math.abs(ms)
    if (absMs < threshold[0]) {
        return ms < 0 ? text.justNow : text.soon
    }
    if (absMs >= threshold[1]) {
        return formatDate(date, format)
    }
    let num
    let unit
    let suffix = text.later
    if (ms < 0) {
        suffix = text.ago
        ms = -ms
    }
    const seconds = Math.floor((ms) / 1000)
    const minutes = Math.floor(seconds / 60)
    const hours = Math.floor(minutes / 60)
    const days = Math.floor(hours / 24)
    const months = Math.floor(days / 30)
    const years = Math.floor(months / 12)
    switch (true) {
        case years > 0:
            num = years
            unit = text.year
            break
        case months > 0:
            num = months
            unit = text.month
            break
        case days > 0:
            num = days
            unit = text.day
            break
        case hours > 0:
            num = hours
            unit = text.hour
            break
        case minutes > 0:
            num = minutes
            unit = text.minute
            break
        default:
            num = seconds
            unit = text.second
            break
    }
    if (locale === 'en') {
        if (num === 1) {
            num = 'a'
        } else {
            unit += 's'
        }
    }
    return text.template.replace(/{\s*num\s*}/g, num + '').replace(/{\s*unit\s*}/g, unit).replace(/{\s*suffix\s*}/g,
        suffix)
}
uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue
对比新文件
@@ -0,0 +1,88 @@
<template>
    <text>{{dateShow}}</text>
</template>
<script>
    import {friendlyDate} from './date-format.js'
    /**
     * Dateformat 日期格式化
     * @description 日期格式化组件
     * @tutorial https://ext.dcloud.net.cn/plugin?id=3279
     * @property {Object|String|Number} date 日期对象/日期字符串/时间戳
     * @property {String} locale 格式化使用的语言
     *     @value zh 中文
     *     @value en 英文
     * @property {Array} threshold 应用不同类型格式化的阈值
     * @property {String} format 输出日期字符串时的格式
     */
    export default {
        name: 'uniDateformat',
        props: {
            date: {
                type: [Object, String, Number],
                default () {
                    return '-'
                }
            },
            locale: {
                type: String,
                default: 'zh',
            },
            threshold: {
                type: Array,
                default () {
                    return [0, 0]
                }
            },
            format: {
                type: String,
                default: 'yyyy/MM/dd hh:mm:ss'
            },
            // refreshRate使用不当可能导致性能问题,谨慎使用
            refreshRate: {
                type: [Number, String],
                default: 0
            }
        },
        data() {
            return {
                refreshMark: 0
            }
        },
        computed: {
            dateShow() {
                this.refreshMark
                return friendlyDate(this.date, {
                    locale: this.locale,
                    threshold: this.threshold,
                    format: this.format
                })
            }
        },
        watch: {
            refreshRate: {
                handler() {
                    this.setAutoRefresh()
                },
                immediate: true
            }
        },
        methods: {
            refresh() {
                this.refreshMark++
            },
            setAutoRefresh() {
                clearInterval(this.refreshInterval)
                if (this.refreshRate) {
                    this.refreshInterval = setInterval(() => {
                        this.refresh()
                    }, parseInt(this.refreshRate))
                }
            }
        }
    }
</script>
<style>
</style>
uni_modules/uni-dateformat/package.json
对比新文件
@@ -0,0 +1,88 @@
{
  "id": "uni-dateformat",
  "displayName": "uni-dateformat 日期格式化",
  "version": "1.0.0",
  "description": "日期格式化组件,可以将日期格式化为1分钟前、刚刚等形式",
  "keywords": [
    "uni-ui",
    "uniui",
    "日期格式化",
    "时间格式化",
    "格式化时间",
    ""
],
  "repository": "https://github.com/dcloudio/uni-ui",
  "engines": {
    "HBuilderX": ""
  },
  "directories": {
    "example": "../../temps/example_temps"
  },
  "dcloudext": {
    "category": [
      "前端组件",
      "通用组件"
    ],
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "无",
      "permissions": "无"
    },
    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
  },
  "uni_modules": {
    "dependencies": ["uni-scss"],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y"
      },
      "client": {
        "App": {
          "app-vue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y"
        },
        "快应用": {
          "华为": "y",
          "联盟": "y"
        },
        "Vue": {
            "vue2": "y",
            "vue3": "y"
        }
      }
    }
  }
}
uni_modules/uni-dateformat/readme.md
对比新文件
@@ -0,0 +1,11 @@
### DateFormat 日期格式化
> **组件名:uni-dateformat**
> 代码块: `uDateformat`
日期格式化组件。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-dateformat)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
uni_modules/uni-datetime-picker/changelog.md
对比新文件
@@ -0,0 +1,168 @@
## 2.2.38(2024-10-15)
- 修复 微信小程序中的getSystemInfo警告
## 2.2.37(2024-10-12)
- 修复 微信小程序中的getSystemInfo警告
## 2.2.36(2024-10-12)
- 修复 微信小程序中的getSystemInfo警告
## 2.2.35(2024-09-21)
- 修复 没有选中日期时点击确定直接报错的Bug [详情](https://ask.dcloud.net.cn/question/198168)
## 2.2.34(2024-04-24)
- 新增 日期点击事件,在点击日期时会触发该事件。
## 2.2.33(2024-04-15)
- 修复 抖音小程序事件传递失效bug
## 2.2.32(2024-02-20)
- 修复 日历的close事件触发异常的bug [详情](https://github.com/dcloudio/uni-ui/issues/844)
## 2.2.31(2024-02-20)
- 修复 h5平台 右边日历的月份默认+1的bug [详情](https://github.com/dcloudio/uni-ui/issues/841)
## 2.2.30(2024-01-31)
- 修复 隐藏“秒”时,在IOS15及以下版本时出现 结束时间在开始时间之前 的bug [详情](https://github.com/dcloudio/uni-ui/issues/788)
## 2.2.29(2024-01-20)
- 新增 show事件,弹窗弹出时触发该事件 [详情](https://github.com/dcloudio/uni-app/issues/4694)
## 2.2.28(2024-01-18)
- 去除 noChange事件,当进行日期范围选择时,若只选了一天,则开始结束日期都为同一天 [详情](https://github.com/dcloudio/uni-ui/issues/815)
## 2.2.27(2024-01-10)
- 优化 增加noChange事件,当进行日期范围选择时,若有空值,则触发该事件 [详情](https://github.com/dcloudio/uni-ui/issues/815)
## 2.2.26(2024-01-08)
- 修复 字节小程序时间选择范围器失效问题 [详情](https://github.com/dcloudio/uni-ui/issues/834)
## 2.2.25(2023-10-18)
- 修复 PC端初次修改时间,开始时间未更新的Bug [详情](https://github.com/dcloudio/uni-ui/issues/737)
## 2.2.24(2023-06-02)
- 修复 部分情况修改时间,开始、结束时间显示异常的Bug [详情](https://ask.dcloud.net.cn/question/171146)
- 优化 当前月可以选择上月、下月的日期的Bug
## 2.2.23(2023-05-02)
- 修复 部分情况修改时间,开始时间未更新的Bug [详情](https://github.com/dcloudio/uni-ui/issues/737)
- 修复 部分平台及设备第一次点击无法显示弹框的Bug
- 修复 ios 日期格式未补零显示及使用异常的Bug [详情](https://ask.dcloud.net.cn/question/162979)
## 2.2.22(2023-03-30)
- 修复 日历 picker 修改年月后,自动选中当月1日的Bug [详情](https://ask.dcloud.net.cn/question/165937)
- 修复 小程序端 低版本 ios NaN的Bug [详情](https://ask.dcloud.net.cn/question/162979)
## 2.2.21(2023-02-20)
- 修复 firefox 浏览器显示区域点击无法拉起日历弹框的Bug [详情](https://ask.dcloud.net.cn/question/163362)
## 2.2.20(2023-02-17)
- 优化 值为空依然选中当天问题
- 优化 提供 default-value 属性支持配置选择器打开时默认显示的时间
- 优化 非范围选择未选择日期时间,点击确认按钮选中当前日期时间
- 优化 字节小程序日期时间范围选择,底部日期换行的Bug
## 2.2.19(2023-02-09)
- 修复 2.2.18 引起范围选择配置 end 选择无效的Bug [详情](https://github.com/dcloudio/uni-ui/issues/686)
## 2.2.18(2023-02-08)
- 修复 移动端范围选择change事件触发异常的Bug [详情](https://github.com/dcloudio/uni-ui/issues/684)
- 优化 PC端输入日期格式错误时返回当前日期时间
- 优化 PC端输入日期时间超出 start、end 限制的Bug
- 优化 移动端日期时间范围用法时间展示不完整问题
## 2.2.17(2023-02-04)
- 修复 小程序端绑定 Date 类型报错的Bug [详情](https://github.com/dcloudio/uni-ui/issues/679)
- 修复 vue3 time-picker 无法显示绑定时分秒的Bug
## 2.2.16(2023-02-02)
- 修复 字节小程序报错的Bug
## 2.2.15(2023-02-02)
- 修复 某些情况切换月份错误的Bug
## 2.2.14(2023-01-30)
- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/162033)
## 2.2.13(2023-01-10)
- 修复 多次加载组件造成内存占用的Bug
## 2.2.12(2022-12-01)
- 修复 vue3 下 i18n 国际化初始值不正确的Bug
## 2.2.11(2022-09-19)
- 修复 支付宝小程序样式错乱的Bug [详情](https://github.com/dcloudio/uni-app/issues/3861)
## 2.2.10(2022-09-19)
- 修复 反向选择日期范围,日期显示异常的Bug [详情](https://ask.dcloud.net.cn/question/153401?item_id=212892&rf=false)
## 2.2.9(2022-09-16)
- 可以使用 uni-scss 控制主题色
## 2.2.8(2022-09-08)
- 修复 close事件无效的Bug
## 2.2.7(2022-09-05)
- 修复 移动端 maskClick 无效的Bug [详情](https://ask.dcloud.net.cn/question/140824)
## 2.2.6(2022-06-30)
- 优化 组件样式,调整了组件图标大小、高度、颜色等,与uni-ui风格保持一致
## 2.2.5(2022-06-24)
- 修复 日历顶部年月及底部确认未国际化的Bug
## 2.2.4(2022-03-31)
- 修复 Vue3 下动态赋值,单选类型未响应的Bug
## 2.2.3(2022-03-28)
- 修复 Vue3 下动态赋值未响应的Bug
## 2.2.2(2021-12-10)
- 修复 clear-icon 属性在小程序平台不生效的Bug
## 2.2.1(2021-12-10)
- 修复 日期范围选在小程序平台,必须多点击一次才能取消选中状态的Bug
## 2.2.0(2021-11-19)
- 优化 组件UI,并提供设计资源 [详情](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移 [https://uniapp.dcloud.io/component/uniui/uni-datetime-picker](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
## 2.1.5(2021-11-09)
- 新增 提供组件设计资源,组件样式调整
## 2.1.4(2021-09-10)
- 修复 hide-second 在移动端的Bug
- 修复 单选赋默认值时,赋值日期未高亮的Bug
- 修复 赋默认值时,移动端未正确显示时间的Bug
## 2.1.3(2021-09-09)
- 新增 hide-second 属性,支持只使用时分,隐藏秒
## 2.1.2(2021-09-03)
- 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次
- 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法
- 优化 调整字号大小,美化日历界面
- 修复 因国际化导致的 placeholder 失效的Bug
## 2.1.1(2021-08-24)
- 新增 支持国际化
- 优化 范围选择器在 pc 端过宽的问题
## 2.1.0(2021-08-09)
- 新增 适配 vue3
## 2.0.19(2021-08-09)
- 新增 支持作为 uni-forms 子组件相关功能
- 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的Bug
## 2.0.18(2021-08-05)
- 修复 type 属性动态赋值无效的Bug
- 修复 ‘确认’按钮被 tabbar 遮盖 bug
- 修复 组件未赋值时范围选左、右日历相同的Bug
## 2.0.17(2021-08-04)
- 修复 范围选未正确显示当前值的Bug
- 修复 h5 平台(移动端)报错 'cale' of undefined 的Bug
## 2.0.16(2021-07-21)
- 新增 return-type 属性支持返回 date 日期对象
## 2.0.15(2021-07-14)
- 修复 单选日期类型,初始赋值后不在当前日历的Bug
- 新增 clearIcon 属性,显示框的清空按钮可配置显示隐藏(仅 pc 有效)
- 优化 移动端移除显示框的清空按钮,无实际用途
## 2.0.14(2021-07-14)
- 修复 组件赋值为空,界面未更新的Bug
- 修复 start 和 end 不能动态赋值的Bug
- 修复 范围选类型,用户选择后再次选择右侧日历(结束日期)显示不正确的Bug
## 2.0.13(2021-07-08)
- 修复 范围选择不能动态赋值的Bug
## 2.0.12(2021-07-08)
- 修复 范围选择的初始时间在一个月内时,造成无法选择的bug
## 2.0.11(2021-07-08)
- 优化 弹出层在超出视窗边缘定位不准确的问题
## 2.0.10(2021-07-08)
- 修复 范围起始点样式的背景色与今日样式的字体前景色融合,导致日期字体看不清的Bug
- 优化 弹出层在超出视窗边缘被遮盖的问题
## 2.0.9(2021-07-07)
- 新增 maskClick 事件
- 修复 特殊情况日历 rpx 布局错误的Bug,rpx -> px
- 修复 范围选择时清空返回值不合理的bug,['', ''] -> []
## 2.0.8(2021-07-07)
- 新增 日期时间显示框支持插槽
## 2.0.7(2021-07-01)
- 优化 添加 uni-icons 依赖
## 2.0.6(2021-05-22)
- 修复 图标在小程序上不显示的Bug
- 优化 重命名引用组件,避免潜在组件命名冲突
## 2.0.5(2021-05-20)
- 优化 代码目录扁平化
## 2.0.4(2021-05-12)
- 新增 组件示例地址
## 2.0.3(2021-05-10)
- 修复 ios 下不识别 '-' 日期格式的Bug
- 优化 pc 下弹出层添加边框和阴影
## 2.0.2(2021-05-08)
- 修复 在 admin 中获取弹出层定位错误的bug
## 2.0.1(2021-05-08)
- 修复 type 属性向下兼容,默认值从 date 变更为 datetime
## 2.0.0(2021-04-30)
- 支持日历形式的日期+时间的范围选择
 > 注意:此版本不向后兼容,不再支持单独时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)
## 1.0.6(2021-03-18)
- 新增 hide-second 属性,时间支持仅选择时、分
- 修复 选择跟显示的日期不一样的Bug
- 修复 chang事件触发2次的Bug
- 修复 分、秒 end 范围错误的Bug
- 优化 更好的 nvue 适配
uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue
对比新文件
@@ -0,0 +1,177 @@
<template>
    <view class="uni-calendar-item__weeks-box" :class="{
        'uni-calendar-item--disable':weeks.disable,
        'uni-calendar-item--before-checked-x':weeks.beforeMultiple,
        'uni-calendar-item--multiple': weeks.multiple,
        'uni-calendar-item--after-checked-x':weeks.afterMultiple,
        }" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)">
        <view class="uni-calendar-item__weeks-box-item" :class="{
                'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && (calendar.userChecked || !checkHover),
                'uni-calendar-item--checked-range-text': checkHover,
                'uni-calendar-item--before-checked':weeks.beforeMultiple,
                'uni-calendar-item--multiple': weeks.multiple,
                'uni-calendar-item--after-checked':weeks.afterMultiple,
                'uni-calendar-item--disable':weeks.disable,
                }">
            <text v-if="selected && weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
            <text class="uni-calendar-item__weeks-box-text uni-calendar-item__weeks-box-text-disable uni-calendar-item--checked-text">{{weeks.date}}</text>
        </view>
        <view :class="{'uni-calendar-item--today': weeks.isToday}"></view>
    </view>
</template>
<script>
    export default {
        props: {
            weeks: {
                type: Object,
                default () {
                    return {}
                }
            },
            calendar: {
                type: Object,
                default: () => {
                    return {}
                }
            },
            selected: {
                type: Array,
                default: () => {
                    return []
                }
            },
            checkHover: {
                type: Boolean,
                default: false
            }
        },
        methods: {
            choiceDate(weeks) {
                this.$emit('change', weeks)
            },
            handleMousemove(weeks) {
                this.$emit('handleMouse', weeks)
            }
        }
    }
</script>
<style lang="scss" >
    $uni-primary: #007aff !default;
    .uni-calendar-item__weeks-box {
        flex: 1;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: column;
        justify-content: center;
        align-items: center;
        margin: 1px 0;
        position: relative;
    }
    .uni-calendar-item__weeks-box-text {
        font-size: 14px;
        // font-family: Lato-Bold, Lato;
        font-weight: bold;
        color: darken($color: $uni-primary, $amount: 40%);
    }
    .uni-calendar-item__weeks-box-item {
        position: relative;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: column;
        justify-content: center;
        align-items: center;
        width: 40px;
        height: 40px;
        /* #ifdef H5 */
        cursor: pointer;
        /* #endif */
    }
    .uni-calendar-item__weeks-box-circle {
        position: absolute;
        top: 5px;
        right: 5px;
        width: 8px;
        height: 8px;
        border-radius: 8px;
        background-color: #dd524d;
    }
    .uni-calendar-item__weeks-box .uni-calendar-item--disable {
        cursor: default;
    }
    .uni-calendar-item--disable .uni-calendar-item__weeks-box-text-disable {
        color: #D1D1D1;
    }
    .uni-calendar-item--today {
        position: absolute;
        top: 10px;
        right: 17%;
        background-color: #dd524d;
        width:6px;
        height: 6px;
        border-radius: 50%;
    }
    .uni-calendar-item--extra {
        color: #dd524d;
        opacity: 0.8;
    }
    .uni-calendar-item__weeks-box .uni-calendar-item--checked {
        background-color: $uni-primary;
        border-radius: 50%;
        box-sizing: border-box;
        border: 3px solid #fff;
    }
    .uni-calendar-item--checked .uni-calendar-item--checked-text {
        color: #fff;
    }
    .uni-calendar-item--multiple .uni-calendar-item--checked-range-text {
        color: #333;
    }
    .uni-calendar-item--multiple {
        background-color:  #F6F7FC;
        // color: #fff;
    }
    .uni-calendar-item--multiple .uni-calendar-item--before-checked,
    .uni-calendar-item--multiple .uni-calendar-item--after-checked {
        background-color: $uni-primary;
        border-radius: 50%;
        box-sizing: border-box;
        border: 3px solid #F6F7FC;
    }
    .uni-calendar-item--before-checked .uni-calendar-item--checked-text,
    .uni-calendar-item--after-checked .uni-calendar-item--checked-text {
        color: #fff;
    }
    .uni-calendar-item--before-checked-x {
        border-top-left-radius: 50px;
        border-bottom-left-radius: 50px;
        box-sizing: border-box;
        background-color: #F6F7FC;
    }
    .uni-calendar-item--after-checked-x {
        border-top-right-radius: 50px;
        border-bottom-right-radius: 50px;
        background-color: #F6F7FC;
    }
</style>
uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
对比新文件
@@ -0,0 +1,947 @@
<template>
    <view class="uni-calendar" @mouseleave="leaveCale">
        <view v-if="!insert && show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}"
            @click="maskClick"></view>
        <view v-if="insert || show" class="uni-calendar__content"
            :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow, 'uni-calendar__content-mobile': aniMaskShow}">
            <view class="uni-calendar__header" :class="{'uni-calendar__header-mobile' :!insert}">
                <view class="uni-calendar__header-btn-box" @click.stop="changeMonth('pre')">
                    <view class="uni-calendar__header-btn uni-calendar--left"></view>
                </view>
                <picker mode="date" :value="date" fields="month" @change="bindDateChange">
                    <text
                        class="uni-calendar__header-text">{{ (nowDate.year||'') + yearText + ( nowDate.month||'') + monthText}}</text>
                </picker>
                <view class="uni-calendar__header-btn-box" @click.stop="changeMonth('next')">
                    <view class="uni-calendar__header-btn uni-calendar--right"></view>
                </view>
                <view v-if="!insert" class="dialog-close" @click="maskClick">
                    <view class="dialog-close-plus" data-id="close"></view>
                    <view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
                </view>
            </view>
            <view class="uni-calendar__box">
                <view v-if="showMonth" class="uni-calendar__box-bg">
                    <text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
                </view>
                <view class="uni-calendar__weeks" style="padding-bottom: 7px;">
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
                    </view>
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{MONText}}</text>
                    </view>
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
                    </view>
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
                    </view>
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{THUText}}</text>
                    </view>
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
                    </view>
                    <view class="uni-calendar__weeks-day">
                        <text class="uni-calendar__weeks-day-text">{{SATText}}</text>
                    </view>
                </view>
                <view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
                    <view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
                        <calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected"
                            :checkHover="range" @change="choiceDate" @handleMouse="handleMouse">
                        </calendar-item>
                    </view>
                </view>
            </view>
            <view v-if="!insert && !range && hasTime" class="uni-date-changed uni-calendar--fixed-top"
                style="padding: 0 80px;">
                <view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view>
                <time-picker type="time" :start="timepickerStartTime" :end="timepickerEndTime" v-model="time"
                    :disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style">
                </time-picker>
            </view>
            <view v-if="!insert && range && hasTime" class="uni-date-changed uni-calendar--fixed-top">
                <view class="uni-date-changed--time-start">
                    <view class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}
                    </view>
                    <time-picker type="time" :start="timepickerStartTime" v-model="timeRange.startTime" :border="false"
                        :hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style">
                    </time-picker>
                </view>
                <view style="line-height: 50px;">
                    <uni-icons type="arrowthinright" color="#999"></uni-icons>
                </view>
                <view class="uni-date-changed--time-end">
                    <view class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</view>
                    <time-picker type="time" :end="timepickerEndTime" v-model="timeRange.endTime" :border="false"
                        :hide-second="hideSecond" :disabled="!tempRange.after" class="time-picker-style">
                    </time-picker>
                </view>
            </view>
            <view v-if="!insert" class="uni-date-changed uni-date-btn--ok">
                <view class="uni-datetime-picker--btn" @click="confirm">{{confirmText}}</view>
            </view>
        </view>
    </view>
</template>
<script>
    import {
        Calendar,
        getDate,
        getTime
    } from './util.js';
    import calendarItem from './calendar-item.vue'
    import timePicker from './time-picker.vue'
    import {
        initVueI18n
    } from '@dcloudio/uni-i18n'
    import i18nMessages from './i18n/index.js'
    const {
        t
    } = initVueI18n(i18nMessages)
    /**
     * Calendar 日历
     * @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
     * @tutorial https://ext.dcloud.net.cn/plugin?id=56
     * @property {String} date 自定义当前时间,默认为今天
     * @property {String} startDate 日期选择范围-开始日期
     * @property {String} endDate 日期选择范围-结束日期
     * @property {Boolean} range 范围选择
     * @property {Boolean} insert = [true|false] 插入模式,默认为false
     *     @value true 弹窗模式
     *     @value false 插入模式
     * @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
     * @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
     * @property {Boolean} showMonth 是否选择月份为背景
     * @property {[String} defaultValue 选择器打开时默认显示的时间
     * @event {Function} change 日期改变,`insert :ture` 时生效
     * @event {Function} confirm 确认选择`insert :false` 时生效
     * @event {Function} monthSwitch 切换月份时触发
     * @example <uni-calendar :insert="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
     */
    export default {
        components: {
            calendarItem,
            timePicker
        },
        options: {
            // #ifdef MP-TOUTIAO
            virtualHost: false,
            // #endif
            // #ifndef MP-TOUTIAO
            virtualHost: true
            // #endif
        },
        props: {
            date: {
                type: String,
                default: ''
            },
            defTime: {
                type: [String, Object],
                default: ''
            },
            selectableTimes: {
                type: [Object],
                default () {
                    return {}
                }
            },
            selected: {
                type: Array,
                default () {
                    return []
                }
            },
            startDate: {
                type: String,
                default: ''
            },
            endDate: {
                type: String,
                default: ''
            },
            startPlaceholder: {
                type: String,
                default: ''
            },
            endPlaceholder: {
                type: String,
                default: ''
            },
            range: {
                type: Boolean,
                default: false
            },
            hasTime: {
                type: Boolean,
                default: false
            },
            insert: {
                type: Boolean,
                default: true
            },
            showMonth: {
                type: Boolean,
                default: true
            },
            clearDate: {
                type: Boolean,
                default: true
            },
            checkHover: {
                type: Boolean,
                default: true
            },
            hideSecond: {
                type: [Boolean],
                default: false
            },
            pleStatus: {
                type: Object,
                default () {
                    return {
                        before: '',
                        after: '',
                        data: [],
                        fulldate: ''
                    }
                }
            },
            defaultValue: {
                type: [String, Object, Array],
                default: ''
            }
        },
        data() {
            return {
                show: false,
                weeks: [],
                calendar: {},
                nowDate: {},
                aniMaskShow: false,
                firstEnter: true,
                time: '',
                timeRange: {
                    startTime: '',
                    endTime: ''
                },
                tempSingleDate: '',
                tempRange: {
                    before: '',
                    after: ''
                }
            }
        },
        watch: {
            date: {
                immediate: true,
                handler(newVal) {
                    if (!this.range) {
                        this.tempSingleDate = newVal
                        setTimeout(() => {
                            this.init(newVal)
                        }, 100)
                    }
                }
            },
            defTime: {
                immediate: true,
                handler(newVal) {
                    if (!this.range) {
                        this.time = newVal
                    } else {
                        this.timeRange.startTime = newVal.start
                        this.timeRange.endTime = newVal.end
                    }
                }
            },
            startDate(val) {
                // 字节小程序 watch 早于 created
                if (!this.cale) {
                    return
                }
                this.cale.setStartDate(val)
                this.cale.setDate(this.nowDate.fullDate)
                this.weeks = this.cale.weeks
            },
            endDate(val) {
                // 字节小程序 watch 早于 created
                if (!this.cale) {
                    return
                }
                this.cale.setEndDate(val)
                this.cale.setDate(this.nowDate.fullDate)
                this.weeks = this.cale.weeks
            },
            selected(newVal) {
                // 字节小程序 watch 早于 created
                if (!this.cale) {
                    return
                }
                this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
                this.weeks = this.cale.weeks
            },
            pleStatus: {
                immediate: true,
                handler(newVal) {
                    const {
                        before,
                        after,
                        fulldate,
                        which
                    } = newVal
                    this.tempRange.before = before
                    this.tempRange.after = after
                    setTimeout(() => {
                        if (fulldate) {
                            this.cale.setHoverMultiple(fulldate)
                            if (before && after) {
                                this.cale.lastHover = true
                                if (this.rangeWithinMonth(after, before)) return
                                this.setDate(before)
                            } else {
                                this.cale.setMultiple(fulldate)
                                this.setDate(this.nowDate.fullDate)
                                this.calendar.fullDate = ''
                                this.cale.lastHover = false
                            }
                        } else {
                            // 字节小程序 watch 早于 created
                            if (!this.cale) {
                                return
                            }
                            this.cale.setDefaultMultiple(before, after)
                            if (which === 'left' && before) {
                                this.setDate(before)
                                this.weeks = this.cale.weeks
                            } else if (after) {
                                this.setDate(after)
                                this.weeks = this.cale.weeks
                            }
                            this.cale.lastHover = true
                        }
                    }, 16)
                }
            }
        },
        computed: {
            timepickerStartTime() {
                const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate
                return activeDate === this.startDate ? this.selectableTimes.start : ''
            },
            timepickerEndTime() {
                const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate
                return activeDate === this.endDate ? this.selectableTimes.end : ''
            },
            /**
             * for i18n
             */
            selectDateText() {
                return t("uni-datetime-picker.selectDate")
            },
            startDateText() {
                return this.startPlaceholder || t("uni-datetime-picker.startDate")
            },
            endDateText() {
                return this.endPlaceholder || t("uni-datetime-picker.endDate")
            },
            okText() {
                return t("uni-datetime-picker.ok")
            },
            yearText() {
                return t("uni-datetime-picker.year")
            },
            monthText() {
                return t("uni-datetime-picker.month")
            },
            MONText() {
                return t("uni-calender.MON")
            },
            TUEText() {
                return t("uni-calender.TUE")
            },
            WEDText() {
                return t("uni-calender.WED")
            },
            THUText() {
                return t("uni-calender.THU")
            },
            FRIText() {
                return t("uni-calender.FRI")
            },
            SATText() {
                return t("uni-calender.SAT")
            },
            SUNText() {
                return t("uni-calender.SUN")
            },
            confirmText() {
                return t("uni-calender.confirm")
            },
        },
        created() {
            // 获取日历方法实例
            this.cale = new Calendar({
                selected: this.selected,
                startDate: this.startDate,
                endDate: this.endDate,
                range: this.range,
            })
            // 选中某一天
            this.init(this.date)
        },
        methods: {
            leaveCale() {
                this.firstEnter = true
            },
            handleMouse(weeks) {
                if (weeks.disable) return
                if (this.cale.lastHover) return
                let {
                    before,
                    after
                } = this.cale.multipleStatus
                if (!before) return
                this.calendar = weeks
                // 设置范围选
                this.cale.setHoverMultiple(this.calendar.fullDate)
                this.weeks = this.cale.weeks
                // hover时,进入一个日历,更新另一个
                if (this.firstEnter) {
                    this.$emit('firstEnterCale', this.cale.multipleStatus)
                    this.firstEnter = false
                }
            },
            rangeWithinMonth(A, B) {
                const [yearA, monthA] = A.split('-')
                const [yearB, monthB] = B.split('-')
                return yearA === yearB && monthA === monthB
            },
            // 蒙版点击事件
            maskClick() {
                this.close()
                this.$emit('maskClose')
            },
            clearCalender() {
                if (this.range) {
                    this.timeRange.startTime = ''
                    this.timeRange.endTime = ''
                    this.tempRange.before = ''
                    this.tempRange.after = ''
                    this.cale.multipleStatus.before = ''
                    this.cale.multipleStatus.after = ''
                    this.cale.multipleStatus.data = []
                    this.cale.lastHover = false
                } else {
                    this.time = ''
                    this.tempSingleDate = ''
                }
                this.calendar.fullDate = ''
                this.setDate(new Date())
            },
            bindDateChange(e) {
                const value = e.detail.value + '-1'
                this.setDate(value)
            },
            /**
             * 初始化日期显示
             * @param {Object} date
             */
            init(date) {
                // 字节小程序 watch 早于 created
                if (!this.cale) {
                    return
                }
                this.cale.setDate(date || new Date())
                this.weeks = this.cale.weeks
                this.nowDate = this.cale.getInfo(date)
                this.calendar = {
                    ...this.nowDate
                }
                if (!date) {
                    // 优化date为空默认不选中今天
                    this.calendar.fullDate = ''
                    if (this.defaultValue && !this.range) {
                        // 暂时只支持移动端非范围选择
                        const defaultDate = new Date(this.defaultValue)
                        const fullDate = getDate(defaultDate)
                        const year = defaultDate.getFullYear()
                        const month = defaultDate.getMonth() + 1
                        const date = defaultDate.getDate()
                        const day = defaultDate.getDay()
                        this.calendar = {
                                fullDate,
                                year,
                                month,
                                date,
                                day
                            },
                            this.tempSingleDate = fullDate
                        this.time = getTime(defaultDate, this.hideSecond)
                    }
                }
            },
            /**
             * 打开日历弹窗
             */
            open() {
                // 弹窗模式并且清理数据
                if (this.clearDate && !this.insert) {
                    this.cale.cleanMultipleStatus()
                    this.init(this.date)
                }
                this.show = true
                this.$nextTick(() => {
                    setTimeout(() => {
                        this.aniMaskShow = true
                    }, 50)
                })
            },
            /**
             * 关闭日历弹窗
             */
            close() {
                this.aniMaskShow = false
                this.$nextTick(() => {
                    setTimeout(() => {
                        this.show = false
                        this.$emit('close')
                    }, 300)
                })
            },
            /**
             * 确认按钮
             */
            confirm() {
                this.setEmit('confirm')
                this.close()
            },
            /**
             * 变化触发
             */
            change(isSingleChange) {
                if (!this.insert && !isSingleChange) return
                this.setEmit('change')
            },
            /**
             * 选择月份触发
             */
            monthSwitch() {
                let {
                    year,
                    month
                } = this.nowDate
                this.$emit('monthSwitch', {
                    year,
                    month: Number(month)
                })
            },
            /**
             * 派发事件
             * @param {Object} name
             */
            setEmit(name) {
                if (!this.range) {
                    if (!this.calendar.fullDate) {
                        this.calendar = this.cale.getInfo(new Date())
                        this.tempSingleDate = this.calendar.fullDate
                    }
                    if (this.hasTime && !this.time) {
                        this.time = getTime(new Date(), this.hideSecond)
                    }
                }
                let {
                    year,
                    month,
                    date,
                    fullDate,
                    extraInfo
                } = this.calendar
                this.$emit(name, {
                    range: this.cale.multipleStatus,
                    year,
                    month,
                    date,
                    time: this.time,
                    timeRange: this.timeRange,
                    fulldate: fullDate,
                    extraInfo: extraInfo || {}
                })
            },
            /**
             * 选择天触发
             * @param {Object} weeks
             */
            choiceDate(weeks) {
                if (weeks.disable) return
                this.calendar = weeks
                this.calendar.userChecked = true
                // 设置多选
                this.cale.setMultiple(this.calendar.fullDate, true)
                this.weeks = this.cale.weeks
                this.tempSingleDate = this.calendar.fullDate
                const beforeDate = new Date(this.cale.multipleStatus.before).getTime()
                const afterDate = new Date(this.cale.multipleStatus.after).getTime()
                if (beforeDate > afterDate && afterDate) {
                    this.tempRange.before = this.cale.multipleStatus.after
                    this.tempRange.after = this.cale.multipleStatus.before
                } else {
                    this.tempRange.before = this.cale.multipleStatus.before
                    this.tempRange.after = this.cale.multipleStatus.after
                }
                this.change(true)
            },
            changeMonth(type) {
                let newDate
                if (type === 'pre') {
                    newDate = this.cale.getPreMonthObj(this.nowDate.fullDate).fullDate
                } else if (type === 'next') {
                    newDate = this.cale.getNextMonthObj(this.nowDate.fullDate).fullDate
                }
                this.setDate(newDate)
                this.monthSwitch()
            },
            /**
             * 设置日期
             * @param {Object} date
             */
            setDate(date) {
                this.cale.setDate(date)
                this.weeks = this.cale.weeks
                this.nowDate = this.cale.getInfo(date)
            }
        }
    }
</script>
<style lang="scss">
    $uni-primary: #007aff !default;
    .uni-calendar {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: column;
    }
    .uni-calendar__mask {
        position: fixed;
        bottom: 0;
        top: 0;
        left: 0;
        right: 0;
        background-color: rgba(0, 0, 0, 0.4);
        transition-property: opacity;
        transition-duration: 0.3s;
        opacity: 0;
        /* #ifndef APP-NVUE */
        z-index: 99;
        /* #endif */
    }
    .uni-calendar--mask-show {
        opacity: 1
    }
    .uni-calendar--fixed {
        position: fixed;
        bottom: calc(var(--window-bottom));
        left: 0;
        right: 0;
        transition-property: transform;
        transition-duration: 0.3s;
        transform: translateY(460px);
        /* #ifndef APP-NVUE */
        z-index: 99;
        /* #endif */
    }
    .uni-calendar--ani-show {
        transform: translateY(0);
    }
    .uni-calendar__content {
        background-color: #fff;
    }
    .uni-calendar__content-mobile {
        border-top-left-radius: 10px;
        border-top-right-radius: 10px;
        box-shadow: 0px 0px 5px 3px rgba(0, 0, 0, 0.1);
    }
    .uni-calendar__header {
        position: relative;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
        justify-content: center;
        align-items: center;
        height: 50px;
    }
    .uni-calendar__header-mobile {
        padding: 10px;
        padding-bottom: 0;
    }
    .uni-calendar--fixed-top {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
        justify-content: space-between;
        border-top-color: rgba(0, 0, 0, 0.4);
        border-top-style: solid;
        border-top-width: 1px;
    }
    .uni-calendar--fixed-width {
        width: 50px;
    }
    .uni-calendar__backtoday {
        position: absolute;
        right: 0;
        top: 25rpx;
        padding: 0 5px;
        padding-left: 10px;
        height: 25px;
        line-height: 25px;
        font-size: 12px;
        border-top-left-radius: 25px;
        border-bottom-left-radius: 25px;
        color: #fff;
        background-color: #f1f1f1;
    }
    .uni-calendar__header-text {
        text-align: center;
        width: 100px;
        font-size: 15px;
        color: #666;
    }
    .uni-calendar__button-text {
        text-align: center;
        width: 100px;
        font-size: 14px;
        color: $uni-primary;
        /* #ifndef APP-NVUE */
        letter-spacing: 3px;
        /* #endif */
    }
    .uni-calendar__header-btn-box {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
        align-items: center;
        justify-content: center;
        width: 50px;
        height: 50px;
    }
    .uni-calendar__header-btn {
        width: 9px;
        height: 9px;
        border-left-color: #808080;
        border-left-style: solid;
        border-left-width: 1px;
        border-top-color: #555555;
        border-top-style: solid;
        border-top-width: 1px;
    }
    .uni-calendar--left {
        transform: rotate(-45deg);
    }
    .uni-calendar--right {
        transform: rotate(135deg);
    }
    .uni-calendar__weeks {
        position: relative;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
    }
    .uni-calendar__weeks-item {
        flex: 1;
    }
    .uni-calendar__weeks-day {
        flex: 1;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: column;
        justify-content: center;
        align-items: center;
        height: 40px;
        border-bottom-color: #F5F5F5;
        border-bottom-style: solid;
        border-bottom-width: 1px;
    }
    .uni-calendar__weeks-day-text {
        font-size: 12px;
        color: #B2B2B2;
    }
    .uni-calendar__box {
        position: relative;
        // padding: 0 10px;
        padding-bottom: 7px;
    }
    .uni-calendar__box-bg {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        justify-content: center;
        align-items: center;
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
    }
    .uni-calendar__box-bg-text {
        font-size: 200px;
        font-weight: bold;
        color: #999;
        opacity: 0.1;
        text-align: center;
        /* #ifndef APP-NVUE */
        line-height: 1;
        /* #endif */
    }
    .uni-date-changed {
        padding: 0 10px;
        // line-height: 50px;
        text-align: center;
        color: #333;
        border-top-color: #DCDCDC;
        ;
        border-top-style: solid;
        border-top-width: 1px;
        flex: 1;
    }
    .uni-date-btn--ok {
        padding: 20px 15px;
    }
    .uni-date-changed--time-start {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        align-items: center;
    }
    .uni-date-changed--time-end {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        align-items: center;
    }
    .uni-date-changed--time-date {
        color: #999;
        line-height: 50px;
        /* #ifdef MP-TOUTIAO */
        font-size: 16px;
        /* #endif */
        margin-right: 5px;
        // opacity: 0.6;
    }
    .time-picker-style {
        // width: 62px;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        justify-content: center;
        align-items: center
    }
    .mr-10 {
        margin-right: 10px;
    }
    .dialog-close {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
        align-items: center;
        padding: 0 25px;
        margin-top: 10px;
    }
    .dialog-close-plus {
        width: 16px;
        height: 2px;
        background-color: #737987;
        border-radius: 2px;
        transform: rotate(45deg);
    }
    .dialog-close-rotate {
        position: absolute;
        transform: rotate(-45deg);
    }
    .uni-datetime-picker--btn {
        border-radius: 100px;
        height: 40px;
        line-height: 40px;
        background-color: $uni-primary;
        color: #fff;
        font-size: 16px;
        letter-spacing: 2px;
    }
    /* #ifndef APP-NVUE */
    .uni-datetime-picker--btn:active {
        opacity: 0.7;
    }
    /* #endif */
</style>
uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json
对比新文件
@@ -0,0 +1,22 @@
{
    "uni-datetime-picker.selectDate": "select date",
    "uni-datetime-picker.selectTime": "select time",
    "uni-datetime-picker.selectDateTime": "select date and time",
    "uni-datetime-picker.startDate": "start date",
    "uni-datetime-picker.endDate": "end date",
    "uni-datetime-picker.startTime": "start time",
    "uni-datetime-picker.endTime": "end time",
    "uni-datetime-picker.ok": "ok",
    "uni-datetime-picker.clear": "clear",
    "uni-datetime-picker.cancel": "cancel",
    "uni-datetime-picker.year": "-",
    "uni-datetime-picker.month": "",
    "uni-calender.MON": "MON",
    "uni-calender.TUE": "TUE",
    "uni-calender.WED": "WED",
    "uni-calender.THU": "THU",
    "uni-calender.FRI": "FRI",
    "uni-calender.SAT": "SAT",
    "uni-calender.SUN": "SUN",
    "uni-calender.confirm": "confirm"
}
uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js
对比新文件
@@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
    en,
    'zh-Hans': zhHans,
    'zh-Hant': zhHant
}
uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json
对比新文件
@@ -0,0 +1,22 @@
{
    "uni-datetime-picker.selectDate": "选择日期",
    "uni-datetime-picker.selectTime": "选择时间",
    "uni-datetime-picker.selectDateTime": "选择日期时间",
    "uni-datetime-picker.startDate": "开始日期",
    "uni-datetime-picker.endDate": "结束日期",
    "uni-datetime-picker.startTime": "开始时间",
    "uni-datetime-picker.endTime": "结束时间",
    "uni-datetime-picker.ok": "确定",
    "uni-datetime-picker.clear": "清除",
    "uni-datetime-picker.cancel": "取消",
    "uni-datetime-picker.year": "年",
    "uni-datetime-picker.month": "月",
    "uni-calender.SUN": "日",
    "uni-calender.MON": "一",
    "uni-calender.TUE": "二",
    "uni-calender.WED": "三",
    "uni-calender.THU": "四",
    "uni-calender.FRI": "五",
    "uni-calender.SAT": "六",
    "uni-calender.confirm": "确认"
}
uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json
对比新文件
@@ -0,0 +1,22 @@
{
  "uni-datetime-picker.selectDate": "選擇日期",
  "uni-datetime-picker.selectTime": "選擇時間",
  "uni-datetime-picker.selectDateTime": "選擇日期時間",
  "uni-datetime-picker.startDate": "開始日期",
  "uni-datetime-picker.endDate": "結束日期",
  "uni-datetime-picker.startTime": "開始时间",
  "uni-datetime-picker.endTime": "結束时间",
  "uni-datetime-picker.ok": "確定",
  "uni-datetime-picker.clear": "清除",
  "uni-datetime-picker.cancel": "取消",
  "uni-datetime-picker.year": "年",
  "uni-datetime-picker.month": "月",
  "uni-calender.SUN": "日",
  "uni-calender.MON": "一",
  "uni-calender.TUE": "二",
  "uni-calender.WED": "三",
  "uni-calender.THU": "四",
  "uni-calender.FRI": "五",
  "uni-calender.SAT": "六",
  "uni-calender.confirm": "確認"
}
uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue
对比新文件
@@ -0,0 +1,940 @@
<template>
    <view class="uni-datetime-picker">
        <view @click="initTimePicker">
            <slot>
                <view class="uni-datetime-picker-timebox-pointer"
                    :class="{'uni-datetime-picker-disabled': disabled, 'uni-datetime-picker-timebox': border}">
                    <text class="uni-datetime-picker-text">{{time}}</text>
                    <view v-if="!time" class="uni-datetime-picker-time">
                        <text class="uni-datetime-picker-text">{{selectTimeText}}</text>
                    </view>
                </view>
            </slot>
        </view>
        <view v-if="visible" id="mask" class="uni-datetime-picker-mask" @click="tiggerTimePicker"></view>
        <view v-if="visible" class="uni-datetime-picker-popup" :class="[dateShow && timeShow ? '' : 'fix-nvue-height']"
            :style="fixNvueBug">
            <view class="uni-title">
                <text class="uni-datetime-picker-text">{{selectTimeText}}</text>
            </view>
            <view v-if="dateShow" class="uni-datetime-picker__container-box">
                <picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd"
                    @change="bindDateChange">
                    <picker-view-column>
                        <view class="uni-datetime-picker-item" v-for="(item,index) in years" :key="index">
                            <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
                        </view>
                    </picker-view-column>
                    <picker-view-column>
                        <view class="uni-datetime-picker-item" v-for="(item,index) in months" :key="index">
                            <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
                        </view>
                    </picker-view-column>
                    <picker-view-column>
                        <view class="uni-datetime-picker-item" v-for="(item,index) in days" :key="index">
                            <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
                        </view>
                    </picker-view-column>
                </picker-view>
                <!-- 兼容 nvue 不支持伪类 -->
                <text class="uni-datetime-picker-sign sign-left">-</text>
                <text class="uni-datetime-picker-sign sign-right">-</text>
            </view>
            <view v-if="timeShow" class="uni-datetime-picker__container-box">
                <picker-view class="uni-datetime-picker-view" :class="[hideSecond ? 'time-hide-second' : '']"
                    :indicator-style="indicatorStyle" :value="hms" @change="bindTimeChange">
                    <picker-view-column>
                        <view class="uni-datetime-picker-item" v-for="(item,index) in hours" :key="index">
                            <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
                        </view>
                    </picker-view-column>
                    <picker-view-column>
                        <view class="uni-datetime-picker-item" v-for="(item,index) in minutes" :key="index">
                            <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
                        </view>
                    </picker-view-column>
                    <picker-view-column v-if="!hideSecond">
                        <view class="uni-datetime-picker-item" v-for="(item,index) in seconds" :key="index">
                            <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
                        </view>
                    </picker-view-column>
                </picker-view>
                <!-- 兼容 nvue 不支持伪类 -->
                <text class="uni-datetime-picker-sign" :class="[hideSecond ? 'sign-center' : 'sign-left']">:</text>
                <text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right">:</text>
            </view>
            <view class="uni-datetime-picker-btn">
                <view @click="clearTime">
                    <text class="uni-datetime-picker-btn-text">{{clearText}}</text>
                </view>
                <view class="uni-datetime-picker-btn-group">
                    <view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">
                        <text class="uni-datetime-picker-btn-text">{{cancelText}}</text>
                    </view>
                    <view @click="setTime">
                        <text class="uni-datetime-picker-btn-text">{{okText}}</text>
                    </view>
                </view>
            </view>
        </view>
    </view>
</template>
<script>
    import {
        initVueI18n
    } from '@dcloudio/uni-i18n'
    import i18nMessages from './i18n/index.js'
    const {
        t
    } = initVueI18n(i18nMessages)
    import {
        fixIosDateFormat
    } from './util'
    /**
     * DatetimePicker 时间选择器
     * @description 可以同时选择日期和时间的选择器
     * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
     * @property {String} type = [datetime | date | time] 显示模式
     * @property {Boolean} multiple = [true|false] 是否多选
     * @property {String|Number} value 默认值
     * @property {String|Number} start 起始日期或时间
     * @property {String|Number} end 起始日期或时间
     * @property {String} return-type = [timestamp | string]
     * @event {Function} change  选中发生变化触发
     */
    export default {
        name: 'UniDatetimePicker',
        data() {
            return {
                indicatorStyle: `height: 50px;`,
                visible: false,
                fixNvueBug: {},
                dateShow: true,
                timeShow: true,
                title: '日期和时间',
                // 输入框当前时间
                time: '',
                // 当前的年月日时分秒
                year: 1920,
                month: 0,
                day: 0,
                hour: 0,
                minute: 0,
                second: 0,
                // 起始时间
                startYear: 1920,
                startMonth: 1,
                startDay: 1,
                startHour: 0,
                startMinute: 0,
                startSecond: 0,
                // 结束时间
                endYear: 2120,
                endMonth: 12,
                endDay: 31,
                endHour: 23,
                endMinute: 59,
                endSecond: 59,
            }
        },
        options: {
            // #ifdef MP-TOUTIAO
            virtualHost: false,
            // #endif
            // #ifndef MP-TOUTIAO
            virtualHost: true
            // #endif
        },
        props: {
            type: {
                type: String,
                default: 'datetime'
            },
            value: {
                type: [String, Number],
                default: ''
            },
            modelValue: {
                type: [String, Number],
                default: ''
            },
            start: {
                type: [Number, String],
                default: ''
            },
            end: {
                type: [Number, String],
                default: ''
            },
            returnType: {
                type: String,
                default: 'string'
            },
            disabled: {
                type: [Boolean, String],
                default: false
            },
            border: {
                type: [Boolean, String],
                default: true
            },
            hideSecond: {
                type: [Boolean, String],
                default: false
            }
        },
        watch: {
            // #ifndef VUE3
            value: {
                handler(newVal) {
                    if (newVal) {
                        this.parseValue(fixIosDateFormat(newVal))
                        this.initTime(false)
                    } else {
                        this.time = ''
                        this.parseValue(Date.now())
                    }
                },
                immediate: true
            },
            // #endif
            // #ifdef VUE3
            modelValue: {
                handler(newVal) {
                    if (newVal) {
                        this.parseValue(fixIosDateFormat(newVal))
                        this.initTime(false)
                    } else {
                        this.time = ''
                        this.parseValue(Date.now())
                    }
                },
                immediate: true
            },
            // #endif
            type: {
                handler(newValue) {
                    if (newValue === 'date') {
                        this.dateShow = true
                        this.timeShow = false
                        this.title = '日期'
                    } else if (newValue === 'time') {
                        this.dateShow = false
                        this.timeShow = true
                        this.title = '时间'
                    } else {
                        this.dateShow = true
                        this.timeShow = true
                        this.title = '日期和时间'
                    }
                },
                immediate: true
            },
            start: {
                handler(newVal) {
                    this.parseDatetimeRange(fixIosDateFormat(newVal), 'start')
                },
                immediate: true
            },
            end: {
                handler(newVal) {
                    this.parseDatetimeRange(fixIosDateFormat(newVal), 'end')
                },
                immediate: true
            },
            // 月、日、时、分、秒可选范围变化后,检查当前值是否在范围内,不在则当前值重置为可选范围第一项
            months(newVal) {
                this.checkValue('month', this.month, newVal)
            },
            days(newVal) {
                this.checkValue('day', this.day, newVal)
            },
            hours(newVal) {
                this.checkValue('hour', this.hour, newVal)
            },
            minutes(newVal) {
                this.checkValue('minute', this.minute, newVal)
            },
            seconds(newVal) {
                this.checkValue('second', this.second, newVal)
            }
        },
        computed: {
            // 当前年、月、日、时、分、秒选择范围
            years() {
                return this.getCurrentRange('year')
            },
            months() {
                return this.getCurrentRange('month')
            },
            days() {
                return this.getCurrentRange('day')
            },
            hours() {
                return this.getCurrentRange('hour')
            },
            minutes() {
                return this.getCurrentRange('minute')
            },
            seconds() {
                return this.getCurrentRange('second')
            },
            // picker 当前值数组
            ymd() {
                return [this.year - this.minYear, this.month - this.minMonth, this.day - this.minDay]
            },
            hms() {
                return [this.hour - this.minHour, this.minute - this.minMinute, this.second - this.minSecond]
            },
            // 当前 date 是 start
            currentDateIsStart() {
                return this.year === this.startYear && this.month === this.startMonth && this.day === this.startDay
            },
            // 当前 date 是 end
            currentDateIsEnd() {
                return this.year === this.endYear && this.month === this.endMonth && this.day === this.endDay
            },
            // 当前年、月、日、时、分、秒的最小值和最大值
            minYear() {
                return this.startYear
            },
            maxYear() {
                return this.endYear
            },
            minMonth() {
                if (this.year === this.startYear) {
                    return this.startMonth
                } else {
                    return 1
                }
            },
            maxMonth() {
                if (this.year === this.endYear) {
                    return this.endMonth
                } else {
                    return 12
                }
            },
            minDay() {
                if (this.year === this.startYear && this.month === this.startMonth) {
                    return this.startDay
                } else {
                    return 1
                }
            },
            maxDay() {
                if (this.year === this.endYear && this.month === this.endMonth) {
                    return this.endDay
                } else {
                    return this.daysInMonth(this.year, this.month)
                }
            },
            minHour() {
                if (this.type === 'datetime') {
                    if (this.currentDateIsStart) {
                        return this.startHour
                    } else {
                        return 0
                    }
                }
                if (this.type === 'time') {
                    return this.startHour
                }
            },
            maxHour() {
                if (this.type === 'datetime') {
                    if (this.currentDateIsEnd) {
                        return this.endHour
                    } else {
                        return 23
                    }
                }
                if (this.type === 'time') {
                    return this.endHour
                }
            },
            minMinute() {
                if (this.type === 'datetime') {
                    if (this.currentDateIsStart && this.hour === this.startHour) {
                        return this.startMinute
                    } else {
                        return 0
                    }
                }
                if (this.type === 'time') {
                    if (this.hour === this.startHour) {
                        return this.startMinute
                    } else {
                        return 0
                    }
                }
            },
            maxMinute() {
                if (this.type === 'datetime') {
                    if (this.currentDateIsEnd && this.hour === this.endHour) {
                        return this.endMinute
                    } else {
                        return 59
                    }
                }
                if (this.type === 'time') {
                    if (this.hour === this.endHour) {
                        return this.endMinute
                    } else {
                        return 59
                    }
                }
            },
            minSecond() {
                if (this.type === 'datetime') {
                    if (this.currentDateIsStart && this.hour === this.startHour && this.minute === this.startMinute) {
                        return this.startSecond
                    } else {
                        return 0
                    }
                }
                if (this.type === 'time') {
                    if (this.hour === this.startHour && this.minute === this.startMinute) {
                        return this.startSecond
                    } else {
                        return 0
                    }
                }
            },
            maxSecond() {
                if (this.type === 'datetime') {
                    if (this.currentDateIsEnd && this.hour === this.endHour && this.minute === this.endMinute) {
                        return this.endSecond
                    } else {
                        return 59
                    }
                }
                if (this.type === 'time') {
                    if (this.hour === this.endHour && this.minute === this.endMinute) {
                        return this.endSecond
                    } else {
                        return 59
                    }
                }
            },
            /**
             * for i18n
             */
            selectTimeText() {
                return t("uni-datetime-picker.selectTime")
            },
            okText() {
                return t("uni-datetime-picker.ok")
            },
            clearText() {
                return t("uni-datetime-picker.clear")
            },
            cancelText() {
                return t("uni-datetime-picker.cancel")
            }
        },
        mounted() {
            // #ifdef APP-NVUE
            const res = uni.getSystemInfoSync();
            this.fixNvueBug = {
                top: res.windowHeight / 2,
                left: res.windowWidth / 2
            }
            // #endif
        },
        methods: {
            /**
             * @param {Object} item
             * 小于 10 在前面加个 0
             */
            lessThanTen(item) {
                return item < 10 ? '0' + item : item
            },
            /**
             * 解析时分秒字符串,例如:00:00:00
             * @param {String} timeString
             */
            parseTimeType(timeString) {
                if (timeString) {
                    let timeArr = timeString.split(':')
                    this.hour = Number(timeArr[0])
                    this.minute = Number(timeArr[1])
                    this.second = Number(timeArr[2])
                }
            },
            /**
             * 解析选择器初始值,类型可以是字符串、时间戳,例如:2000-10-02、'08:30:00'、 1610695109000
             * @param {String | Number} datetime
             */
            initPickerValue(datetime) {
                let defaultValue = null
                if (datetime) {
                    defaultValue = this.compareValueWithStartAndEnd(datetime, this.start, this.end)
                } else {
                    defaultValue = Date.now()
                    defaultValue = this.compareValueWithStartAndEnd(defaultValue, this.start, this.end)
                }
                this.parseValue(defaultValue)
            },
            /**
             * 初始值规则:
             * - 用户设置初始值 value
             *     - 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start
             *     - 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start
             *     - 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end
             *     - 无起始终止时间,则初始值为 value
             * - 无初始值 value,则初始值为当前本地时间 Date.now()
             * @param {Object} value
             * @param {Object} dateBase
             */
            compareValueWithStartAndEnd(value, start, end) {
                let winner = null
                value = this.superTimeStamp(value)
                start = this.superTimeStamp(start)
                end = this.superTimeStamp(end)
                if (start && end) {
                    if (value < start) {
                        winner = new Date(start)
                    } else if (value > end) {
                        winner = new Date(end)
                    } else {
                        winner = new Date(value)
                    }
                } else if (start && !end) {
                    winner = start <= value ? new Date(value) : new Date(start)
                } else if (!start && end) {
                    winner = value <= end ? new Date(value) : new Date(end)
                } else {
                    winner = new Date(value)
                }
                return winner
            },
            /**
             * 转换为可比较的时间戳,接受日期、时分秒、时间戳
             * @param {Object} value
             */
            superTimeStamp(value) {
                let dateBase = ''
                if (this.type === 'time' && value && typeof value === 'string') {
                    const now = new Date()
                    const year = now.getFullYear()
                    const month = now.getMonth() + 1
                    const day = now.getDate()
                    dateBase = year + '/' + month + '/' + day + ' '
                }
                if (Number(value)) {
                    value = parseInt(value)
                    dateBase = 0
                }
                return this.createTimeStamp(dateBase + value)
            },
            /**
             * 解析默认值 value,字符串、时间戳
             * @param {Object} defaultTime
             */
            parseValue(value) {
                if (!value) {
                    return
                }
                if (this.type === 'time' && typeof value === "string") {
                    this.parseTimeType(value)
                } else {
                    let defaultDate = null
                    defaultDate = new Date(value)
                    if (this.type !== 'time') {
                        this.year = defaultDate.getFullYear()
                        this.month = defaultDate.getMonth() + 1
                        this.day = defaultDate.getDate()
                    }
                    if (this.type !== 'date') {
                        this.hour = defaultDate.getHours()
                        this.minute = defaultDate.getMinutes()
                        this.second = defaultDate.getSeconds()
                    }
                }
                if (this.hideSecond) {
                    this.second = 0
                }
            },
            /**
             * 解析可选择时间范围 start、end,年月日字符串、时间戳
             * @param {Object} defaultTime
             */
            parseDatetimeRange(point, pointType) {
                // 时间为空,则重置为初始值
                if (!point) {
                    if (pointType === 'start') {
                        this.startYear = 1920
                        this.startMonth = 1
                        this.startDay = 1
                        this.startHour = 0
                        this.startMinute = 0
                        this.startSecond = 0
                    }
                    if (pointType === 'end') {
                        this.endYear = 2120
                        this.endMonth = 12
                        this.endDay = 31
                        this.endHour = 23
                        this.endMinute = 59
                        this.endSecond = 59
                    }
                    return
                }
                if (this.type === 'time') {
                    const pointArr = point.split(':')
                    this[pointType + 'Hour'] = Number(pointArr[0])
                    this[pointType + 'Minute'] = Number(pointArr[1])
                    this[pointType + 'Second'] = Number(pointArr[2])
                } else {
                    if (!point) {
                        pointType === 'start' ? this.startYear = this.year - 60 : this.endYear = this.year + 60
                        return
                    }
                    if (Number(point)) {
                        point = parseInt(point)
                    }
                    // datetime 的 end 没有时分秒, 则不限制
                    const hasTime = /[0-9]:[0-9]/
                    if (this.type === 'datetime' && pointType === 'end' && typeof point === 'string' && !hasTime.test(
                            point)) {
                        point = point + ' 23:59:59'
                    }
                    const pointDate = new Date(point)
                    this[pointType + 'Year'] = pointDate.getFullYear()
                    this[pointType + 'Month'] = pointDate.getMonth() + 1
                    this[pointType + 'Day'] = pointDate.getDate()
                    if (this.type === 'datetime') {
                        this[pointType + 'Hour'] = pointDate.getHours()
                        this[pointType + 'Minute'] = pointDate.getMinutes()
                        this[pointType + 'Second'] = pointDate.getSeconds()
                    }
                }
            },
            // 获取 年、月、日、时、分、秒 当前可选范围
            getCurrentRange(value) {
                const range = []
                for (let i = this['min' + this.capitalize(value)]; i <= this['max' + this.capitalize(value)]; i++) {
                    range.push(i)
                }
                return range
            },
            // 字符串首字母大写
            capitalize(str) {
                return str.charAt(0).toUpperCase() + str.slice(1)
            },
            // 检查当前值是否在范围内,不在则当前值重置为可选范围第一项
            checkValue(name, value, values) {
                if (values.indexOf(value) === -1) {
                    this[name] = values[0]
                }
            },
            // 每个月的实际天数
            daysInMonth(year, month) { // Use 1 for January, 2 for February, etc.
                return new Date(year, month, 0).getDate();
            },
            /**
             * 生成时间戳
             * @param {Object} time
             */
            createTimeStamp(time) {
                if (!time) return
                if (typeof time === "number") {
                    return time
                } else {
                    time = time.replace(/-/g, '/')
                    if (this.type === 'date') {
                        time = time + ' ' + '00:00:00'
                    }
                    return Date.parse(time)
                }
            },
            /**
             * 生成日期或时间的字符串
             */
            createDomSting() {
                const yymmdd = this.year +
                    '-' +
                    this.lessThanTen(this.month) +
                    '-' +
                    this.lessThanTen(this.day)
                let hhmmss = this.lessThanTen(this.hour) +
                    ':' +
                    this.lessThanTen(this.minute)
                if (!this.hideSecond) {
                    hhmmss = hhmmss + ':' + this.lessThanTen(this.second)
                }
                if (this.type === 'date') {
                    return yymmdd
                } else if (this.type === 'time') {
                    return hhmmss
                } else {
                    return yymmdd + ' ' + hhmmss
                }
            },
            /**
             * 初始化返回值,并抛出 change 事件
             */
            initTime(emit = true) {
                this.time = this.createDomSting()
                if (!emit) return
                if (this.returnType === 'timestamp' && this.type !== 'time') {
                    this.$emit('change', this.createTimeStamp(this.time))
                    this.$emit('input', this.createTimeStamp(this.time))
                    this.$emit('update:modelValue', this.createTimeStamp(this.time))
                } else {
                    this.$emit('change', this.time)
                    this.$emit('input', this.time)
                    this.$emit('update:modelValue', this.time)
                }
            },
            /**
             * 用户选择日期或时间更新 data
             * @param {Object} e
             */
            bindDateChange(e) {
                const val = e.detail.value
                this.year = this.years[val[0]]
                this.month = this.months[val[1]]
                this.day = this.days[val[2]]
            },
            bindTimeChange(e) {
                const val = e.detail.value
                this.hour = this.hours[val[0]]
                this.minute = this.minutes[val[1]]
                this.second = this.seconds[val[2]]
            },
            /**
             * 初始化弹出层
             */
            initTimePicker() {
                if (this.disabled) return
                const value = fixIosDateFormat(this.time)
                this.initPickerValue(value)
                this.visible = !this.visible
            },
            /**
             * 触发或关闭弹框
             */
            tiggerTimePicker(e) {
                this.visible = !this.visible
            },
            /**
             * 用户点击“清空”按钮,清空当前值
             */
            clearTime() {
                this.time = ''
                this.$emit('change', this.time)
                this.$emit('input', this.time)
                this.$emit('update:modelValue', this.time)
                this.tiggerTimePicker()
            },
            /**
             * 用户点击“确定”按钮
             */
            setTime() {
                this.initTime()
                this.tiggerTimePicker()
            }
        }
    }
</script>
<style lang="scss">
    $uni-primary: #007aff !default;
    .uni-datetime-picker {
        /* #ifndef APP-NVUE */
        /* width: 100%; */
        /* #endif */
    }
    .uni-datetime-picker-view {
        height: 130px;
        width: 270px;
        /* #ifndef APP-NVUE */
        cursor: pointer;
        /* #endif */
    }
    .uni-datetime-picker-item {
        height: 50px;
        line-height: 50px;
        text-align: center;
        font-size: 14px;
    }
    .uni-datetime-picker-btn {
        margin-top: 60px;
        /* #ifndef APP-NVUE */
        display: flex;
        cursor: pointer;
        /* #endif */
        flex-direction: row;
        justify-content: space-between;
    }
    .uni-datetime-picker-btn-text {
        font-size: 14px;
        color: $uni-primary;
    }
    .uni-datetime-picker-btn-group {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
    }
    .uni-datetime-picker-cancel {
        margin-right: 30px;
    }
    .uni-datetime-picker-mask {
        position: fixed;
        bottom: 0px;
        top: 0px;
        left: 0px;
        right: 0px;
        background-color: rgba(0, 0, 0, 0.4);
        transition-duration: 0.3s;
        z-index: 998;
    }
    .uni-datetime-picker-popup {
        border-radius: 8px;
        padding: 30px;
        width: 270px;
        /* #ifdef APP-NVUE */
        height: 500px;
        /* #endif */
        /* #ifdef APP-NVUE */
        width: 330px;
        /* #endif */
        background-color: #fff;
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        transition-duration: 0.3s;
        z-index: 999;
    }
    .fix-nvue-height {
        /* #ifdef APP-NVUE */
        height: 330px;
        /* #endif */
    }
    .uni-datetime-picker-time {
        color: grey;
    }
    .uni-datetime-picker-column {
        height: 50px;
    }
    .uni-datetime-picker-timebox {
        border: 1px solid #E5E5E5;
        border-radius: 5px;
        padding: 7px 10px;
        /* #ifndef APP-NVUE */
        box-sizing: border-box;
        cursor: pointer;
        /* #endif */
    }
    .uni-datetime-picker-timebox-pointer {
        /* #ifndef APP-NVUE */
        cursor: pointer;
        /* #endif */
    }
    .uni-datetime-picker-disabled {
        opacity: 0.4;
        /* #ifdef H5 */
        cursor: not-allowed !important;
        /* #endif */
    }
    .uni-datetime-picker-text {
        font-size: 14px;
        line-height: 50px
    }
    .uni-datetime-picker-sign {
        position: absolute;
        top: 53px;
        /* 减掉 10px 的元素高度,兼容nvue */
        color: #999;
        /* #ifdef APP-NVUE */
        font-size: 16px;
        /* #endif */
    }
    .sign-left {
        left: 86px;
    }
    .sign-right {
        right: 86px;
    }
    .sign-center {
        left: 135px;
    }
    .uni-datetime-picker__container-box {
        position: relative;
        display: flex;
        align-items: center;
        justify-content: center;
        margin-top: 40px;
    }
    .time-hide-second {
        width: 180px;
    }
</style>
uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
对比新文件
@@ -0,0 +1,1064 @@
<template>
    <view class="uni-date">
        <view class="uni-date-editor" @click="show">
            <slot>
                <view class="uni-date-editor--x"
                    :class="{'uni-date-editor--x__disabled': disabled,'uni-date-x--border': border}">
                    <view v-if="!isRange" class="uni-date-x uni-date-single">
                        <uni-icons class="icon-calendar" type="calendar" color="#c0c4cc" size="22"></uni-icons>
                        <view class="uni-date__x-input">{{ displayValue || singlePlaceholderText }}</view>
                    </view>
                    <view v-else class="uni-date-x uni-date-range">
                        <uni-icons class="icon-calendar" type="calendar" color="#c0c4cc" size="22"></uni-icons>
                        <view class="uni-date__x-input text-center">{{ displayRangeValue.startDate || startPlaceholderText }}</view>
                        <view class="range-separator">{{rangeSeparator}}</view>
                        <view class="uni-date__x-input text-center">{{ displayRangeValue.endDate || endPlaceholderText }}</view>
                    </view>
                    <view v-if="showClearIcon" class="uni-date__icon-clear" @click.stop="clear">
                        <uni-icons type="clear" color="#c0c4cc" size="22"></uni-icons>
                    </view>
                </view>
            </slot>
        </view>
        <view v-show="pickerVisible" class="uni-date-mask--pc" @click="close"></view>
        <view v-if="!isPhone" v-show="pickerVisible" ref="datePicker" class="uni-date-picker__container">
            <view v-if="!isRange" class="uni-date-single--x" :style="pickerPositionStyle">
                <view class="uni-popper__arrow"></view>
                <view v-if="hasTime" class="uni-date-changed popup-x-header">
                    <input class="uni-date__input text-center" type="text" v-model="inputDate" :placeholder="selectDateText" />
                    <time-picker type="time" v-model="pickerTime" :border="false" :disabled="!inputDate"
                        :start="timepickerStartTime" :end="timepickerEndTime" :hideSecond="hideSecond" style="width: 100%;">
                        <input class="uni-date__input text-center" type="text" v-model="pickerTime" :placeholder="selectTimeText"
                            :disabled="!inputDate" />
                    </time-picker>
                </view>
                <Calendar ref="pcSingle" :showMonth="false" :start-date="calendarRange.startDate"
                    :end-date="calendarRange.endDate" :date="calendarDate" @change="singleChange" :default-value="defaultValue"
                    style="padding: 0 8px;" />
                <view v-if="hasTime" class="popup-x-footer">
                    <text class="confirm-text" @click="confirmSingleChange">{{okText}}</text>
                </view>
            </view>
            <view v-else class="uni-date-range--x" :style="pickerPositionStyle">
                <view class="uni-popper__arrow"></view>
                <view v-if="hasTime" class="popup-x-header uni-date-changed">
                    <view class="popup-x-header--datetime">
                        <input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.startDate"
                            :placeholder="startDateText" />
                        <time-picker type="time" v-model="tempRange.startTime" :start="timepickerStartTime" :border="false"
                            :disabled="!tempRange.startDate" :hideSecond="hideSecond">
                            <input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.startTime"
                                :placeholder="startTimeText" :disabled="!tempRange.startDate" />
                        </time-picker>
                    </view>
                    <uni-icons type="arrowthinright" color="#999" style="line-height: 40px;"></uni-icons>
                    <view class="popup-x-header--datetime">
                        <input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endDate"
                            :placeholder="endDateText" />
                        <time-picker type="time" v-model="tempRange.endTime" :end="timepickerEndTime" :border="false"
                            :disabled="!tempRange.endDate" :hideSecond="hideSecond">
                            <input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endTime"
                                :placeholder="endTimeText" :disabled="!tempRange.endDate" />
                        </time-picker>
                    </view>
                </view>
                <view class="popup-x-body">
                    <Calendar ref="left" :showMonth="false" :start-date="calendarRange.startDate"
                        :end-date="calendarRange.endDate" :range="true" :pleStatus="endMultipleStatus" @change="leftChange"
                        @firstEnterCale="updateRightCale" style="padding: 0 8px;"/>
                    <Calendar ref="right" :showMonth="false" :start-date="calendarRange.startDate"
                        :end-date="calendarRange.endDate" :range="true" @change="rightChange" :pleStatus="startMultipleStatus"
                        @firstEnterCale="updateLeftCale" style="padding: 0 8px;border-left: 1px solid #F1F1F1;" />
                </view>
                <view v-if="hasTime" class="popup-x-footer">
                    <text @click="clear">{{clearText}}</text>
                    <text class="confirm-text" @click="confirmRangeChange">{{okText}}</text>
                </view>
            </view>
        </view>
        <Calendar v-if="isPhone" ref="mobile" :clearDate="false" :date="calendarDate" :defTime="mobileCalendarTime"
            :start-date="calendarRange.startDate" :end-date="calendarRange.endDate" :selectableTimes="mobSelectableTime"
            :startPlaceholder="startPlaceholder" :endPlaceholder="endPlaceholder" :default-value="defaultValue"
            :pleStatus="endMultipleStatus" :showMonth="false" :range="isRange" :hasTime="hasTime" :insert="false"
            :hideSecond="hideSecond" @confirm="mobileChange" @maskClose="close" @change="calendarClick"/>
    </view>
</template>
<script>
    /**
     * DatetimePicker 时间选择器
     * @description 同时支持 PC 和移动端使用日历选择日期和日期范围
     * @tutorial https://ext.dcloud.net.cn/plugin?id=3962
     * @property {String} type 选择器类型
     * @property {String|Number|Array|Date} value 绑定值
     * @property {String} placeholder 单选择时的占位内容
     * @property {String} start 起始时间
     * @property {String} end 终止时间
     * @property {String} start-placeholder 范围选择时开始日期的占位内容
     * @property {String} end-placeholder 范围选择时结束日期的占位内容
     * @property {String} range-separator 选择范围时的分隔符
     * @property {Boolean} border = [true|false] 是否有边框
     * @property {Boolean} disabled = [true|false] 是否禁用
     * @property {Boolean} clearIcon = [true|false] 是否显示清除按钮(仅PC端适用)
     * @property {[String} defaultValue 选择器打开时默认显示的时间
     * @event {Function} change 确定日期时触发的事件
     * @event {Function} maskClick 点击遮罩层触发的事件
     * @event {Function} show 打开弹出层
     * @event {Function} close 关闭弹出层
     * @event {Function} clear 清除上次选中的状态和值
     **/
    import Calendar from './calendar.vue'
    import TimePicker from './time-picker.vue'
    import {
        initVueI18n
    } from '@dcloudio/uni-i18n'
    import i18nMessages from './i18n/index.js'
    import {
        getDateTime,
        getDate,
        getTime,
        getDefaultSecond,
        dateCompare,
        checkDate,
        fixIosDateFormat
    } from './util'
    export default {
        name: 'UniDatetimePicker',
        options: {
            // #ifdef MP-TOUTIAO
            virtualHost: false,
            // #endif
            // #ifndef MP-TOUTIAO
            virtualHost: true
            // #endif
        },
        components: {
            Calendar,
            TimePicker
        },
        data() {
            return {
                isRange: false,
                hasTime: false,
                displayValue: '',
                inputDate: '',
                calendarDate: '',
                pickerTime: '',
                calendarRange: {
                    startDate: '',
                    startTime: '',
                    endDate: '',
                    endTime: ''
                },
                displayRangeValue: {
                    startDate: '',
                    endDate: '',
                },
                tempRange: {
                    startDate: '',
                    startTime: '',
                    endDate: '',
                    endTime: ''
                },
                // 左右日历同步数据
                startMultipleStatus: {
                    before: '',
                    after: '',
                    data: [],
                    fulldate: ''
                },
                endMultipleStatus: {
                    before: '',
                    after: '',
                    data: [],
                    fulldate: ''
                },
                pickerVisible: false,
                pickerPositionStyle: null,
                isEmitValue: false,
                isPhone: false,
                isFirstShow: true,
                i18nT: () => {}
            }
        },
        props: {
            type: {
                type: String,
                default: 'datetime'
            },
            value: {
                type: [String, Number, Array, Date],
                default: ''
            },
            modelValue: {
                type: [String, Number, Array, Date],
                default: ''
            },
            start: {
                type: [Number, String],
                default: ''
            },
            end: {
                type: [Number, String],
                default: ''
            },
            returnType: {
                type: String,
                default: 'string'
            },
            placeholder: {
                type: String,
                default: ''
            },
            startPlaceholder: {
                type: String,
                default: ''
            },
            endPlaceholder: {
                type: String,
                default: ''
            },
            rangeSeparator: {
                type: String,
                default: '-'
            },
            border: {
                type: [Boolean],
                default: true
            },
            disabled: {
                type: [Boolean],
                default: false
            },
            clearIcon: {
                type: [Boolean],
                default: true
            },
            hideSecond: {
                type: [Boolean],
                default: false
            },
            defaultValue: {
                type: [String, Object, Array],
                default: ''
            }
        },
        watch: {
            type: {
                immediate: true,
                handler(newVal) {
                    this.hasTime = newVal.indexOf('time') !== -1
                    this.isRange = newVal.indexOf('range') !== -1
                }
            },
            // #ifndef VUE3
            value: {
                immediate: true,
                handler(newVal) {
                    if (this.isEmitValue) {
                        this.isEmitValue = false
                        return
                    }
                    this.initPicker(newVal)
                }
            },
            // #endif
            // #ifdef VUE3
            modelValue: {
                immediate: true,
                handler(newVal) {
                    if (this.isEmitValue) {
                        this.isEmitValue = false
                        return
                    }
                    this.initPicker(newVal)
                }
            },
            // #endif
            start: {
                immediate: true,
                handler(newVal) {
                    if (!newVal) return
                    this.calendarRange.startDate = getDate(newVal)
                    if (this.hasTime) {
                        this.calendarRange.startTime = getTime(newVal)
                    }
                }
            },
            end: {
                immediate: true,
                handler(newVal) {
                    if (!newVal) return
                    this.calendarRange.endDate = getDate(newVal)
                    if (this.hasTime) {
                        this.calendarRange.endTime = getTime(newVal, this.hideSecond)
                    }
                }
            },
        },
        computed: {
            timepickerStartTime() {
                const activeDate = this.isRange ? this.tempRange.startDate : this.inputDate
                return activeDate === this.calendarRange.startDate ? this.calendarRange.startTime : ''
            },
            timepickerEndTime() {
                const activeDate = this.isRange ? this.tempRange.endDate : this.inputDate
                return activeDate === this.calendarRange.endDate ? this.calendarRange.endTime : ''
            },
            mobileCalendarTime() {
                const timeRange = {
                    start: this.tempRange.startTime,
                    end: this.tempRange.endTime
                }
                return this.isRange ? timeRange : this.pickerTime
            },
            mobSelectableTime() {
                return {
                    start: this.calendarRange.startTime,
                    end: this.calendarRange.endTime
                }
            },
            datePopupWidth() {
                // todo
                return this.isRange ? 653 : 301
            },
            /**
             * for i18n
             */
            singlePlaceholderText() {
                return this.placeholder || (this.type === 'date' ? this.selectDateText : this.selectDateTimeText)
            },
            startPlaceholderText() {
                return this.startPlaceholder || this.startDateText
            },
            endPlaceholderText() {
                return this.endPlaceholder || this.endDateText
            },
            selectDateText() {
                return this.i18nT("uni-datetime-picker.selectDate")
            },
            selectDateTimeText() {
                return this.i18nT("uni-datetime-picker.selectDateTime")
            },
            selectTimeText() {
                return this.i18nT("uni-datetime-picker.selectTime")
            },
            startDateText() {
                return this.startPlaceholder || this.i18nT("uni-datetime-picker.startDate")
            },
            startTimeText() {
                return this.i18nT("uni-datetime-picker.startTime")
            },
            endDateText() {
                return this.endPlaceholder || this.i18nT("uni-datetime-picker.endDate")
            },
            endTimeText() {
                return this.i18nT("uni-datetime-picker.endTime")
            },
            okText() {
                return this.i18nT("uni-datetime-picker.ok")
            },
            clearText() {
                return this.i18nT("uni-datetime-picker.clear")
            },
            showClearIcon() {
                return this.clearIcon && !this.disabled && (this.displayValue || (this.displayRangeValue.startDate && this
                    .displayRangeValue.endDate))
            }
        },
        created() {
            this.initI18nT()
            this.platform()
        },
        methods: {
            initI18nT() {
                const vueI18n = initVueI18n(i18nMessages)
                this.i18nT = vueI18n.t
            },
            initPicker(newVal) {
                if ((!newVal && !this.defaultValue) || Array.isArray(newVal) && !newVal.length) {
                    this.$nextTick(() => {
                        this.clear(false)
                    })
                    return
                }
                if (!Array.isArray(newVal) && !this.isRange) {
                    if (newVal) {
                        this.displayValue = this.inputDate = this.calendarDate = getDate(newVal)
                        if (this.hasTime) {
                            this.pickerTime = getTime(newVal, this.hideSecond)
                            this.displayValue = `${this.displayValue} ${this.pickerTime}`
                        }
                    } else if (this.defaultValue) {
                        this.inputDate = this.calendarDate = getDate(this.defaultValue)
                        if (this.hasTime) {
                            this.pickerTime = getTime(this.defaultValue, this.hideSecond)
                        }
                    }
                } else {
                    const [before, after] = newVal
                    if (!before && !after) return
                    const beforeDate = getDate(before)
                    const beforeTime = getTime(before, this.hideSecond)
                    const afterDate = getDate(after)
                    const afterTime = getTime(after, this.hideSecond)
                    const startDate = beforeDate
                    const endDate = afterDate
                    this.displayRangeValue.startDate = this.tempRange.startDate = startDate
                    this.displayRangeValue.endDate = this.tempRange.endDate = endDate
                    if (this.hasTime) {
                        this.displayRangeValue.startDate = `${beforeDate} ${beforeTime}`
                        this.displayRangeValue.endDate = `${afterDate} ${afterTime}`
                        this.tempRange.startTime = beforeTime
                        this.tempRange.endTime = afterTime
                    }
                    const defaultRange = {
                        before: beforeDate,
                        after: afterDate
                    }
                    this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, defaultRange, {
                        which: 'right'
                    })
                    this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, defaultRange, {
                        which: 'left'
                    })
                }
            },
            updateLeftCale(e) {
                const left = this.$refs.left
                // 设置范围选
                left.cale.setHoverMultiple(e.after)
                left.setDate(this.$refs.left.nowDate.fullDate)
            },
            updateRightCale(e) {
                const right = this.$refs.right
                // 设置范围选
                right.cale.setHoverMultiple(e.after)
                right.setDate(this.$refs.right.nowDate.fullDate)
            },
            platform() {
                if (typeof navigator !== "undefined") {
                    this.isPhone = navigator.userAgent.toLowerCase().indexOf('mobile') !== -1
                    return
                }
                // #ifdef MP-WEIXIN
                const {
                    windowWidth
                } = uni.getWindowInfo()
                // #endif
                // #ifndef MP-WEIXIN
                const {
                    windowWidth
                } = uni.getSystemInfoSync()
                // #endif
                this.isPhone = windowWidth <= 500
                this.windowWidth = windowWidth
            },
            show() {
                this.$emit("show")
                if (this.disabled) {
                    return
                }
                this.platform()
                if (this.isPhone) {
                    setTimeout(() => {
                        this.$refs.mobile.open()
                    }, 0);
                    return
                }
                this.pickerPositionStyle = {
                    top: '10px'
                }
                const dateEditor = uni.createSelectorQuery().in(this).select(".uni-date-editor")
                dateEditor.boundingClientRect(rect => {
                    if (this.windowWidth - rect.left < this.datePopupWidth) {
                        this.pickerPositionStyle.right = 0
                    }
                }).exec()
                setTimeout(() => {
                    this.pickerVisible = !this.pickerVisible
                    if (!this.isPhone && this.isRange && this.isFirstShow) {
                        this.isFirstShow = false
                        const {
                            startDate,
                            endDate
                        } = this.calendarRange
                        if (startDate && endDate) {
                            if (this.diffDate(startDate, endDate) < 30) {
                                this.$refs.right.changeMonth('pre')
                            }
                        } else {
                            // this.$refs.right.changeMonth('next')
                            if (this.isPhone) {
                                this.$refs.right.cale.lastHover = false;
                            }
                        }
                    }
                }, 50)
            },
            close() {
                setTimeout(() => {
                    this.pickerVisible = false
                    this.$emit('maskClick', this.value)
                    this.$refs.mobile && this.$refs.mobile.close()
                }, 20)
            },
            setEmit(value) {
                if (this.returnType === "timestamp" || this.returnType === "date") {
                    if (!Array.isArray(value)) {
                        if (!this.hasTime) {
                            value = value + ' ' + '00:00:00'
                        }
                        value = this.createTimestamp(value)
                        if (this.returnType === "date") {
                            value = new Date(value)
                        }
                    } else {
                        if (!this.hasTime) {
                            value[0] = value[0] + ' ' + '00:00:00'
                            value[1] = value[1] + ' ' + '00:00:00'
                        }
                        value[0] = this.createTimestamp(value[0])
                        value[1] = this.createTimestamp(value[1])
                        if (this.returnType === "date") {
                            value[0] = new Date(value[0])
                            value[1] = new Date(value[1])
                        }
                    }
                }
                this.$emit('update:modelValue', value)
                this.$emit('input', value)
                this.$emit('change', value)
                this.isEmitValue = true
            },
            createTimestamp(date) {
                date = fixIosDateFormat(date)
                return Date.parse(new Date(date))
            },
            singleChange(e) {
                this.calendarDate = this.inputDate = e.fulldate
                if (this.hasTime) return
                this.confirmSingleChange()
            },
            confirmSingleChange() {
                if (!checkDate(this.inputDate)) {
                    const now = new Date()
                    this.calendarDate = this.inputDate = getDate(now)
                    this.pickerTime = getTime(now, this.hideSecond)
                }
                let startLaterInputDate = false
                let startDate, startTime
                if (this.start) {
                    let startString = this.start
                    if (typeof this.start === 'number') {
                        startString = getDateTime(this.start, this.hideSecond)
                    }
                    [startDate, startTime] = startString.split(' ')
                    if (this.start && !dateCompare(startDate, this.inputDate)) {
                        startLaterInputDate = true
                        this.inputDate = startDate
                    }
                }
                let endEarlierInputDate = false
                let endDate, endTime
                if (this.end) {
                    let endString = this.end
                    if (typeof this.end === 'number') {
                        endString = getDateTime(this.end, this.hideSecond)
                    }
                    [endDate, endTime] = endString.split(' ')
                    if (this.end && !dateCompare(this.inputDate, endDate)) {
                        endEarlierInputDate = true
                        this.inputDate = endDate
                    }
                }
                if (this.hasTime) {
                    if (startLaterInputDate) {
                        this.pickerTime = startTime || getDefaultSecond(this.hideSecond)
                    }
                    if (endEarlierInputDate) {
                        this.pickerTime = endTime || getDefaultSecond(this.hideSecond)
                    }
                    if (!this.pickerTime) {
                        this.pickerTime = getTime(Date.now(), this.hideSecond)
                    }
                    this.displayValue = `${this.inputDate} ${this.pickerTime}`
                } else {
                    this.displayValue = this.inputDate
                }
                this.setEmit(this.displayValue)
                this.pickerVisible = false
            },
            leftChange(e) {
                const {
                    before,
                    after
                } = e.range
                this.rangeChange(before, after)
                const obj = {
                    before: e.range.before,
                    after: e.range.after,
                    data: e.range.data,
                    fulldate: e.fulldate
                }
                this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, obj)
                this.$emit('calendarClick', e)
            },
            rightChange(e) {
                const {
                    before,
                    after
                } = e.range
                this.rangeChange(before, after)
                const obj = {
                    before: e.range.before,
                    after: e.range.after,
                    data: e.range.data,
                    fulldate: e.fulldate
                }
                this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, obj)
                this.$emit('calendarClick', e)
            },
            mobileChange(e) {
                if (this.isRange) {
                    const {
                        before,
                        after
                    } = e.range
                    if (!before) {
                        return;
                    }
                    this.handleStartAndEnd(before, after, true)
                    if (this.hasTime) {
                        const {
                            startTime,
                            endTime
                        } = e.timeRange
                        this.tempRange.startTime = startTime
                        this.tempRange.endTime = endTime
                    }
                    this.confirmRangeChange()
                } else {
                    if (this.hasTime) {
                        this.displayValue = e.fulldate + ' ' + e.time
                    } else {
                        this.displayValue = e.fulldate
                    }
                    this.setEmit(this.displayValue)
                }
                this.$refs.mobile.close()
            },
            rangeChange(before, after) {
                if (!(before && after)) return
                this.handleStartAndEnd(before, after, true)
                if (this.hasTime) return
                this.confirmRangeChange()
            },
            confirmRangeChange() {
                if (!this.tempRange.startDate || !this.tempRange.endDate) {
                    this.pickerVisible = false
                    return
                }
                if (!checkDate(this.tempRange.startDate)) {
                    this.tempRange.startDate = getDate(Date.now())
                }
                if (!checkDate(this.tempRange.endDate)) {
                    this.tempRange.endDate = getDate(Date.now())
                }
                let start, end
                let startDateLaterRangeStartDate = false
                let startDateLaterRangeEndDate = false
                let startDate, startTime
                if (this.start) {
                    let startString = this.start
                    if (typeof this.start === 'number') {
                        startString = getDateTime(this.start, this.hideSecond)
                    }
                    [startDate, startTime] = startString.split(' ')
                    if (this.start && !dateCompare(this.start, `${this.tempRange.startDate} ${this.tempRange.startTime}`)) {
                        startDateLaterRangeStartDate = true
                        this.tempRange.startDate = startDate
                    }
                    if (this.start && !dateCompare(this.start, `${this.tempRange.endDate} ${this.tempRange.endTime}`)) {
                        startDateLaterRangeEndDate = true
                        this.tempRange.endDate = startDate
                    }
                }
                let endDateEarlierRangeStartDate = false
                let endDateEarlierRangeEndDate = false
                let endDate, endTime
                if (this.end) {
                    let endString = this.end
                    if (typeof this.end === 'number') {
                        endString = getDateTime(this.end, this.hideSecond)
                    }
                    [endDate, endTime] = endString.split(' ')
                    if (this.end && !dateCompare(`${this.tempRange.startDate} ${this.tempRange.startTime}`, this.end)) {
                        endDateEarlierRangeStartDate = true
                        this.tempRange.startDate = endDate
                    }
                    if (this.end && !dateCompare(`${this.tempRange.endDate} ${this.tempRange.endTime}`, this.end)) {
                        endDateEarlierRangeEndDate = true
                        this.tempRange.endDate = endDate
                    }
                }
                if (!this.hasTime) {
                    start = this.displayRangeValue.startDate = this.tempRange.startDate
                    end = this.displayRangeValue.endDate = this.tempRange.endDate
                } else {
                    if (startDateLaterRangeStartDate) {
                        this.tempRange.startTime = startTime || getDefaultSecond(this.hideSecond)
                    } else if (endDateEarlierRangeStartDate) {
                        this.tempRange.startTime = endTime || getDefaultSecond(this.hideSecond)
                    }
                    if (!this.tempRange.startTime) {
                        this.tempRange.startTime = getTime(Date.now(), this.hideSecond)
                    }
                    if (startDateLaterRangeEndDate) {
                        this.tempRange.endTime = startTime || getDefaultSecond(this.hideSecond)
                    } else if (endDateEarlierRangeEndDate) {
                        this.tempRange.endTime = endTime || getDefaultSecond(this.hideSecond)
                    }
                    if (!this.tempRange.endTime) {
                        this.tempRange.endTime = getTime(Date.now(), this.hideSecond)
                    }
                    start = this.displayRangeValue.startDate = `${this.tempRange.startDate} ${this.tempRange.startTime}`
                    end = this.displayRangeValue.endDate = `${this.tempRange.endDate} ${this.tempRange.endTime}`
                }
                if (!dateCompare(start, end)) {
                    [start, end] = [end, start]
                }
                this.displayRangeValue.startDate = start
                this.displayRangeValue.endDate = end
                const displayRange = [start, end]
                this.setEmit(displayRange)
                this.pickerVisible = false
            },
            handleStartAndEnd(before, after, temp = false) {
                if (!before) return
                if (!after) after = before;
                const type = temp ? 'tempRange' : 'range'
                const isStartEarlierEnd = dateCompare(before, after)
                this[type].startDate = isStartEarlierEnd ? before : after
                this[type].endDate = isStartEarlierEnd ? after : before
            },
            /**
             * 比较时间大小
             */
            dateCompare(startDate, endDate) {
                // 计算截止时间
                startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
                // 计算详细项的截止时间
                endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
                return startDate <= endDate
            },
            /**
             * 比较时间差
             */
            diffDate(startDate, endDate) {
                // 计算截止时间
                startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
                // 计算详细项的截止时间
                endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
                const diff = (endDate - startDate) / (24 * 60 * 60 * 1000)
                return Math.abs(diff)
            },
            clear(needEmit = true) {
                if (!this.isRange) {
                    this.displayValue = ''
                    this.inputDate = ''
                    this.pickerTime = ''
                    if (this.isPhone) {
                        this.$refs.mobile && this.$refs.mobile.clearCalender()
                    } else {
                        this.$refs.pcSingle && this.$refs.pcSingle.clearCalender()
                    }
                    if (needEmit) {
                        this.$emit('change', '')
                        this.$emit('input', '')
                        this.$emit('update:modelValue', '')
                    }
                } else {
                    this.displayRangeValue.startDate = ''
                    this.displayRangeValue.endDate = ''
                    this.tempRange.startDate = ''
                    this.tempRange.startTime = ''
                    this.tempRange.endDate = ''
                    this.tempRange.endTime = ''
                    if (this.isPhone) {
                        this.$refs.mobile && this.$refs.mobile.clearCalender()
                    } else {
                        this.$refs.left && this.$refs.left.clearCalender()
                        this.$refs.right && this.$refs.right.clearCalender()
                        this.$refs.right && this.$refs.right.changeMonth('next')
                    }
                    if (needEmit) {
                        this.$emit('change', [])
                        this.$emit('input', [])
                        this.$emit('update:modelValue', [])
                    }
                }
            },
            calendarClick(e) {
                this.$emit('calendarClick', e)
            }
        }
    }
</script>
<style lang="scss">
    $uni-primary: #007aff !default;
    .uni-date {
        width: 100%;
        flex: 1;
    }
    .uni-date-x {
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: center;
        border-radius: 4px;
        background-color: #fff;
        color: #666;
        font-size: 14px;
        flex: 1;
        .icon-calendar {
            padding-left: 3px;
        }
        .range-separator {
            height: 35px;
            /* #ifndef MP */
            padding: 0 2px;
            /* #endif */
            line-height: 35px;
        }
    }
    .uni-date-x--border {
        box-sizing: border-box;
        border-radius: 4px;
        border: 1px solid #e5e5e5;
    }
    .uni-date-editor--x {
        display: flex;
        align-items: center;
        position: relative;
    }
    .uni-date-editor--x .uni-date__icon-clear {
        padding-right: 3px;
        display: flex;
        align-items: center;
        /* #ifdef H5 */
        cursor: pointer;
        /* #endif */
    }
    .uni-date__x-input {
        width: auto;
        height: 35px;
        /* #ifndef MP */
        padding-left: 5px;
        /* #endif */
        position: relative;
        flex: 1;
        line-height: 35px;
        font-size: 14px;
        overflow: hidden;
    }
    .text-center {
        text-align: center;
    }
    .uni-date__input {
        height: 40px;
        width: 100%;
        line-height: 40px;
        font-size: 14px;
    }
    .uni-date-range__input {
        text-align: center;
        max-width: 142px;
    }
    .uni-date-picker__container {
        position: relative;
    }
    .uni-date-mask--pc {
        position: fixed;
        bottom: 0px;
        top: 0px;
        left: 0px;
        right: 0px;
        background-color: rgba(0, 0, 0, 0);
        transition-duration: 0.3s;
        z-index: 996;
    }
    .uni-date-single--x {
        background-color: #fff;
        position: absolute;
        top: 0;
        z-index: 999;
        border: 1px solid #EBEEF5;
        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
        border-radius: 4px;
    }
    .uni-date-range--x {
        background-color: #fff;
        position: absolute;
        top: 0;
        z-index: 999;
        border: 1px solid #EBEEF5;
        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
        border-radius: 4px;
    }
    .uni-date-editor--x__disabled {
        opacity: 0.4;
        cursor: default;
    }
    .uni-date-editor--logo {
        width: 16px;
        height: 16px;
        vertical-align: middle;
    }
    /* 添加时间 */
    .popup-x-header {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
    }
    .popup-x-header--datetime {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
        flex: 1;
    }
    .popup-x-body {
        display: flex;
    }
    .popup-x-footer {
        padding: 0 15px;
        border-top-color: #F1F1F1;
        border-top-style: solid;
        border-top-width: 1px;
        line-height: 40px;
        text-align: right;
        color: #666;
    }
    .popup-x-footer text:hover {
        color: $uni-primary;
        cursor: pointer;
        opacity: 0.8;
    }
    .popup-x-footer .confirm-text {
        margin-left: 20px;
        color: $uni-primary;
    }
    .uni-date-changed {
        text-align: center;
        color: #333;
        border-bottom-color: #F1F1F1;
        border-bottom-style: solid;
        border-bottom-width: 1px;
    }
    .uni-date-changed--time text {
        height: 50px;
        line-height: 50px;
    }
    .uni-date-changed .uni-date-changed--time {
        flex: 1;
    }
    .uni-date-changed--time-date {
        color: #333;
        opacity: 0.6;
    }
    .mr-50 {
        margin-right: 50px;
    }
    /* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */
    .uni-popper__arrow,
    .uni-popper__arrow::after {
        position: absolute;
        display: block;
        width: 0;
        height: 0;
        border: 6px solid transparent;
        border-top-width: 0;
    }
    .uni-popper__arrow {
        filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
        top: -6px;
        left: 10%;
        margin-right: 3px;
        border-bottom-color: #EBEEF5;
    }
    .uni-popper__arrow::after {
        content: " ";
        top: 1px;
        margin-left: -6px;
        border-bottom-color: #fff;
    }
</style>
uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js
对比新文件
@@ -0,0 +1,421 @@
class Calendar {
    constructor({
        selected,
        startDate,
        endDate,
        range,
    } = {}) {
        // 当前日期
        this.date = this.getDateObj(new Date()) // 当前初入日期
        // 打点信息
        this.selected = selected || [];
        // 起始时间
        this.startDate = startDate
        // 终止时间
        this.endDate = endDate
        // 是否范围选择
        this.range = range
        // 多选状态
        this.cleanMultipleStatus()
        // 每周日期
        this.weeks = {}
        this.lastHover = false
    }
    /**
     * 设置日期
     * @param {Object} date
     */
    setDate(date) {
        const selectDate = this.getDateObj(date)
        this.getWeeks(selectDate.fullDate)
    }
    /**
     * 清理多选状态
     */
    cleanMultipleStatus() {
        this.multipleStatus = {
            before: '',
            after: '',
            data: []
        }
    }
    setStartDate(startDate) {
        this.startDate = startDate
    }
    setEndDate(endDate) {
        this.endDate = endDate
    }
    getPreMonthObj(date) {
        date = fixIosDateFormat(date)
        date = new Date(date)
        const oldMonth = date.getMonth()
        date.setMonth(oldMonth - 1)
        const newMonth = date.getMonth()
        if (oldMonth !== 0 && newMonth - oldMonth === 0) {
            date.setMonth(newMonth - 1)
        }
        return this.getDateObj(date)
    }
    getNextMonthObj(date) {
        date = fixIosDateFormat(date)
        date = new Date(date)
        const oldMonth = date.getMonth()
        date.setMonth(oldMonth + 1)
        const newMonth = date.getMonth()
        if (newMonth - oldMonth > 1) {
            date.setMonth(newMonth - 1)
        }
        return this.getDateObj(date)
    }
    /**
     * 获取指定格式Date对象
     */
    getDateObj(date) {
        date = fixIosDateFormat(date)
        date = new Date(date)
        return {
            fullDate: getDate(date),
            year: date.getFullYear(),
            month: addZero(date.getMonth() + 1),
            date: addZero(date.getDate()),
            day: date.getDay()
        }
    }
    /**
     * 获取上一个月日期集合
     */
    getPreMonthDays(amount, dateObj) {
        const result = []
        for (let i = amount - 1; i >= 0; i--) {
            const month = dateObj.month - 1
            result.push({
                date: new Date(dateObj.year, month, -i).getDate(),
                month,
                disable: true
            })
        }
        return result
    }
    /**
     * 获取本月日期集合
     */
    getCurrentMonthDays(amount, dateObj) {
        const result = []
        const fullDate = this.date.fullDate
        for (let i = 1; i <= amount; i++) {
            const currentDate = `${dateObj.year}-${dateObj.month}-${addZero(i)}`
            const isToday = fullDate === currentDate
            // 获取打点信息
            const info = this.selected && this.selected.find((item) => {
                if (this.dateEqual(currentDate, item.date)) {
                    return item
                }
            })
            // 日期禁用
            let disableBefore = true
            let disableAfter = true
            if (this.startDate) {
                disableBefore = dateCompare(this.startDate, currentDate)
            }
            if (this.endDate) {
                disableAfter = dateCompare(currentDate, this.endDate)
            }
            let multiples = this.multipleStatus.data
            let multiplesStatus = -1
            if (this.range && multiples) {
                multiplesStatus = multiples.findIndex((item) => {
                    return this.dateEqual(item, currentDate)
                })
            }
            const checked = multiplesStatus !== -1
            result.push({
                fullDate: currentDate,
                year: dateObj.year,
                date: i,
                multiple: this.range ? checked : false,
                beforeMultiple: this.isLogicBefore(currentDate, this.multipleStatus.before, this.multipleStatus.after),
                afterMultiple: this.isLogicAfter(currentDate, this.multipleStatus.before, this.multipleStatus.after),
                month: dateObj.month,
                disable: (this.startDate && !dateCompare(this.startDate, currentDate)) || (this.endDate && !dateCompare(
                    currentDate, this.endDate)),
                isToday,
                userChecked: false,
                extraInfo: info
            })
        }
        return result
    }
    /**
     * 获取下一个月日期集合
     */
    _getNextMonthDays(amount, dateObj) {
        const result = []
        const month = dateObj.month + 1
        for (let i = 1; i <= amount; i++) {
            result.push({
                date: i,
                month,
                disable: true
            })
        }
        return result
    }
    /**
     * 获取当前日期详情
     * @param {Object} date
     */
    getInfo(date) {
        if (!date) {
            date = new Date()
        }
        const res = this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
        return res ? res : this.getDateObj(date)
    }
    /**
     * 比较时间是否相等
     */
    dateEqual(before, after) {
        before = new Date(fixIosDateFormat(before))
        after = new Date(fixIosDateFormat(after))
        return before.valueOf() === after.valueOf()
    }
    /**
     *  比较真实起始日期
     */
    isLogicBefore(currentDate, before, after) {
        let logicBefore = before
        if (before && after) {
            logicBefore = dateCompare(before, after) ? before : after
        }
        return this.dateEqual(logicBefore, currentDate)
    }
    isLogicAfter(currentDate, before, after) {
        let logicAfter = after
        if (before && after) {
            logicAfter = dateCompare(before, after) ? after : before
        }
        return this.dateEqual(logicAfter, currentDate)
    }
    /**
     * 获取日期范围内所有日期
     * @param {Object} begin
     * @param {Object} end
     */
    geDateAll(begin, end) {
        var arr = []
        var ab = begin.split('-')
        var ae = end.split('-')
        var db = new Date()
        db.setFullYear(ab[0], ab[1] - 1, ab[2])
        var de = new Date()
        de.setFullYear(ae[0], ae[1] - 1, ae[2])
        var unixDb = db.getTime() - 24 * 60 * 60 * 1000
        var unixDe = de.getTime() - 24 * 60 * 60 * 1000
        for (var k = unixDb; k <= unixDe;) {
            k = k + 24 * 60 * 60 * 1000
            arr.push(this.getDateObj(new Date(parseInt(k))).fullDate)
        }
        return arr
    }
    /**
     *  获取多选状态
     */
    setMultiple(fullDate) {
        if (!this.range) return
        let {
            before,
            after
        } = this.multipleStatus
        if (before && after) {
            if (!this.lastHover) {
                this.lastHover = true
                return
            }
            this.multipleStatus.before = fullDate
            this.multipleStatus.after = ''
            this.multipleStatus.data = []
            this.multipleStatus.fulldate = ''
            this.lastHover = false
        } else {
            if (!before) {
                this.multipleStatus.before = fullDate
                this.multipleStatus.after = undefined;
                this.lastHover = false
            } else {
                this.multipleStatus.after = fullDate
                if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
                    this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
                        .after);
                } else {
                    this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
                        .before);
                }
                this.lastHover = true
            }
        }
        this.getWeeks(fullDate)
    }
    /**
     *  鼠标 hover 更新多选状态
     */
    setHoverMultiple(fullDate) {
        //抖音小程序点击会触发hover事件,需要避免一下
        // #ifndef MP-TOUTIAO
        if (!this.range || this.lastHover) return
        const {
            before
        } = this.multipleStatus
        if (!before) {
            this.multipleStatus.before = fullDate
        } else {
            this.multipleStatus.after = fullDate
            if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
                this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
            } else {
                this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
            }
        }
        this.getWeeks(fullDate)
        // #endif
    }
    /**
     * 更新默认值多选状态
     */
    setDefaultMultiple(before, after) {
        this.multipleStatus.before = before
        this.multipleStatus.after = after
        if (before && after) {
            if (dateCompare(before, after)) {
                this.multipleStatus.data = this.geDateAll(before, after);
                this.getWeeks(after)
            } else {
                this.multipleStatus.data = this.geDateAll(after, before);
                this.getWeeks(before)
            }
        }
    }
    /**
     * 获取每周数据
     * @param {Object} dateData
     */
    getWeeks(dateData) {
        const {
            year,
            month,
        } = this.getDateObj(dateData)
        const preMonthDayAmount = new Date(year, month - 1, 1).getDay()
        const preMonthDays = this.getPreMonthDays(preMonthDayAmount, this.getDateObj(dateData))
        const currentMonthDayAmount = new Date(year, month, 0).getDate()
        const currentMonthDays = this.getCurrentMonthDays(currentMonthDayAmount, this.getDateObj(dateData))
        const nextMonthDayAmount = 42 - preMonthDayAmount - currentMonthDayAmount
        const nextMonthDays = this._getNextMonthDays(nextMonthDayAmount, this.getDateObj(dateData))
        const calendarDays = [...preMonthDays, ...currentMonthDays, ...nextMonthDays]
        const weeks = new Array(6)
        for (let i = 0; i < calendarDays.length; i++) {
            const index = Math.floor(i / 7)
            if (!weeks[index]) {
                weeks[index] = new Array(7)
            }
            weeks[index][i % 7] = calendarDays[i]
        }
        this.calendar = calendarDays
        this.weeks = weeks
    }
}
function getDateTime(date, hideSecond) {
    return `${getDate(date)} ${getTime(date, hideSecond)}`
}
function getDate(date) {
    date = fixIosDateFormat(date)
    date = new Date(date)
    const year = date.getFullYear()
    const month = date.getMonth() + 1
    const day = date.getDate()
    return `${year}-${addZero(month)}-${addZero(day)}`
}
function getTime(date, hideSecond) {
    date = fixIosDateFormat(date)
    date = new Date(date)
    const hour = date.getHours()
    const minute = date.getMinutes()
    const second = date.getSeconds()
    return hideSecond ? `${addZero(hour)}:${addZero(minute)}` : `${addZero(hour)}:${addZero(minute)}:${addZero(second)}`
}
function addZero(num) {
    if (num < 10) {
        num = `0${num}`
    }
    return num
}
function getDefaultSecond(hideSecond) {
    return hideSecond ? '00:00' : '00:00:00'
}
function dateCompare(startDate, endDate) {
    startDate = new Date(fixIosDateFormat(startDate))
    endDate = new Date(fixIosDateFormat(endDate))
    return startDate <= endDate
}
function checkDate(date) {
    const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g
    return date.match(dateReg)
}
//ios低版本15及以下,无法匹配 没有 ’秒‘ 时的情况,所以需要在末尾 秒 加上 问号
const dateTimeReg = /^\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])( [0-5]?[0-9]:[0-5]?[0-9](:[0-5]?[0-9])?)?$/;
function fixIosDateFormat(value) {
    if (typeof value === 'string' && dateTimeReg.test(value)) {
        value = value.replace(/-/g, '/')
    }
    return value
}
export {
    Calendar,
    getDateTime,
    getDate,
    getTime,
    addZero,
    getDefaultSecond,
    dateCompare,
    checkDate,
    fixIosDateFormat
}
在上述文件截断后对比
uni_modules/uni-datetime-picker/package.json uni_modules/uni-datetime-picker/readme.md uni_modules/uni-drawer/changelog.md uni_modules/uni-drawer/components/uni-drawer/keypress.js uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue uni_modules/uni-drawer/package.json uni_modules/uni-drawer/readme.md uni_modules/uni-easyinput/changelog.md uni_modules/uni-easyinput/components/uni-easyinput/common.js uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue uni_modules/uni-easyinput/package.json uni_modules/uni-easyinput/readme.md uni_modules/uni-fab/changelog.md uni_modules/uni-fab/components/uni-fab/uni-fab.vue uni_modules/uni-fab/package.json uni_modules/uni-fab/readme.md uni_modules/uni-fav/changelog.md uni_modules/uni-fav/components/uni-fav/i18n/en.json uni_modules/uni-fav/components/uni-fav/i18n/index.js uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json uni_modules/uni-fav/components/uni-fav/uni-fav.vue uni_modules/uni-fav/package.json uni_modules/uni-fav/readme.md uni_modules/uni-file-picker/changelog.md uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue uni_modules/uni-file-picker/components/uni-file-picker/utils.js uni_modules/uni-file-picker/package.json uni_modules/uni-file-picker/readme.md uni_modules/uni-forms/changelog.md uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue uni_modules/uni-forms/components/uni-forms/uni-forms.vue uni_modules/uni-forms/components/uni-forms/utils.js uni_modules/uni-forms/components/uni-forms/validate.js uni_modules/uni-forms/package.json uni_modules/uni-forms/readme.md uni_modules/uni-goods-nav/changelog.md uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/en.json uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/index.js uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hans.json uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hant.json uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue uni_modules/uni-goods-nav/package.json uni_modules/uni-goods-nav/readme.md uni_modules/uni-grid/changelog.md uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue uni_modules/uni-grid/components/uni-grid/uni-grid.vue uni_modules/uni-grid/package.json uni_modules/uni-grid/readme.md uni_modules/uni-group/changelog.md uni_modules/uni-group/components/uni-group/uni-group.vue uni_modules/uni-group/package.json uni_modules/uni-group/readme.md uni_modules/uni-icons/changelog.md uni_modules/uni-icons/components/uni-icons/uni-icons.uvue uni_modules/uni-icons/components/uni-icons/uni-icons.vue uni_modules/uni-icons/components/uni-icons/uniicons.css uni_modules/uni-icons/components/uni-icons/uniicons.ttf uni_modules/uni-icons/components/uni-icons/uniicons_file.ts uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js uni_modules/uni-icons/package.json uni_modules/uni-icons/readme.md uni_modules/uni-indexed-list/changelog.md uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue uni_modules/uni-indexed-list/package.json uni_modules/uni-indexed-list/readme.md uni_modules/uni-link/changelog.md uni_modules/uni-link/components/uni-link/uni-link.vue uni_modules/uni-link/package.json uni_modules/uni-link/readme.md uni_modules/uni-list/changelog.md uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue uni_modules/uni-list/components/uni-list-item/uni-list-item.vue uni_modules/uni-list/components/uni-list/uni-list.vue uni_modules/uni-list/components/uni-list/uni-refresh.vue uni_modules/uni-list/components/uni-list/uni-refresh.wxs uni_modules/uni-list/package.json uni_modules/uni-list/readme.md uni_modules/uni-load-more/changelog.md uni_modules/uni-load-more/components/uni-load-more/i18n/en.json uni_modules/uni-load-more/components/uni-load-more/i18n/index.js uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue uni_modules/uni-load-more/package.json uni_modules/uni-load-more/readme.md uni_modules/uni-nav-bar/changelog.md uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue uni_modules/uni-nav-bar/package.json uni_modules/uni-nav-bar/readme.md uni_modules/uni-notice-bar/changelog.md uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue uni_modules/uni-notice-bar/package.json uni_modules/uni-notice-bar/readme.md uni_modules/uni-number-box/changelog.md uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue uni_modules/uni-number-box/package.json uni_modules/uni-number-box/readme.md uni_modules/uni-pagination/changelog.md uni_modules/uni-pagination/components/uni-pagination/i18n/en.json uni_modules/uni-pagination/components/uni-pagination/i18n/es.json uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json uni_modules/uni-pagination/components/uni-pagination/i18n/index.js uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue uni_modules/uni-pagination/package.json uni_modules/uni-pagination/readme.md uni_modules/uni-popup/changelog.md uni_modules/uni-popup/components/uni-popup-dialog/keypress.js uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue uni_modules/uni-popup/components/uni-popup/i18n/en.json uni_modules/uni-popup/components/uni-popup/i18n/index.js uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json uni_modules/uni-popup/components/uni-popup/keypress.js uni_modules/uni-popup/components/uni-popup/popup.js uni_modules/uni-popup/components/uni-popup/uni-popup.uvue uni_modules/uni-popup/components/uni-popup/uni-popup.vue uni_modules/uni-popup/package.json uni_modules/uni-popup/readme.md uni_modules/uni-rate/changelog.md uni_modules/uni-rate/components/uni-rate/uni-rate.vue uni_modules/uni-rate/package.json uni_modules/uni-rate/readme.md uni_modules/uni-row/changelog.md uni_modules/uni-row/components/uni-col/uni-col.vue uni_modules/uni-row/components/uni-row/uni-row.vue uni_modules/uni-row/package.json uni_modules/uni-row/readme.md uni_modules/uni-scss/changelog.md uni_modules/uni-scss/index.scss uni_modules/uni-scss/package.json uni_modules/uni-scss/readme.md uni_modules/uni-scss/styles/index.scss uni_modules/uni-scss/styles/setting/_border.scss uni_modules/uni-scss/styles/setting/_color.scss uni_modules/uni-scss/styles/setting/_radius.scss uni_modules/uni-scss/styles/setting/_space.scss uni_modules/uni-scss/styles/setting/_styles.scss uni_modules/uni-scss/styles/setting/_text.scss uni_modules/uni-scss/styles/setting/_variables.scss uni_modules/uni-scss/styles/tools/functions.scss uni_modules/uni-scss/theme.scss uni_modules/uni-scss/variables.scss uni_modules/uni-search-bar/changelog.md uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue uni_modules/uni-search-bar/package.json uni_modules/uni-search-bar/readme.md uni_modules/uni-section/changelog.md uni_modules/uni-section/components/uni-section/uni-section.vue uni_modules/uni-section/package.json uni_modules/uni-section/readme.md uni_modules/uni-segmented-control/changelog.md uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue uni_modules/uni-segmented-control/package.json uni_modules/uni-segmented-control/readme.md uni_modules/uni-steps/changelog.md uni_modules/uni-steps/components/uni-steps/uni-steps.vue uni_modules/uni-steps/package.json uni_modules/uni-steps/readme.md uni_modules/uni-swipe-action/changelog.md uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue uni_modules/uni-swipe-action/package.json uni_modules/uni-swipe-action/readme.md uni_modules/uni-swiper-dot/changelog.md uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue uni_modules/uni-swiper-dot/package.json uni_modules/uni-swiper-dot/readme.md uni_modules/uni-table/changelog.md uni_modules/uni-table/components/uni-table/uni-table.vue uni_modules/uni-table/components/uni-tbody/uni-tbody.vue uni_modules/uni-table/components/uni-td/uni-td.vue uni_modules/uni-table/components/uni-th/filter-dropdown.vue uni_modules/uni-table/components/uni-th/uni-th.vue uni_modules/uni-table/components/uni-thead/uni-thead.vue uni_modules/uni-table/components/uni-tr/table-checkbox.vue uni_modules/uni-table/components/uni-tr/uni-tr.vue uni_modules/uni-table/i18n/en.json uni_modules/uni-table/i18n/es.json uni_modules/uni-table/i18n/fr.json uni_modules/uni-table/i18n/index.js uni_modules/uni-table/i18n/zh-Hans.json uni_modules/uni-table/i18n/zh-Hant.json uni_modules/uni-table/package.json uni_modules/uni-table/readme.md uni_modules/uni-tag/changelog.md uni_modules/uni-tag/components/uni-tag/uni-tag.vue uni_modules/uni-tag/package.json uni_modules/uni-tag/readme.md uni_modules/uni-title/changelog.md uni_modules/uni-title/components/uni-title/uni-title.vue uni_modules/uni-title/package.json uni_modules/uni-title/readme.md uni_modules/uni-tooltip/changelog.md uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue uni_modules/uni-tooltip/package.json uni_modules/uni-tooltip/readme.md uni_modules/uni-transition/changelog.md uni_modules/uni-transition/components/uni-transition/createAnimation.js uni_modules/uni-transition/components/uni-transition/uni-transition.vue uni_modules/uni-transition/package.json uni_modules/uni-transition/readme.md uni_modules/uni-ui/changelog.md uni_modules/uni-ui/components/uni-ui/uni-ui.vue uni_modules/uni-ui/package.json uni_modules/uni-ui/readme.md unpackage/dist/cache/.vite/deps/_metadata.json (已删除) unpackage/dist/cache/.vite/deps/package.json (已删除) unpackage/dist/dev/mp-weixin/api/index.js (已删除) unpackage/dist/dev/mp-weixin/app.js (已删除) unpackage/dist/dev/mp-weixin/app.json (已删除) unpackage/dist/dev/mp-weixin/app.wxss (已删除) unpackage/dist/dev/mp-weixin/common/assets.js (已删除) unpackage/dist/dev/mp-weixin/common/vendor.js (已删除) unpackage/dist/dev/mp-weixin/components/navbar/navbar.js (已删除) unpackage/dist/dev/mp-weixin/components/navbar/navbar.json (已删除) unpackage/dist/dev/mp-weixin/components/navbar/navbar.wxml (已删除) unpackage/dist/dev/mp-weixin/components/navbar/navbar.wxss (已删除) unpackage/dist/dev/mp-weixin/config/baseUrl.js (已删除) unpackage/dist/dev/mp-weixin/pages/addCard/index.js (已删除) unpackage/dist/dev/mp-weixin/pages/addCard/index.json (已删除) unpackage/dist/dev/mp-weixin/pages/addCard/index.wxml (已删除) unpackage/dist/dev/mp-weixin/pages/addCard/index.wxss (已删除) unpackage/dist/dev/mp-weixin/pages/address/index.js (已删除) unpackage/dist/dev/mp-weixin/pages/address/index.json (已删除) unpackage/dist/dev/mp-weixin/pages/address/index.wxml (已删除) unpackage/dist/dev/mp-weixin/pages/address/index.wxss (已删除) unpackage/dist/dev/mp-weixin/pages/index/index.js (已删除) unpackage/dist/dev/mp-weixin/pages/index/index.json (已删除) unpackage/dist/dev/mp-weixin/pages/index/index.wxml (已删除) unpackage/dist/dev/mp-weixin/pages/index/index.wxss (已删除) unpackage/dist/dev/mp-weixin/pages/preSendWater/index.js (已删除) unpackage/dist/dev/mp-weixin/pages/preSendWater/index.json (已删除) unpackage/dist/dev/mp-weixin/pages/preSendWater/index.wxml (已删除) unpackage/dist/dev/mp-weixin/pages/preSendWater/index.wxss (已删除) unpackage/dist/dev/mp-weixin/pages/recharge/index.js (已删除) unpackage/dist/dev/mp-weixin/pages/recharge/index.json (已删除) unpackage/dist/dev/mp-weixin/pages/recharge/index.wxml (已删除) unpackage/dist/dev/mp-weixin/pages/recharge/index.wxss (已删除) unpackage/dist/dev/mp-weixin/pages/sendWater/index.js (已删除) unpackage/dist/dev/mp-weixin/pages/sendWater/index.json (已删除) unpackage/dist/dev/mp-weixin/pages/sendWater/index.wxml (已删除) unpackage/dist/dev/mp-weixin/pages/sendWater/index.wxss (已删除) unpackage/dist/dev/mp-weixin/project.config.json (已删除) unpackage/dist/dev/mp-weixin/project.private.config.json (已删除) unpackage/dist/dev/mp-weixin/static/images/addCard/back.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/back.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/bottom-line.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/code1.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/icon23.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/icon31.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/icon32.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/icon33.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/icon34.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/icon35.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/icon36.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/icon37.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/icon38.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/more-info5.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/vip-add.png (已删除) unpackage/dist/dev/mp-weixin/static/images/index/vip1.png (已删除) unpackage/dist/dev/mp-weixin/static/images/login/logo.png (已删除) unpackage/dist/dev/mp-weixin/static/images/login/wechat.png (已删除) unpackage/dist/dev/mp-weixin/static/images/recharge/balance.png (已删除) unpackage/dist/dev/mp-weixin/static/images/recharge/pay.png (已删除) unpackage/dist/dev/mp-weixin/static/images/recharge/wx.png (已删除) unpackage/dist/dev/mp-weixin/static/logo.png (已删除) unpackage/dist/dev/mp-weixin/util/request.js (已删除)