yt-dateTimePicker.vue 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. <template>
  2. <view class="yt-dateTimePicker" v-if="done">
  3. <view class="mask" :class="{ show: open }" @touchmove.stop.prevent catchtouchmove="true">
  4. </view>
  5. <view class="wrap" :class="{ show: open }">
  6. <view class="picker-header" @touchmove.stop.prevent catchtouchmove="true">
  7. <view class="btn-picker cancel" @click="open = false">取消</view>
  8. <view>请选择时间</view>
  9. <view class="btn-picker submit" @click="_onSubmit">确定</view>
  10. </view>
  11. <view class="picker-body">
  12. <picker-view :value="value" @change="_onChange">
  13. <picker-view-column v-if="timeHide[0]">
  14. <view class="column-item" v-for="item in years" :key="item">
  15. {{ item + timeLabel[0] }}
  16. </view>
  17. </picker-view-column>
  18. <picker-view-column v-if="timeHide[1]">
  19. <view class="column-item" v-for="item in months" :key="item">
  20. {{ formatNum(item) + timeLabel[1] }}
  21. </view>
  22. </picker-view-column>
  23. <picker-view-column v-if="timeHide[2]">
  24. <view class="column-item" v-for="item in days" :key="item">
  25. {{ formatNum(item) + timeLabel[2] }}
  26. </view>
  27. </picker-view-column>
  28. <picker-view-column v-if="timeHide[3]">
  29. <view class="column-item" v-for="item in hours" :key="item">
  30. {{ formatNum(item) + timeLabel[3] }}
  31. </view>
  32. </picker-view-column>
  33. <picker-view-column v-if="timeHide[4]">
  34. <view class="column-item" v-for="item in minutes" :key="item">
  35. {{ formatNum(item) + timeLabel[4] }}
  36. </view>
  37. </picker-view-column>
  38. <picker-view-column v-if="timeHide[5]">
  39. <view class="column-item" v-for="item in seconds" :key="item">
  40. {{ formatNum(item) + timeLabel[5] }}
  41. </view>
  42. </picker-view-column>
  43. </picker-view>
  44. </view>
  45. </view>
  46. </view>
  47. </template>
  48. <script>
  49. export default {
  50. name: "yt-dateTimePicker",
  51. props: {
  52. startYear: {
  53. type: Number,
  54. default: 2000,
  55. },
  56. endYear: {
  57. type: Number,
  58. default: 2099,
  59. },
  60. timeLabel: {
  61. type: Array,
  62. default: () => ["年", "月", "日", "时", "分", "秒"],
  63. },
  64. timeHide: {
  65. type: Array,
  66. default: () => [true, true, true, true, true, true],
  67. },
  68. timeInit: {
  69. type: Number,
  70. default: new Date().valueOf(),
  71. },
  72. },
  73. data() {
  74. return {
  75. open: false,
  76. years: [],
  77. months: [],
  78. days: [],
  79. hours: [],
  80. minutes: [],
  81. seconds: [],
  82. year: "",
  83. month: "",
  84. day: "",
  85. hour: "",
  86. minute: "",
  87. second: "",
  88. value: [0, 0, 0, 0, 0, 0],
  89. done: false,
  90. };
  91. },
  92. computed: {
  93. currentDatetime() {
  94. return new Date(this.timeInit);
  95. },
  96. },
  97. mounted() {
  98. this.init();
  99. },
  100. watch: {
  101. month() {
  102. this.initDays();
  103. },
  104. },
  105. methods: {
  106. init() {
  107. this.initYears();
  108. this.initMonths();
  109. this.initDays();
  110. this.initHours();
  111. this.initMinutes();
  112. this.initSeconds();
  113. this.setSelectValue();
  114. this.done = true;
  115. },
  116. initYears() {
  117. const years = [];
  118. for (let year = this.startYear; year <= this.endYear; year++) {
  119. years.push(year);
  120. if (this.currentDatetime.getFullYear() === year) {
  121. this.$set(this.value, 0, year - this.startYear);
  122. }
  123. }
  124. this.years = years;
  125. },
  126. initMonths() {
  127. const months = [];
  128. for (let month = 1; month <= 12; month++) {
  129. months.push(month);
  130. if (this.currentDatetime.getMonth() + 1 === month) {
  131. this.$set(this.value, 1, month - 1);
  132. }
  133. }
  134. this.months = months;
  135. },
  136. initDays() {
  137. const value = this.value;
  138. const selectedYear = this.years[value[0]];
  139. const selectedMonth = this.months[value[1]];
  140. const days = [];
  141. const totalDays = new Date(selectedYear, selectedMonth, 0).getDate();
  142. for (let day = 1; day <= totalDays; day++) {
  143. days.push(day);
  144. if (this.currentDatetime.getDate() === day) {
  145. this.$set(value, 2, day - 1);
  146. }
  147. }
  148. this.days = days;
  149. },
  150. initHours() {
  151. const hours = [];
  152. for (let hour = 0; hour <= 23; hour++) {
  153. hours.push(hour);
  154. if (this.currentDatetime.getHours() === hour) {
  155. this.$set(this.value, 3, hour);
  156. }
  157. }
  158. this.hours = hours;
  159. },
  160. initMinutes() {
  161. const minutes = [];
  162. for (let minute = 0; minute < 60; minute++) {
  163. minutes.push(minute);
  164. if (this.currentDatetime.getMinutes() === minute) {
  165. this.$set(this.value, 4, minute);
  166. }
  167. }
  168. this.minutes = minutes;
  169. },
  170. initSeconds() {
  171. const seconds = [];
  172. for (let second = 0; second < 60; second++) {
  173. seconds.push(second);
  174. if (this.currentDatetime.getSeconds() === second) {
  175. this.$set(this.value, 5, second);
  176. }
  177. }
  178. this.seconds = seconds;
  179. },
  180. show() {
  181. this.init();
  182. this.open = true;
  183. },
  184. hide() {
  185. this.open = false;
  186. },
  187. _onChange(e) {
  188. this.value = e.detail.value;
  189. this.setSelectValue();
  190. },
  191. setSelectValue() {
  192. const v = this.value;
  193. this.year = this.years[v[0]];
  194. this.month = this.months[v[1]];
  195. this.day = this.days[v[2]];
  196. this.hour = this.hours[v[3]];
  197. this.minute = this.minutes[v[4]];
  198. this.second = this.seconds[v[5]];
  199. },
  200. _onSubmit() {
  201. const {
  202. year,
  203. month,
  204. day,
  205. hour,
  206. minute,
  207. second,
  208. formatNum,
  209. timeHide,
  210. timeLabel,
  211. } = this;
  212. const result = {
  213. year: timeHide[0] ? formatNum(year) : "",
  214. month: timeHide[1] ? formatNum(month) : "",
  215. day: timeHide[2] ? formatNum(day) : "",
  216. hour: timeHide[3] ? formatNum(hour) : "",
  217. minute: timeHide[4] ? formatNum(minute) : "",
  218. second: timeHide[5] ? formatNum(second) : "",
  219. };
  220. this.$emit("submit", result);
  221. this.hide();
  222. },
  223. formatNum(num) {
  224. return num < 10 ? "0" + num : num + "";
  225. },
  226. },
  227. };
  228. </script>
  229. <style lang="scss">
  230. $transition: all 0.3s ease;
  231. $primary: #54cf4c;
  232. .yt-dateTimePicker {
  233. position: relative;
  234. z-index: 999;
  235. picker-view {
  236. height: 100%;
  237. }
  238. .mask {
  239. position: fixed;
  240. z-index: 1000;
  241. top: 0;
  242. right: 0;
  243. bottom: 0;
  244. left: 0;
  245. background-color: rgba(0, 0, 0, 0.4);
  246. visibility: hidden;
  247. opacity: 0;
  248. transition: $transition;
  249. &.show {
  250. visibility: visible;
  251. opacity: 1;
  252. }
  253. }
  254. .wrap {
  255. z-index: 1001;
  256. position: fixed;
  257. bottom: 0;
  258. left: 0;
  259. width: 100%;
  260. transition: $transition;
  261. transform: translateY(100%);
  262. &.show {
  263. transform: translateY(0);
  264. }
  265. }
  266. .picker-header {
  267. display: flex;
  268. flex-direction: row;
  269. justify-content: space-between;
  270. align-items: center;
  271. padding: 8px 8px;
  272. background-color: darken(#fff, 2%);
  273. background-color: #fff;
  274. }
  275. .picker-body {
  276. width: 100%;
  277. height: 420rpx;
  278. overflow: hidden;
  279. background-color: #fff;
  280. }
  281. .column-item {
  282. text-overflow: ellipsis;
  283. white-space: nowrap;
  284. display: flex;
  285. justify-content: center;
  286. align-items: center;
  287. }
  288. .btn-picker {
  289. position: relative;
  290. display: inline-block;
  291. padding-left: 10px;
  292. padding-right: 10px;
  293. box-sizing: border-box;
  294. text-align: center;
  295. text-decoration: none;
  296. line-height: 2;
  297. -webkit-tap-highlight-color: transparent;
  298. overflow: hidden;
  299. background-color: #eee;
  300. font-size: 14px;
  301. border-radius: 3px;
  302. color: #000;
  303. cursor: pointer;
  304. }
  305. .btn-picker.submit {
  306. background-color: $primary;
  307. color: #fff;
  308. }
  309. }
  310. </style>