date-selector-picker.vue 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. <template>
  2. <view class="lb-selector-picker lb-picker-item"
  3. :style="{ height: height }">
  4. <picker-view :value="pickerValue"
  5. :style="{ height: height }"
  6. :indicator-style="indicatorStyle"
  7. @change="handleChange">
  8. <picker-view-column v-for="(column, index) in pickerColumns"
  9. :key="column.name">
  10. <view v-for="item in column.list || []"
  11. :class="[
  12. 'lb-picker-column',
  13. item.value === selectValue[index]
  14. ? 'lb-picker-column-active'
  15. : ''
  16. ]"
  17. :key="item.value">
  18. <!-- #ifdef APP-PLUS || H5 -->
  19. <text :class="[
  20. 'lb-picker-column-label',
  21. `lb-picker-column-label-${align}`
  22. ]"
  23. :style="[
  24. item.value === selectValue[index]
  25. ? activeColumnStyle
  26. : columnStyle
  27. ]">{{ item.label }}</text>
  28. <!-- #endif -->
  29. <!-- #ifndef APP-PLUS || H5 -->
  30. <text :class="[
  31. 'lb-picker-column-label',
  32. `lb-picker-column-label-${align}`
  33. ]">{{ item.label }}</text>
  34. <!-- #endif -->
  35. </view>
  36. </picker-view-column>
  37. </picker-view>
  38. </view>
  39. </template>
  40. <script>
  41. import { isFunction } from '../utils'
  42. const INVALID_DATE = 'Invalid Date'
  43. const dayjs = require('../lib/dayjs.min.js')
  44. const objectSupport = require('../lib/object-support.min.js')
  45. const customParseFormat = require('../lib/custom-parse-format.min.js')
  46. dayjs.extend(objectSupport)
  47. dayjs.extend(customParseFormat)
  48. export default {
  49. props: {
  50. value: String,
  51. mode: String,
  52. visible: Boolean,
  53. height: String,
  54. columnStyle: Object,
  55. activeColumnStyle: Object,
  56. align: String,
  57. formatter: Function,
  58. format: String,
  59. displayFormat: String,
  60. startDate: String,
  61. endDate: String,
  62. defaultTimeLimit: Number,
  63. isShowChinese: Boolean,
  64. chConfig: Object,
  65. filter: Function
  66. },
  67. data () {
  68. return {
  69. pickerValue: [],
  70. pickerColumns: [],
  71. selectValue: [],
  72. selectItem: null,
  73. isConfirmChange: false,
  74. indicatorStyle: `height: 34px`,
  75. dayjs: dayjs,
  76. startInfo: {},
  77. endInfo: {}
  78. }
  79. },
  80. created () {
  81. this.init('init')
  82. },
  83. methods: {
  84. init (changeType) {
  85. this.startInfo = this.toObject(
  86. this.startDate
  87. ? this.startDate
  88. : this.dayjs().subtract(this.defaultTimeLimit, 'year').$d
  89. )
  90. this.endInfo = this.toObject(
  91. this.endDate
  92. ? this.endDate
  93. : this.dayjs().add(this.defaultTimeLimit, 'year').$d
  94. )
  95. this.selectDate = this.value
  96. ? this.dayjs(this.value, this.format)
  97. : new Date()
  98. if (!this.validate('date')) {
  99. throw new Error('日期格式不合法')
  100. }
  101. if (!this.validate('displayFormat')) {
  102. throw new Error('display-format参数异常')
  103. }
  104. if (this.startInfo.timestamp > this.endInfo.timestamp) {
  105. throw new Error('开始结束日期异常,startDate不得大于endDate')
  106. }
  107. this.selectItem = this.toObject(this.selectDate)
  108. this.setColumnData()
  109. const value = this.getValueDate()
  110. this.$emit('change', {
  111. value: value.format(this.format),
  112. valueArr: this.selectValue,
  113. item: this.selectItem,
  114. index: this.pickerValue,
  115. change: changeType
  116. })
  117. },
  118. handleChange (item) {
  119. const pickerValue = item.detail.value
  120. const columnIndex = pickerValue.findIndex(
  121. (item, i) => item !== this.pickerValue[i]
  122. )
  123. if (columnIndex > -1) {
  124. const valueIndex = pickerValue[columnIndex]
  125. const columnItem = this.pickerColumns[columnIndex]
  126. const columnName = columnItem.name
  127. const valueItem = columnItem.list[valueIndex]
  128. this.pickerValue = pickerValue
  129. this.$set(this.selectValue, columnIndex, valueItem.value)
  130. this.$set(this.selectItem, columnName, valueItem.value)
  131. this.setColumnData(columnIndex)
  132. const value = this.getValueDate()
  133. this.$emit('change', {
  134. value: value.format(this.format),
  135. valueArr: this.selectValue,
  136. item: this.selectItem,
  137. index: this.pickerValue,
  138. change: 'scroll'
  139. })
  140. }
  141. },
  142. getLabel (value, name, format, $d, rowIndex, columnIndex) {
  143. const ch = this.isShowChinese ? this.chConfig[name] || '' : ''
  144. let label =
  145. value < 10 && format.length > 1 ? `0${value}${ch}` : value + ch
  146. if (this.formatter && isFunction(this.formatter)) {
  147. const item = { name, format, value, $d }
  148. label = this.formatter({ item, rowIndex, columnIndex }) || label
  149. }
  150. return label
  151. },
  152. getValueDate (dateObj = {}) {
  153. let selectItem = {
  154. ...this.selectItem,
  155. ...dateObj
  156. }
  157. selectItem.month = selectItem.month - 1
  158. return this.dayjs(selectItem)
  159. },
  160. setColumnData (n = 0) {
  161. const formatArr = this.displayFormat.split('-')
  162. const formatObj = {
  163. YY: 'year',
  164. YYYY: 'year',
  165. M: 'month',
  166. MM: 'month',
  167. D: 'day',
  168. DD: 'day',
  169. h: 'hour',
  170. HH: 'hour',
  171. h: 'hour',
  172. hh: 'hour',
  173. m: 'minute',
  174. mm: 'minute',
  175. s: 'second',
  176. ss: 'second'
  177. }
  178. formatArr.forEach((item, index) => {
  179. if (index >= n) {
  180. const name = formatObj[item]
  181. const obj = {
  182. name: name,
  183. list: this.getColumnData(name, item, index)
  184. }
  185. let value = this.selectItem[name]
  186. if (index !== n) {
  187. this.$set(this.pickerColumns, index, obj)
  188. }
  189. let n = obj.list.findIndex(l => l.value === value)
  190. if (n < 0) {
  191. const l = obj.list.length - 1
  192. const firstValue = obj.list[0].value
  193. const lastValue = obj.list[l].value
  194. if (value < firstValue) {
  195. n = 0
  196. value = firstValue
  197. }
  198. if (value > lastValue) {
  199. n = l
  200. value = lastValue
  201. }
  202. if (n < 0) {
  203. n = 0
  204. value = firstValue
  205. }
  206. }
  207. this.$set(this.pickerValue, index, n)
  208. this.$set(this.selectValue, index, value)
  209. this.$set(this.selectItem, name, value)
  210. }
  211. })
  212. },
  213. isSame (name, type = 'startInfo') {
  214. let same = true
  215. const arr = ['year', 'month', 'day', 'hour', 'minute', 'second']
  216. const index = arr.findIndex(item => item === name)
  217. if (index > -1) {
  218. const slice = arr.slice(0, index + 1)
  219. for (let i = 0; i < slice.length; i++) {
  220. same = same && this.selectItem[slice[i]] === this[type][slice[i]]
  221. }
  222. }
  223. return same
  224. },
  225. getColumnData (name, format, index) {
  226. let list = []
  227. let start = 0
  228. let end = 0
  229. let n = 0
  230. const obj = {
  231. month: 'year',
  232. day: 'month',
  233. hour: 'day',
  234. minute: 'hour',
  235. second: 'minute'
  236. }
  237. switch (name) {
  238. case 'year':
  239. start = this.startInfo[name]
  240. end = this.endInfo[name]
  241. break
  242. case 'month':
  243. start = 1
  244. end = 12
  245. break
  246. case 'day':
  247. start = 1
  248. end = new Date(
  249. this.selectItem.year,
  250. this.selectItem.month,
  251. 0
  252. ).getDate()
  253. break
  254. case 'hour':
  255. start = 0
  256. end = 23
  257. break
  258. case 'minute':
  259. start = 0
  260. end = 59
  261. break
  262. case 'second':
  263. start = 0
  264. end = 59
  265. break
  266. }
  267. if (this.isSame(obj[name], 'startInfo')) {
  268. start = this.startInfo[name]
  269. }
  270. if (this.isSame(obj[name], 'endInfo')) {
  271. end = this.endInfo[name]
  272. }
  273. for (let i = start; i <= end; i++) {
  274. n++
  275. list.push({
  276. label: this.getLabel(
  277. i,
  278. name,
  279. format,
  280. this.getValueDate({ [name]: i }),
  281. n,
  282. index
  283. ),
  284. value: i
  285. })
  286. }
  287. if (this.filter && isFunction(this.filter)) {
  288. list = this.filter(name, list) || list
  289. }
  290. return list
  291. },
  292. validate (type) {
  293. let valid = true
  294. switch (type) {
  295. case 'date':
  296. valid = this.dayjs(this.selectDate).isValid()
  297. break
  298. case 'displayFormat':
  299. if (this[type]) {
  300. const arr = [
  301. 'YY',
  302. 'YYYY',
  303. 'M',
  304. 'MM',
  305. 'D',
  306. 'DD',
  307. 'H',
  308. 'HH',
  309. 'h',
  310. 'hh',
  311. 'm',
  312. 'mm',
  313. 's',
  314. 'ss'
  315. ]
  316. const formatArr = this.displayFormat.split('-')
  317. for (let i = 0; i < formatArr.length; i++) {
  318. const val = formatArr[i]
  319. const isIn = arr.includes(val)
  320. if (!isIn) {
  321. valid = false
  322. break
  323. }
  324. }
  325. } else {
  326. valid = false
  327. }
  328. break
  329. }
  330. return valid
  331. },
  332. toObject (val) {
  333. const d = this.dayjs(val)
  334. return {
  335. year: d.$y,
  336. month: d.$M + 1,
  337. day: d.$D,
  338. hour: d.$H,
  339. minute: d.$m,
  340. second: d.$s,
  341. timestamp: d.valueOf(),
  342. $d: d
  343. }
  344. }
  345. },
  346. watch: {
  347. value () {
  348. if (!this.isConfirmChange) {
  349. this.init('value')
  350. }
  351. },
  352. displayFormat () {
  353. this.init('displayFormat')
  354. },
  355. startDate () {
  356. this.init('startDate')
  357. },
  358. endDate () {
  359. this.init('endDate')
  360. },
  361. defaultTimeLimit () {
  362. this.init('defaultTimeLimit')
  363. },
  364. isShowChinese () {
  365. this.init('isShowChinese')
  366. },
  367. chConfig () {
  368. this.init('chConfig')
  369. }
  370. }
  371. }
  372. </script>
  373. <style lang="scss" scoped>
  374. @import "../style/picker-item.scss";
  375. </style>