@ecolovo/uniapp-components 1.0.10 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/README.md +202 -66
  2. package/components/aspect/aspect.vue +24 -15
  3. package/components/badge/badge.scss +20 -0
  4. package/components/badge/badge.vue +49 -40
  5. package/components/button/button.scss +15 -0
  6. package/components/button/button.vue +121 -177
  7. package/components/checkbox/checkbox.scss +10 -0
  8. package/components/checkbox/checkbox.vue +118 -146
  9. package/components/checkbox-group/checkbox-group.vue +79 -85
  10. package/components/checkbox-group2/checkbox-group2.vue +111 -107
  11. package/components/checkbox-group2/checkbox2.vue +104 -0
  12. package/components/data-list/data-list.scss +9 -0
  13. package/components/data-list/data-list.vue +70 -79
  14. package/components/date-picker/date-picker-view.vue +125 -124
  15. package/components/date-picker/date-picker.vue +145 -146
  16. package/components/dialog/dialog-content.vue +39 -47
  17. package/components/dialog/dialog.scss +11 -0
  18. package/components/dialog/dialog.vue +125 -138
  19. package/components/dropdown/dropdown.scss +11 -0
  20. package/components/dropdown/dropdown.vue +55 -97
  21. package/components/empty/empty.scss +14 -0
  22. package/components/empty/empty.vue +42 -41
  23. package/components/flex/flex.vue +45 -54
  24. package/components/form/form.vue +29 -24
  25. package/components/form-item/form-item.scss +11 -0
  26. package/components/form-item/form-item.vue +43 -40
  27. package/components/icon/icon.vue +70 -85
  28. package/components/image/image.vue +35 -38
  29. package/components/input/input.vue +65 -79
  30. package/components/input/password-input.vue +34 -42
  31. package/components/list-page/list-page.vue +73 -99
  32. package/components/load-more/load-more.scss +12 -0
  33. package/components/load-more/load-more.vue +29 -29
  34. package/components/loading/animations/loading-animation1.vue +8 -8
  35. package/components/loading/animations/loading-animation2.vue +8 -9
  36. package/components/loading/animations/loading-animation3.vue +11 -11
  37. package/components/loading/animations/loading-animation4.vue +8 -8
  38. package/components/loading/loading.vue +19 -20
  39. package/components/message-box/message-box.vue +59 -41
  40. package/components/number-dialog/number-dialog.scss +9 -0
  41. package/components/number-dialog/number-dialog.vue +209 -204
  42. package/components/number-input/number-input.scss +9 -0
  43. package/components/number-input/number-input.vue +233 -232
  44. package/components/numpad/numpad.scss +9 -0
  45. package/components/numpad/numpad.vue +133 -150
  46. package/components/page/page-body.scss +15 -0
  47. package/components/page/page-body.vue +137 -119
  48. package/components/page/page-footer.scss +13 -0
  49. package/components/page/page-footer.vue +31 -33
  50. package/components/page/page-header.scss +17 -0
  51. package/components/page/page-header.vue +89 -94
  52. package/components/page/page.scss +9 -0
  53. package/components/page/page.vue +105 -81
  54. package/components/picker/picker-popup.vue +218 -209
  55. package/components/picker/picker.vue +99 -104
  56. package/components/popover/popover-content.vue +54 -63
  57. package/components/popover/popover-mask.vue +63 -63
  58. package/components/popover/popover.scss +28 -0
  59. package/components/popover/popover.vue +49 -47
  60. package/components/popup/popup-content.vue +49 -53
  61. package/components/popup/popup.scss +11 -0
  62. package/components/popup/popup.vue +117 -132
  63. package/components/price/price.scss +20 -0
  64. package/components/price/price.vue +31 -42
  65. package/components/search/search.scss +12 -0
  66. package/components/search/search.vue +93 -117
  67. package/components/searching/searching.vue +33 -40
  68. package/components/selector/selector.vue +43 -48
  69. package/components/switch/switch.scss +12 -0
  70. package/components/switch/switch.vue +99 -96
  71. package/components/tab/tab.scss +19 -0
  72. package/components/tab/tab.vue +151 -145
  73. package/components/textarea/textarea.vue +104 -101
  74. package/composable/component-name.d.ts +2 -0
  75. package/composable/component-name.js +8 -0
  76. package/composable/component-name.ts +10 -0
  77. package/configs/index.d.ts +25 -10
  78. package/configs/index.js +14 -23
  79. package/configs/index.ts +82 -0
  80. package/easyCom.d.ts +9 -0
  81. package/easyCom.js +1 -2
  82. package/easyCom.ts +31 -0
  83. package/index.d.ts +1 -0
  84. package/index.js +1 -0
  85. package/index.ts +1 -0
  86. package/init.d.ts +4 -7
  87. package/init.js +5 -4
  88. package/init.ts +34 -0
  89. package/package.json +14 -4
  90. package/styles/utils/css-var.scss +12 -15
  91. package/styles/utils/ellipsis.scss +0 -7
  92. package/styles/utils/z-index.scss +1 -1
  93. package/styles/var/component.scss +21 -245
  94. package/utils/date.d.ts +47 -0
  95. package/utils/date.js +23 -43
  96. package/utils/date.ts +153 -0
  97. package/utils/freezeDeep.d.ts +1 -0
  98. package/utils/freezeDeep.js +4 -14
  99. package/utils/freezeDeep.ts +9 -0
  100. package/utils/price.d.ts +24 -0
  101. package/utils/price.js +14 -8
  102. package/utils/price.ts +57 -0
  103. package/utils/round.d.ts +2 -0
  104. package/utils/round.js +2 -14
  105. package/utils/round.ts +11 -0
  106. package/utils/windowInfo.d.ts +24 -0
  107. package/utils/windowInfo.js +8 -36
  108. package/utils/windowInfo.ts +50 -0
  109. package/components/checkbox-group2/checkbox.vue +0 -109
  110. package/components/datetime-picker/datetime-picker-view.vue +0 -209
  111. package/components/datetime-picker/datetime-picker.vue +0 -235
  112. package/components/form/mixin.js +0 -13
  113. package/components/list-page/list-page.js +0 -10
  114. package/components/table/table.vue +0 -112
  115. package/components/time-picker/time-picker-view.vue +0 -127
  116. package/components/time-picker/time-picker.vue +0 -140
  117. package/components/uploader/download.js +0 -81
  118. package/components/uploader/file-uploader.vue +0 -52
  119. package/components/uploader/files.js +0 -225
  120. package/components/uploader/media-uploader.vue +0 -189
  121. package/components/uploader/mixin.js +0 -171
  122. package/components/uploader/uni.js +0 -38
  123. package/components/uploader/upload-button.vue +0 -29
  124. package/components/uploader/uploader copy.vue +0 -547
  125. package/components/uploader/uploader.vue +0 -117
  126. package/mixins/componentName.js +0 -32
  127. package/mixins/listPage.js +0 -1
  128. package/mixins/windowInfo.js +0 -1
  129. package/utils/fileSize.js +0 -39
  130. package/utils/floor.js +0 -20
package/utils/price.ts ADDED
@@ -0,0 +1,57 @@
1
+ interface FormatPriceOption {
2
+ /** 精度,默认为 2 */
3
+ precision: number;
4
+ /** 是否补齐小数部分 0 */
5
+ padDecimal: boolean;
6
+ }
7
+ interface FormatPriceResult {
8
+ /** 格式化的价格字符串 */
9
+ price: string;
10
+ /** 是否负值 */
11
+ negative: boolean;
12
+ /** 整数部分价格 */
13
+ integer: string;
14
+ /** 小数部分价格 */
15
+ decimal: string;
16
+ /** 价格对应数值 */
17
+ number: number;
18
+ }
19
+
20
+ /**
21
+ * 格式化价格
22
+ * @param price 价格
23
+ */
24
+ export function formatPrice(price: number | string, option?: FormatPriceOption): FormatPriceResult {
25
+ if (isNaN(Number(price))) {
26
+ return {
27
+ price: '',
28
+ negative: false,
29
+ integer: '',
30
+ decimal: '',
31
+ number: NaN,
32
+ };
33
+ }
34
+ price = Number(price);
35
+ let negative = false;
36
+ if (price < 0) {
37
+ negative = true;
38
+ price = -price;
39
+ }
40
+ const integer = Math.floor(price).toString();
41
+ const decimalNum = Math.round(Number(price + 'e' + (option?.precision ?? 2))) % 100;
42
+ let decimal: string;
43
+ if (option?.padDecimal ?? true) {
44
+ decimal = '.' + decimalNum.toString().padStart(option?.precision ?? 2, '0');
45
+ } else {
46
+ if (decimalNum === 0) decimal = '';
47
+ else decimal = decimalNum.toString().slice(1);
48
+ }
49
+ const formattedPrice = `${negative ? '-' : ''}${integer}.${decimal}`;
50
+ return {
51
+ price: formattedPrice, // 价格字符串
52
+ negative,
53
+ integer, // 整数部分
54
+ decimal, // 小数部分
55
+ number: Number(formattedPrice),
56
+ };
57
+ }
@@ -0,0 +1,2 @@
1
+ export declare function round(val: number, precision?: number): number;
2
+ export declare function round2(val: number): number;
package/utils/round.js CHANGED
@@ -1,22 +1,10 @@
1
- /**
2
- * 四舍五入处理
3
- * @param {number} val 需要处理的数据
4
- * @param {number} precision 保留小数位数,默认不保留
5
- * @returns {number} 处理后的数据
6
- */
7
1
  export function round(val, precision = 0) {
8
2
  if (val.toString().indexOf('e') >= 0) {
9
3
  const exponential = val.toString().split('e');
10
- return Math.round(exponential[0] + 'e' + (+exponential[1] + precision)) / Math.pow(10, precision);
4
+ return Math.round(+`${exponential[0]}e${+exponential[1] + precision}`) / 10 ** precision;
11
5
  }
12
- return Math.round(+val + 'e' + precision) / Math.pow(10, precision);
6
+ return Math.round(+`${val}e${precision}`) / 10 ** precision;
13
7
  }
14
-
15
- /**
16
- * 四舍五入处理,并保留 2 位小数
17
- * @param {number} val 需要处理的数据
18
- * @returns {number} 处理后的数据
19
- */
20
8
  export function round2(val) {
21
9
  return round(val, 2);
22
10
  }
package/utils/round.ts ADDED
@@ -0,0 +1,11 @@
1
+ export function round(val: number, precision = 0): number {
2
+ if (val.toString().indexOf('e') >= 0) {
3
+ const exponential = val.toString().split('e');
4
+ return Math.round(+`${exponential[0]}e${+exponential[1]! + precision}`) / 10 ** precision;
5
+ }
6
+ return Math.round(+`${val}e${precision}`) / 10 ** precision;
7
+ }
8
+
9
+ export function round2(val: number): number {
10
+ return round(val, 2);
11
+ }
@@ -0,0 +1,24 @@
1
+ /// <reference types="@dcloudio/types" />
2
+ /** 胶囊按钮位置信息 */
3
+ declare let menuButton: UniApp.GetMenuButtonBoundingClientRectRes | null;
4
+ /** 胶囊按钮宽度,仅在 css 中使用,当有胶囊按钮时,表示胶囊按钮左边缘到屏幕右侧的宽度,否则为 `0px` */
5
+ declare let menuButtonWidthInCss: string;
6
+ /** 系统信息 */
7
+ declare let windowInfo: UniApp.GetWindowInfoResult | null;
8
+ /** 导航栏高度 */
9
+ declare let navBarHeight: number;
10
+ /** 导航栏顶部距离 */
11
+ declare let navBarTopOffset: number;
12
+ /** 导航栏底部距离 */
13
+ declare let navBarBottomOffset: number;
14
+ /** 底部安全区域高度 */
15
+ declare let safeAreaInsetBottom: number;
16
+ export {
17
+ menuButton,
18
+ menuButtonWidthInCss,
19
+ windowInfo,
20
+ navBarHeight,
21
+ navBarTopOffset,
22
+ navBarBottomOffset,
23
+ safeAreaInsetBottom,
24
+ };
@@ -1,12 +1,10 @@
1
1
  /** 默认导航栏高度 */
2
2
  const NAV_TITLE_HEIGHT = 44;
3
- /** 胶囊按钮位置信息
4
- * @type {UniApp.GetMenuButtonBoundingClientRectRes | null}
5
- */
3
+ /** 胶囊按钮位置信息 */
6
4
  let menuButton = null;
7
- /** 系统信息
8
- * @type {UniApp.GetWindowInfoResult | null}
9
- */
5
+ /** 胶囊按钮宽度,仅在 css 中使用,当有胶囊按钮时,表示胶囊按钮左边缘到屏幕右侧的宽度,否则为 `0px` */
6
+ let menuButtonWidthInCss = '0px';
7
+ /** 系统信息 */
10
8
  let windowInfo = null;
11
9
  /** 导航栏高度 */
12
10
  let navBarHeight = NAV_TITLE_HEIGHT;
@@ -14,23 +12,20 @@ let navBarHeight = NAV_TITLE_HEIGHT;
14
12
  let navBarTopOffset = 0;
15
13
  /** 导航栏底部距离 */
16
14
  let navBarBottomOffset = NAV_TITLE_HEIGHT;
17
- /** 底部安全区域高度
18
- * @type {number}
19
- */
15
+ /** 底部安全区域高度 */
20
16
  let safeAreaInsetBottom = uni.upx2px(50);
21
-
22
17
  /* #ifdef MP-WEIXIN || MP-ALIPAY */
23
18
  menuButton = uni.getMenuButtonBoundingClientRect();
24
19
  /* #endif */
25
20
  windowInfo = uni.getWindowInfo();
26
21
  // eslint-disable-next-line no-console
27
22
  console.log('windowInfo:', windowInfo);
28
-
29
23
  if (menuButton) {
30
24
  if (navBarHeight < menuButton.height) {
31
25
  navBarHeight = menuButton.height + 12;
32
26
  }
33
- navBarTopOffset = menuButton.top - (navBarHeight - menuButton.height) / 3;
27
+ navBarTopOffset = menuButton.top - (navBarHeight - menuButton.height) / 2;
28
+ menuButtonWidthInCss = 'calc(100vw - ' + menuButton.left + 'px)';
34
29
  } else {
35
30
  navBarTopOffset = windowInfo.safeArea.top || windowInfo.statusBarHeight;
36
31
  }
@@ -39,35 +34,12 @@ const _safeAreaBottom = windowInfo.screenHeight - windowInfo.safeArea.bottom;
39
34
  if (_safeAreaBottom) {
40
35
  safeAreaInsetBottom = _safeAreaBottom;
41
36
  }
42
-
43
- /** mixin */
44
- const windowInfoMixin = {
45
- computed: {
46
- /** 胶囊按钮位置信息 */
47
- menuButton: () => menuButton,
48
- /** 胶囊按钮宽度 */
49
- menuButtonWidth() {
50
- return this.menuButton ? 'calc(100vw - ' + this.menuButton.left + 'px)' : '0px';
51
- },
52
- /** 系统信息 */
53
- windowInfo: () => windowInfo,
54
- /** 导航栏高度 */
55
- navBarHeight: () => navBarHeight,
56
- /** 导航栏顶部距离 */
57
- navBarTopOffset: () => navBarTopOffset,
58
- /** 导航栏底部距离 */
59
- navBarBottomOffset: () => navBarBottomOffset,
60
- /** 底部安全区域高度 */
61
- safeAreaInsetBottom: () => safeAreaInsetBottom,
62
- },
63
- };
64
-
65
37
  export {
66
38
  menuButton,
39
+ menuButtonWidthInCss,
67
40
  windowInfo,
68
41
  navBarHeight,
69
42
  navBarTopOffset,
70
43
  navBarBottomOffset,
71
44
  safeAreaInsetBottom,
72
- windowInfoMixin,
73
45
  };
@@ -0,0 +1,50 @@
1
+ /** 默认导航栏高度 */
2
+ const NAV_TITLE_HEIGHT = 44;
3
+
4
+ /** 胶囊按钮位置信息 */
5
+ let menuButton: UniApp.GetMenuButtonBoundingClientRectRes | null = null;
6
+ /** 胶囊按钮宽度,仅在 css 中使用,当有胶囊按钮时,表示胶囊按钮左边缘到屏幕右侧的宽度,否则为 `0px` */
7
+ let menuButtonWidthInCss: string = '0px';
8
+ /** 系统信息 */
9
+ let windowInfo: UniApp.GetWindowInfoResult | null = null;
10
+ /** 导航栏高度 */
11
+ let navBarHeight = NAV_TITLE_HEIGHT;
12
+ /** 导航栏顶部距离 */
13
+ let navBarTopOffset = 0;
14
+ /** 导航栏底部距离 */
15
+ let navBarBottomOffset = NAV_TITLE_HEIGHT;
16
+ /** 底部安全区域高度 */
17
+ let safeAreaInsetBottom = uni.upx2px(50);
18
+
19
+ /* #ifdef MP-WEIXIN || MP-ALIPAY */
20
+ menuButton = uni.getMenuButtonBoundingClientRect();
21
+ /* #endif */
22
+ windowInfo = uni.getWindowInfo();
23
+ // eslint-disable-next-line no-console
24
+ console.log('windowInfo:', windowInfo);
25
+
26
+ if (menuButton) {
27
+ if (navBarHeight < menuButton.height) {
28
+ navBarHeight = menuButton.height + 12;
29
+ }
30
+ navBarTopOffset = menuButton.top - (navBarHeight - menuButton.height) / 2;
31
+
32
+ menuButtonWidthInCss = 'calc(100vw - ' + menuButton.left + 'px)';
33
+ } else {
34
+ navBarTopOffset = windowInfo.safeArea.top || windowInfo.statusBarHeight;
35
+ }
36
+ navBarBottomOffset = navBarTopOffset + navBarHeight;
37
+ const _safeAreaBottom = windowInfo.screenHeight - windowInfo.safeArea.bottom;
38
+ if (_safeAreaBottom) {
39
+ safeAreaInsetBottom = _safeAreaBottom;
40
+ }
41
+
42
+ export {
43
+ menuButton,
44
+ menuButtonWidthInCss,
45
+ windowInfo,
46
+ navBarHeight,
47
+ navBarTopOffset,
48
+ navBarBottomOffset,
49
+ safeAreaInsetBottom,
50
+ };
@@ -1,109 +0,0 @@
1
- <template>
2
- <view :class="componentClassNames" @click="toggle()">
3
- <icon-cpn
4
- v-if="icon"
5
- :icon="currentValue ? checkedIcon || 'checkbox-checked' : uncheckedIcon || 'checkbox-unchecked'"
6
- tap-size="50rpx"
7
- :class="[$style['Checkbox2--icon'], { [$style['Checkbox2--checked']]: currentValue }]"
8
- />
9
- <view :class="$style['Checkbox2--text']">
10
- <slot></slot>
11
- </view>
12
- </view>
13
- </template>
14
-
15
- <script>
16
- import componentName from '../../mixins/componentName';
17
- import IconCpn from '../icon/icon.vue';
18
-
19
- export default {
20
- name: 'Checkbox2',
21
- options: {
22
- virtualHost: true,
23
- styleIsolation: 'shared',
24
- },
25
- components: { IconCpn },
26
- mixins: [componentName],
27
- props: {
28
- /** 值 */
29
- value: {
30
- type: [Boolean, null],
31
- default: null,
32
- },
33
- /** 是否显示勾选图标 */
34
- icon: {
35
- type: Boolean,
36
- default: true,
37
- },
38
- /** 选中时的图标 */
39
- checkedIcon: {
40
- type: String,
41
- default: '',
42
- },
43
- /** 未选中时的图标 */
44
- uncheckedIcon: {
45
- type: String,
46
- default: '',
47
- },
48
- },
49
- data() {
50
- return {
51
- innerValue: false,
52
- };
53
- },
54
- computed: {
55
- currentValue: {
56
- get: function () {
57
- return this.value === null ? this.innerValue : this.value;
58
- },
59
- set: function (val) {
60
- this.$emit('input', val);
61
- this.innerValue = val;
62
- this.$emit('change', val);
63
- },
64
- },
65
- },
66
- methods: {
67
- /** 切换选择 */
68
- toggle(checked) {
69
- if (checked === undefined || checked === null) {
70
- this.currentValue = !this.currentValue;
71
- return;
72
- }
73
-
74
- if (this.currentValue !== !!checked) {
75
- this.currentValue = !!checked;
76
- }
77
- },
78
- },
79
- };
80
- </script>
81
-
82
- <style lang="scss" module>
83
- @use '../../styles/index' as *;
84
-
85
- // 定义外部变量
86
- $component-name: 'checkbox';
87
- $component-vars: $checkbox;
88
- %external-vars {
89
- @include UTILS__DEFINE_COMPONENT_VARS();
90
- }
91
-
92
- .Checkbox2 {
93
- @extend %external-vars;
94
- display: flex;
95
- align-items: center;
96
-
97
- .Checkbox2--icon {
98
- flex: none;
99
- margin-right: 12rpx;
100
- color: UTILS__LOCAL_VAR(unchecked-color);
101
- }
102
- .Checkbox2--checked {
103
- color: UTILS__LOCAL_VAR(checked-color);
104
- }
105
- .Checkbox2--text {
106
- flex: 0 1 auto;
107
- }
108
- }
109
- </style>
@@ -1,209 +0,0 @@
1
- <template>
2
- <picker-view
3
- immediate-change
4
- :value="pickerValue"
5
- :class="componentClassNames"
6
- @change="handlePickerChange"
7
- @pickend="onPickEnd"
8
- >
9
- <picker-view-column>
10
- <view v-for="item in yearOptions" :key="item" :class="$style['DatetimePickerView--option']">
11
- {{ item }} 年
12
- </view>
13
- </picker-view-column>
14
- <picker-view-column>
15
- <view v-for="item in monthOptions" :key="item" :class="$style['DatetimePickerView--option']">
16
- {{ item }} 月
17
- </view>
18
- </picker-view-column>
19
- <picker-view-column>
20
- <view v-for="item in dateOptions" :key="item" :class="$style['DatetimePickerView--option']">
21
- {{ item }} 日
22
- </view>
23
- </picker-view-column>
24
- <picker-view-column>
25
- <view v-for="item in hourOptions" :key="item" :class="$style['DatetimePickerView--option']">
26
- {{ item }} 时
27
- </view>
28
- </picker-view-column>
29
- <picker-view-column v-if="minuteStep > 0">
30
- <view v-for="item in minuteOptions" :key="item" :class="$style['DatetimePickerView--option']">
31
- {{ item }} 分
32
- </view>
33
- </picker-view-column>
34
- </picker-view>
35
- </template>
36
-
37
- <script>
38
- import range from 'lodash-es/range';
39
- import componentName from '../../mixins/componentName';
40
- import { formatDate, toDate } from '../../utils/date';
41
-
42
- /** 年份选项 */
43
- const yearOptions = (function () {
44
- const arr = [];
45
- for (let i = 1900; i <= 2099; i++) {
46
- arr.push(i);
47
- }
48
- return arr;
49
- })();
50
-
51
- /** 获取指定日期所在月份的日期选项列表 */
52
- function getDateOptions(date) {
53
- date = new Date(date);
54
- date.setMonth(date.getMonth() + 1, 0);
55
- const max = date.getDate();
56
- return range(1, max + 1);
57
- }
58
-
59
- export default {
60
- name: 'DatetimePickerView',
61
- options: {
62
- virtualHost: true,
63
- styleIsolation: 'shared',
64
- },
65
- mixins: [componentName],
66
- props: {
67
- /** 绑定值 */
68
- value: {
69
- type: [String, null],
70
- default: null,
71
- },
72
- /** 是否在选择开始日期时,同步修改结束日期,且保持时间差 */
73
- keepDiff: {
74
- type: Boolean,
75
- default: false,
76
- },
77
- /** 结束日期是否可以与开始日期相同 */
78
- canSame: {
79
- type: Boolean,
80
- default: false,
81
- },
82
- /** 最小日期 */
83
- min: {
84
- type: String,
85
- default: '',
86
- },
87
- /** 最大日期 */
88
- max: {
89
- type: String,
90
- default: '',
91
- },
92
- /** 分钟步长 */
93
- minuteStep: {
94
- type: Number,
95
- default: 5,
96
- },
97
- },
98
- data() {
99
- return {
100
- innerValue: '',
101
- /** 年份选项列表 */
102
- yearOptions: yearOptions,
103
- /** 月份选项列表 */
104
- monthOptions: range(1, 13),
105
- /** 日期选项列表 */
106
- dateOptions: [],
107
- /** 小时选项列表 */
108
- hourOptions: range(0, 24),
109
- /** 分钟选项列表 */
110
- minuteOptions: [],
111
- /** picker-view 绑定值 */
112
- pickerValue: [0, 0, 0, 0, 0],
113
- };
114
- },
115
- computed: {
116
- currentValue: {
117
- get: function () {
118
- return this.value === null ? this.innerValue : this.value;
119
- },
120
- set: function (value) {
121
- this.$emit('input', value);
122
- this.innerValue = value;
123
- this.$emit('change', value);
124
- },
125
- },
126
- },
127
- created() {
128
- this.minuteOptions = range(0, 60, this.minuteStep);
129
- },
130
- mounted() {
131
- this.$nextTick(() => {
132
- this.syncPickerValue(this.currentValue || new Date());
133
- });
134
- },
135
- methods: {
136
- /** 同步 picker-view 选中索引 */
137
- syncPickerValue(date) {
138
- const dateObj = toDate(date || new Date());
139
- const [Y, M, D, h, m] = formatDate(dateObj, 'YYYY-MM-DD-HH-mm').split('-');
140
- this.dateOptions = getDateOptions(dateObj);
141
- const i1 = this.yearOptions.indexOf(Number(Y));
142
- const i2 = this.monthOptions.indexOf(Number(M));
143
- const i3 = this.dateOptions.indexOf(Number(D));
144
- const i4 = this.hourOptions.indexOf(Number(h));
145
- const i5 = Math.max(
146
- this.minuteOptions.indexOf(Math.round(Number(m) / this.minuteStep) * this.minuteStep),
147
- 0
148
- );
149
- this.$nextTick(() => {
150
- this.pickerValue =
151
- typeof this.pickerValue[0] === 'number'
152
- ? [i1, i2, i3, i4, i5].map((item) => item.toString())
153
- : [i1, i2, i3, i4, i5];
154
- });
155
- },
156
- /** picker-view 选项值变化处理 */
157
- handlePickerChange(e) {
158
- const newPickerValue = e.detail.value;
159
- /** 获取变化的列 */
160
- const col = this.pickerValue.findIndex((item, index) => Number(item) !== Number(newPickerValue[index]));
161
- const year = this.yearOptions[newPickerValue[0]];
162
- const month = this.monthOptions[newPickerValue[1]];
163
- // 如果改变的是年份或月份,需要重新获取日期列表
164
- if (col === 0 || col === 1) {
165
- this.dateOptions = getDateOptions(toDate(`${year}-${month}-01`));
166
- newPickerValue[2] = Math.min(
167
- newPickerValue[2] === -1 ? this.dateOptions.length - 1 : newPickerValue[2],
168
- this.dateOptions.length - 1
169
- );
170
- }
171
- const date = this.dateOptions[newPickerValue[2]];
172
- const hour = this.hourOptions[newPickerValue[3]];
173
- const minute = this.minuteStep >= 0 ? this.minuteOptions[newPickerValue[4]] : '00';
174
-
175
- this.pickerValue = newPickerValue;
176
- const dateValue = new Date(year, month - 1, date, hour, minute, 0, 0);
177
- let dateStr = formatDate(dateValue, formatDate.DATE_MINUTE_WITH_YEAR);
178
- if (this.min && dateStr < this.min) {
179
- dateStr = this.min;
180
- }
181
- if (this.max && dateStr > this.max) {
182
- dateStr = this.max;
183
- }
184
- this.currentValue = dateStr;
185
- },
186
- /** 滑动结束处理,保持选择器显示值与输入框值一致 */
187
- onPickEnd() {
188
- this.$nextTick(() => {
189
- this.syncPickerValue(this.currentValue);
190
- });
191
- },
192
- },
193
- };
194
- </script>
195
-
196
- <style lang="scss" module>
197
- @use '../../styles/index' as *;
198
-
199
- .DatetimePickerView {
200
- margin-top: 24rpx;
201
- height: 300rpx;
202
- }
203
- .DatetimePickerView--option {
204
- display: flex;
205
- align-items: center;
206
- justify-content: center;
207
- white-space: nowrap;
208
- }
209
- </style>