input.js 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819
  1. import XEUtils from 'xe-utils/ctor'
  2. import GlobalConfig from '../../conf'
  3. import { UtilTools, DomTools, GlobalEvent } from '../../tools'
  4. const browse = DomTools.browse
  5. const wheelName = browse.firefox ? 'DOMMouseScroll' : 'mousewheel'
  6. const yearSize = 20
  7. const monthSize = 20
  8. function toStringTime (str) {
  9. if (str) {
  10. const rest = new Date()
  11. let h, m, s
  12. if (XEUtils.isDate(str)) {
  13. h = str.getHours()
  14. m = str.getMinutes()
  15. s = str.getSeconds()
  16. } else {
  17. str = XEUtils.toString(str)
  18. const parses = str.match(/^(\d{1,2})(:(\d{1,2}))?(:(\d{1,2}))?/)
  19. if (parses) {
  20. h = parses[1]
  21. m = parses[3]
  22. s = parses[5]
  23. }
  24. }
  25. rest.setHours(h || 0)
  26. rest.setMinutes(m || 0)
  27. rest.setSeconds(s || 0)
  28. return rest
  29. }
  30. return new Date('')
  31. }
  32. function toFloatValueFixed (inputValue, digitsValue) {
  33. if (/^-/.test('' + inputValue)) {
  34. return XEUtils.toFixed(XEUtils.ceil(inputValue, digitsValue), digitsValue)
  35. }
  36. return XEUtils.toFixed(XEUtils.floor(inputValue, digitsValue), digitsValue)
  37. }
  38. function renderDefaultInput (h, _vm) {
  39. const { inpAttrs, inpEvents, value } = _vm
  40. return h('input', {
  41. ref: 'input',
  42. class: 'vxe-input--inner',
  43. domProps: {
  44. value
  45. },
  46. attrs: inpAttrs,
  47. on: inpEvents
  48. })
  49. }
  50. function renderDateInput (h, _vm) {
  51. const { inpAttrs, inpEvents, inputValue } = _vm
  52. return h('input', {
  53. ref: 'input',
  54. class: 'vxe-input--inner',
  55. domProps: {
  56. value: inputValue
  57. },
  58. attrs: inpAttrs,
  59. on: inpEvents
  60. })
  61. }
  62. function renderDateLabel (h, _vm, item, label) {
  63. const festivalMethod = _vm.festivalMethod
  64. if (festivalMethod) {
  65. const festivalRest = festivalMethod({ $input: _vm, type: _vm.datePanelType, viewType: _vm.datePanelType, ...item })
  66. const festivalItem = festivalRest ? (XEUtils.isString(festivalRest) ? { label: festivalRest } : festivalRest) : {}
  67. const extraItem = festivalItem.extra ? (XEUtils.isString(festivalItem.extra) ? { label: festivalItem.extra } : festivalItem.extra) : null
  68. const labels = [
  69. h('span', {
  70. class: ['vxe-input--date-label', {
  71. 'is-notice': festivalItem.notice
  72. }]
  73. }, extraItem && extraItem.label ? [
  74. h('span', label),
  75. h('span', {
  76. class: ['vxe-input--date-label--extra', extraItem.important ? 'is-important' : '', extraItem.className],
  77. style: extraItem.style
  78. }, XEUtils.toString(extraItem.label))
  79. ] : label)
  80. ]
  81. const festivalLabel = festivalItem.label
  82. if (festivalLabel) {
  83. // 默认最多支持3个节日重叠
  84. const festivalLabels = XEUtils.toString(festivalLabel).split(',')
  85. labels.push(
  86. h('span', {
  87. class: ['vxe-input--date-festival', festivalItem.important ? 'is-important' : '', festivalItem.className],
  88. style: festivalItem.style
  89. }, [
  90. festivalLabels.length > 1 ? h('span', {
  91. class: ['vxe-input--date-festival--overlap', `overlap--${festivalLabels.length}`]
  92. }, festivalLabels.map(label => h('span', label.substring(0, 3)))) : h('span', {
  93. class: 'vxe-input--date-festival--label'
  94. }, festivalLabels[0].substring(0, 3))
  95. ])
  96. )
  97. }
  98. return labels
  99. }
  100. return label
  101. }
  102. function isDateDisabled (_vm, item) {
  103. const disabledMethod = _vm.disabledMethod || _vm.dateOpts.disabledMethod
  104. return disabledMethod && disabledMethod({ $input: _vm, type: _vm.datePanelType, viewType: _vm.datePanelType, date: item.date })
  105. }
  106. function renderDateDayTable (h, _vm) {
  107. const { datePanelType, dateValue, datePanelValue, dateHeaders, dayDatas } = _vm
  108. const matchFormat = 'yyyy-MM-dd'
  109. return [
  110. h('table', {
  111. class: `vxe-input--date-${datePanelType}-view`,
  112. attrs: {
  113. cellspacing: 0,
  114. cellpadding: 0,
  115. border: 0
  116. }
  117. }, [
  118. h('thead', [
  119. h('tr', dateHeaders.map(item => {
  120. return h('th', item.label)
  121. }))
  122. ]),
  123. h('tbody', dayDatas.map(rows => {
  124. return h('tr', rows.map(item => {
  125. return h('td', {
  126. class: {
  127. 'is--prev': item.isPrev,
  128. 'is--current': item.isCurrent,
  129. 'is--now': item.isNow,
  130. 'is--next': item.isNext,
  131. 'is--disabled': isDateDisabled(_vm, item),
  132. 'is--selected': XEUtils.isDateSame(dateValue, item.date, matchFormat),
  133. 'is--hover': XEUtils.isDateSame(datePanelValue, item.date, matchFormat)
  134. },
  135. on: {
  136. click: () => _vm.dateSelectEvent(item),
  137. mouseenter: () => _vm.dateMouseenterEvent(item)
  138. }
  139. }, renderDateLabel(h, _vm, item, item.label))
  140. }))
  141. }))
  142. ])
  143. ]
  144. }
  145. function renderDateWeekTable (h, _vm) {
  146. const { datePanelType, dateValue, datePanelValue, weekHeaders, weekDates } = _vm
  147. const matchFormat = 'yyyy-MM-dd'
  148. return [
  149. h('table', {
  150. class: `vxe-input--date-${datePanelType}-view`,
  151. attrs: {
  152. cellspacing: 0,
  153. cellpadding: 0,
  154. border: 0
  155. }
  156. }, [
  157. h('thead', [
  158. h('tr', weekHeaders.map(item => {
  159. return h('th', item.label)
  160. }))
  161. ]),
  162. h('tbody', weekDates.map(rows => {
  163. const isSelected = rows.some(item => XEUtils.isDateSame(dateValue, item.date, matchFormat))
  164. const isHover = rows.some(item => XEUtils.isDateSame(datePanelValue, item.date, matchFormat))
  165. return h('tr', rows.map(item => {
  166. return h('td', {
  167. class: {
  168. 'is--prev': item.isPrev,
  169. 'is--current': item.isCurrent,
  170. 'is--now': item.isNow,
  171. 'is--next': item.isNext,
  172. 'is--disabled': isDateDisabled(_vm, item),
  173. 'is--selected': isSelected,
  174. 'is--hover': isHover
  175. },
  176. on: {
  177. click: () => _vm.dateSelectEvent(item),
  178. mouseenter: () => _vm.dateMouseenterEvent(item)
  179. }
  180. }, renderDateLabel(h, _vm, item, item.label))
  181. }))
  182. }))
  183. ])
  184. ]
  185. }
  186. function renderDateMonthTable (h, _vm) {
  187. const { dateValue, datePanelType, monthDatas, datePanelValue } = _vm
  188. const matchFormat = 'yyyy-MM'
  189. return [
  190. h('table', {
  191. class: `vxe-input--date-${datePanelType}-view`,
  192. attrs: {
  193. cellspacing: 0,
  194. cellpadding: 0,
  195. border: 0
  196. }
  197. }, [
  198. h('tbody', monthDatas.map(rows => {
  199. return h('tr', rows.map(item => {
  200. return h('td', {
  201. class: {
  202. 'is--prev': item.isPrev,
  203. 'is--current': item.isCurrent,
  204. 'is--now': item.isNow,
  205. 'is--next': item.isNext,
  206. 'is--disabled': isDateDisabled(_vm, item),
  207. 'is--selected': XEUtils.isDateSame(dateValue, item.date, matchFormat),
  208. 'is--hover': XEUtils.isDateSame(datePanelValue, item.date, matchFormat)
  209. },
  210. on: {
  211. click: () => _vm.dateSelectEvent(item),
  212. mouseenter: () => _vm.dateMouseenterEvent(item)
  213. }
  214. }, renderDateLabel(h, _vm, item, GlobalConfig.i18n(`vxe.input.date.months.m${item.month}`)))
  215. }))
  216. }))
  217. ])
  218. ]
  219. }
  220. function renderDateYearTable (h, _vm) {
  221. const { dateValue, datePanelType, yearDatas, datePanelValue } = _vm
  222. const matchFormat = 'yyyy'
  223. return [
  224. h('table', {
  225. class: `vxe-input--date-${datePanelType}-view`,
  226. attrs: {
  227. cellspacing: 0,
  228. cellpadding: 0,
  229. border: 0
  230. }
  231. }, [
  232. h('tbody', yearDatas.map(rows => {
  233. return h('tr', rows.map(item => {
  234. return h('td', {
  235. class: {
  236. 'is--disabled': isDateDisabled(_vm, item),
  237. 'is--current': item.isCurrent,
  238. 'is--now': item.isNow,
  239. 'is--selected': XEUtils.isDateSame(dateValue, item.date, matchFormat),
  240. 'is--hover': XEUtils.isDateSame(datePanelValue, item.date, matchFormat)
  241. },
  242. on: {
  243. click: () => _vm.dateSelectEvent(item),
  244. mouseenter: () => _vm.dateMouseenterEvent(item)
  245. }
  246. }, renderDateLabel(h, _vm, item, item.year))
  247. }))
  248. }))
  249. ])
  250. ]
  251. }
  252. function renderDateTable (h, _vm) {
  253. const { datePanelType } = _vm
  254. switch (datePanelType) {
  255. case 'week' :
  256. return renderDateWeekTable(h, _vm)
  257. case 'month' :
  258. return renderDateMonthTable(h, _vm)
  259. case 'year' :
  260. return renderDateYearTable(h, _vm)
  261. }
  262. return renderDateDayTable(h, _vm)
  263. }
  264. function renderDatePanel (h, _vm) {
  265. const { datePanelType, selectDatePanelLabel, isDisabledPrevDateBtn, isDisabledNextDateBtn } = _vm
  266. return [
  267. h('div', {
  268. class: 'vxe-input--date-picker-header'
  269. }, [
  270. h('div', {
  271. class: 'vxe-input--date-picker-type-wrapper'
  272. }, [
  273. datePanelType === 'year' ? h('span', {
  274. class: 'vxe-input--date-picker-label'
  275. }, selectDatePanelLabel) : h('span', {
  276. class: 'vxe-input--date-picker-btn',
  277. on: {
  278. click: _vm.dateToggleTypeEvent
  279. }
  280. }, selectDatePanelLabel)
  281. ]),
  282. h('div', {
  283. class: 'vxe-input--date-picker-btn-wrapper'
  284. }, [
  285. h('span', {
  286. class: ['vxe-input--date-picker-btn vxe-input--date-picker-prev-btn', {
  287. 'is--disabled': isDisabledPrevDateBtn
  288. }],
  289. on: {
  290. click: _vm.datePrevEvent
  291. }
  292. }, [
  293. h('i', {
  294. class: 'vxe-icon--caret-left'
  295. })
  296. ]),
  297. h('span', {
  298. class: 'vxe-input--date-picker-btn vxe-input--date-picker-current-btn',
  299. on: {
  300. click: _vm.dateTodayMonthEvent
  301. }
  302. }, [
  303. h('i', {
  304. class: 'vxe-icon--dot'
  305. })
  306. ]),
  307. h('span', {
  308. class: ['vxe-input--date-picker-btn vxe-input--date-picker-next-btn', {
  309. 'is--disabled': isDisabledNextDateBtn
  310. }],
  311. on: {
  312. click: _vm.dateNextEvent
  313. }
  314. }, [
  315. h('i', {
  316. class: 'vxe-icon--caret-right'
  317. })
  318. ])
  319. ])
  320. ]),
  321. h('div', {
  322. class: 'vxe-input--date-picker-body'
  323. }, renderDateTable(h, _vm))
  324. ]
  325. }
  326. function renderTimePanel (h, _vm) {
  327. const { dateTimeLabel, datetimePanelValue, hourList, minuteList, secondList } = _vm
  328. return [
  329. h('div', {
  330. class: 'vxe-input--time-picker-header'
  331. }, [
  332. h('span', {
  333. class: 'vxe-input--time-picker-title'
  334. }, dateTimeLabel),
  335. h('button', {
  336. class: 'vxe-input--time-picker-confirm',
  337. attrs: {
  338. type: 'button'
  339. },
  340. on: {
  341. click: _vm.dateConfirmEvent
  342. }
  343. }, GlobalConfig.i18n('vxe.button.confirm'))
  344. ]),
  345. h('div', {
  346. ref: 'timeBody',
  347. class: 'vxe-input--time-picker-body'
  348. }, [
  349. h('ul', {
  350. class: 'vxe-input--time-picker-hour-list'
  351. }, hourList.map((item, index) => {
  352. return h('li', {
  353. key: index,
  354. class: {
  355. 'is--selected': datetimePanelValue && datetimePanelValue.getHours() === item.value
  356. },
  357. on: {
  358. click: (evnt) => _vm.dateHourEvent(evnt, item)
  359. }
  360. }, item.label)
  361. })),
  362. h('ul', {
  363. class: 'vxe-input--time-picker-minute-list'
  364. }, minuteList.map((item, index) => {
  365. return h('li', {
  366. key: index,
  367. class: {
  368. 'is--selected': datetimePanelValue && datetimePanelValue.getMinutes() === item.value
  369. },
  370. on: {
  371. click: (evnt) => _vm.dateMinuteEvent(evnt, item)
  372. }
  373. }, item.label)
  374. })),
  375. h('ul', {
  376. class: 'vxe-input--time-picker-second-list'
  377. }, secondList.map((item, index) => {
  378. return h('li', {
  379. key: index,
  380. class: {
  381. 'is--selected': datetimePanelValue && datetimePanelValue.getSeconds() === item.value
  382. },
  383. on: {
  384. click: (evnt) => _vm.dateSecondEvent(evnt, item)
  385. }
  386. }, item.label)
  387. }))
  388. ])
  389. ]
  390. }
  391. function renderPanel (h, _vm) {
  392. const { type, vSize, isDatePicker, transfer, animatVisible, visiblePanel, panelPlacement, panelStyle } = _vm
  393. const renders = []
  394. if (isDatePicker) {
  395. if (type === 'datetime') {
  396. renders.push(
  397. h('div', {
  398. class: 'vxe-input--panel-layout-wrapper'
  399. }, [
  400. h('div', {
  401. class: 'vxe-input--panel-left-wrapper'
  402. }, renderDatePanel(h, _vm)),
  403. h('div', {
  404. class: 'vxe-input--panel-right-wrapper'
  405. }, renderTimePanel(h, _vm))
  406. ])
  407. )
  408. } else if (type === 'time') {
  409. renders.push(
  410. h('div', {
  411. class: 'vxe-input--panel-wrapper'
  412. }, renderTimePanel(h, _vm))
  413. )
  414. } else {
  415. renders.push(
  416. h('div', {
  417. class: 'vxe-input--panel-wrapper'
  418. }, renderDatePanel(h, _vm))
  419. )
  420. }
  421. return h('div', {
  422. ref: 'panel',
  423. class: ['vxe-table--ignore-clear vxe-input--panel', `type--${type}`, {
  424. [`size--${vSize}`]: vSize,
  425. 'is--transfer': transfer,
  426. 'animat--leave': animatVisible,
  427. 'animat--enter': visiblePanel
  428. }],
  429. attrs: {
  430. 'data-placement': panelPlacement
  431. },
  432. style: panelStyle
  433. }, renders)
  434. }
  435. return null
  436. }
  437. function renderNumberIcon (h, _vm) {
  438. return h('span', {
  439. class: 'vxe-input--number-suffix'
  440. }, [
  441. h('span', {
  442. class: 'vxe-input--number-prev is--prev',
  443. on: {
  444. mousedown: _vm.numberMousedownEvent,
  445. mouseup: _vm.numberStopDown,
  446. mouseleave: _vm.numberStopDown
  447. }
  448. }, [
  449. h('i', {
  450. class: ['vxe-input--number-prev-icon', GlobalConfig.icon.INPUT_PREV_NUM]
  451. })
  452. ]),
  453. h('span', {
  454. class: 'vxe-input--number-next is--next',
  455. on: {
  456. mousedown: _vm.numberMousedownEvent,
  457. mouseup: _vm.numberStopDown,
  458. mouseleave: _vm.numberStopDown
  459. }
  460. }, [
  461. h('i', {
  462. class: ['vxe-input--number-next-icon', GlobalConfig.icon.INPUT_NEXT_NUM]
  463. })
  464. ])
  465. ])
  466. }
  467. function renderDatePickerIcon (h, _vm) {
  468. return h('span', {
  469. class: 'vxe-input--date-picker-suffix',
  470. on: {
  471. click: _vm.datePickerOpenEvent
  472. }
  473. }, [
  474. h('i', {
  475. class: ['vxe-input--date-picker-icon', GlobalConfig.icon.INPUT_DATE]
  476. })
  477. ])
  478. }
  479. function renderSearchIcon (h, _vm) {
  480. return h('span', {
  481. class: 'vxe-input--search-suffix',
  482. on: {
  483. click: _vm.searchEvent
  484. }
  485. }, [
  486. h('i', {
  487. class: ['vxe-input--search-icon', GlobalConfig.icon.INPUT_SEARCH]
  488. })
  489. ])
  490. }
  491. function renderPasswordIcon (h, _vm) {
  492. const { showPwd } = _vm
  493. return h('span', {
  494. class: 'vxe-input--password-suffix',
  495. on: {
  496. click: _vm.passwordToggleEvent
  497. }
  498. }, [
  499. h('i', {
  500. class: ['vxe-input--password-icon', showPwd ? GlobalConfig.icon.INPUT_SHOW_PWD : GlobalConfig.icon.INPUT_PWD]
  501. })
  502. ])
  503. }
  504. function rendePrefixIcon (h, _vm) {
  505. const { $scopedSlots, prefixIcon } = _vm
  506. const icons = []
  507. if ($scopedSlots.prefix) {
  508. icons.push(
  509. h('span', {
  510. class: 'vxe-input--prefix-icon'
  511. }, $scopedSlots.prefix.call(this, {}, h))
  512. )
  513. } else if (prefixIcon) {
  514. icons.push(
  515. h('i', {
  516. class: ['vxe-input--prefix-icon', prefixIcon]
  517. })
  518. )
  519. }
  520. return icons.length ? h('span', {
  521. class: 'vxe-input--prefix',
  522. on: {
  523. click: _vm.clickPrefixEvent
  524. }
  525. }, icons) : null
  526. }
  527. function renderSuffixIcon (h, _vm) {
  528. const { $scopedSlots, value, isClearable, disabled, suffixIcon } = _vm
  529. const icons = []
  530. if ($scopedSlots.suffix) {
  531. icons.push(
  532. h('span', {
  533. class: 'vxe-input--suffix-icon'
  534. }, $scopedSlots.suffix.call(this, {}, h))
  535. )
  536. } else if (suffixIcon) {
  537. icons.push(
  538. h('i', {
  539. class: ['vxe-input--suffix-icon', suffixIcon]
  540. })
  541. )
  542. }
  543. if (isClearable) {
  544. icons.push(
  545. h('i', {
  546. class: ['vxe-input--clear-icon', GlobalConfig.icon.INPUT_CLEAR]
  547. })
  548. )
  549. }
  550. return icons.length ? h('span', {
  551. class: ['vxe-input--suffix', {
  552. 'is--clear': isClearable && !disabled && !(value === '' || XEUtils.eqNull(value))
  553. }],
  554. on: {
  555. click: _vm.clickSuffixEvent
  556. }
  557. }, icons) : null
  558. }
  559. function renderExtraSuffixIcon (h, _vm) {
  560. const { controls, isPassword, isNumber, isDatePicker, isSearch } = _vm
  561. let icons
  562. if (isPassword) {
  563. icons = renderPasswordIcon(h, _vm)
  564. } else if (isNumber) {
  565. if (controls) {
  566. icons = renderNumberIcon(h, _vm)
  567. }
  568. } else if (isDatePicker) {
  569. icons = renderDatePickerIcon(h, _vm)
  570. } else if (isSearch) {
  571. icons = renderSearchIcon(h, _vm)
  572. }
  573. return icons ? h('span', {
  574. class: 'vxe-input--extra-suffix'
  575. }, [icons]) : null
  576. }
  577. export default {
  578. name: 'VxeInput',
  579. props: {
  580. value: [String, Number, Date],
  581. name: String,
  582. type: { type: String, default: 'text' },
  583. clearable: { type: Boolean, default: () => GlobalConfig.input.clearable },
  584. readonly: Boolean,
  585. disabled: Boolean,
  586. placeholder: String,
  587. maxlength: [String, Number],
  588. autocomplete: { type: String, default: 'off' },
  589. align: String,
  590. form: String,
  591. size: { type: String, default: () => GlobalConfig.input.size || GlobalConfig.size },
  592. // number、integer、float
  593. min: { type: [String, Number], default: null },
  594. max: { type: [String, Number], default: null },
  595. step: [String, Number],
  596. // number、integer、float、password
  597. controls: { type: Boolean, default: () => GlobalConfig.input.controls },
  598. // float
  599. digits: { type: [String, Number], default: () => GlobalConfig.input.digits },
  600. // date、week、month、year
  601. dateConfig: Object,
  602. minDate: { type: [String, Number, Date], default: () => GlobalConfig.input.minDate },
  603. maxDate: { type: [String, Number, Date], default: () => GlobalConfig.input.maxDate },
  604. // 已废弃 startWeek,被 startDay 替换
  605. startWeek: Number,
  606. startDay: { type: [String, Number], default: () => GlobalConfig.input.startDay },
  607. labelFormat: { type: String, default: () => GlobalConfig.input.labelFormat },
  608. parseFormat: { type: String, default: () => GlobalConfig.input.parseFormat },
  609. valueFormat: { type: String, default: () => GlobalConfig.input.valueFormat },
  610. editable: { type: Boolean, default: true },
  611. festivalMethod: { type: Function, default: () => GlobalConfig.input.festivalMethod },
  612. disabledMethod: { type: Function, default: () => GlobalConfig.input.disabledMethod },
  613. prefixIcon: String,
  614. suffixIcon: String,
  615. placement: String,
  616. transfer: { type: Boolean, default: () => GlobalConfig.input.transfer }
  617. },
  618. data () {
  619. return {
  620. panelIndex: 0,
  621. showPwd: false,
  622. visiblePanel: false,
  623. animatVisible: false,
  624. panelStyle: null,
  625. panelPlacement: null,
  626. isActivated: false,
  627. inputValue: '',
  628. datetimePanelValue: null,
  629. datePanelValue: null,
  630. datePanelLabel: '',
  631. datePanelType: 'day',
  632. selectMonth: null,
  633. currentDate: null
  634. }
  635. },
  636. computed: {
  637. vSize () {
  638. return this.size || this.$parent.size || this.$parent.vSize
  639. },
  640. isNumber () {
  641. return ['number', 'integer', 'float'].indexOf(this.type) > -1
  642. },
  643. isDatePicker () {
  644. return this.hasTime || ['date', 'week', 'month', 'year'].indexOf(this.type) > -1
  645. },
  646. hasTime () {
  647. const { type } = this
  648. return type === 'time' || type === 'datetime'
  649. },
  650. isPassword () {
  651. return this.type === 'password'
  652. },
  653. isSearch () {
  654. return this.type === 'search'
  655. },
  656. stepValue () {
  657. const { type, step } = this
  658. if (type === 'integer') {
  659. return XEUtils.toInteger(step) || 1
  660. } else if (type === 'float') {
  661. return XEUtils.toNumber(step) || (1 / Math.pow(10, this.digitsValue))
  662. }
  663. return XEUtils.toNumber(step) || 1
  664. },
  665. digitsValue () {
  666. return XEUtils.toInteger(this.digits) || 1
  667. },
  668. isClearable () {
  669. return this.clearable && (this.isPassword || this.isNumber || this.isDatePicker || this.type === 'text' || this.type === 'search')
  670. },
  671. isDisabledPrevDateBtn () {
  672. const { selectMonth, dateMinTime } = this
  673. if (selectMonth) {
  674. return selectMonth <= dateMinTime
  675. }
  676. return false
  677. },
  678. isDisabledNextDateBtn () {
  679. const { selectMonth, dateMaxTime } = this
  680. if (selectMonth) {
  681. return selectMonth >= dateMaxTime
  682. }
  683. return false
  684. },
  685. dateMinTime () {
  686. return this.minDate ? XEUtils.toStringDate(this.minDate) : null
  687. },
  688. dateMaxTime () {
  689. return this.maxDate ? XEUtils.toStringDate(this.maxDate) : null
  690. },
  691. dateValue () {
  692. const { value, isDatePicker, type, dateValueFormat } = this
  693. let val = null
  694. if (value && isDatePicker) {
  695. let date
  696. if (type === 'time') {
  697. date = toStringTime(value)
  698. } else {
  699. date = XEUtils.toStringDate(value, dateValueFormat)
  700. }
  701. if (XEUtils.isValidDate(date)) {
  702. val = date
  703. }
  704. }
  705. return val
  706. },
  707. dateTimeLabel () {
  708. const { datetimePanelValue } = this
  709. if (datetimePanelValue) {
  710. return XEUtils.toDateString(datetimePanelValue, 'HH:mm:ss')
  711. }
  712. return ''
  713. },
  714. hmsTime () {
  715. const { dateValue } = this
  716. return dateValue && (this.hasTime) ? (dateValue.getHours() * 3600 + dateValue.getMinutes() * 60 + dateValue.getSeconds()) * 1000 : 0
  717. },
  718. dateLabelFormat () {
  719. if (this.isDatePicker) {
  720. return this.labelFormat || this.dateOpts.labelFormat || GlobalConfig.i18n(`vxe.input.date.labelFormat.${this.type}`)
  721. }
  722. return null
  723. },
  724. dateValueFormat () {
  725. const { type } = this
  726. return type === 'time' ? 'HH:mm:ss' : (this.valueFormat || this.dateOpts.valueFormat || (type === 'datetime' ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd'))
  727. },
  728. selectDatePanelLabel () {
  729. if (this.isDatePicker) {
  730. const { datePanelType, selectMonth, yearList } = this
  731. let year = ''
  732. let month
  733. if (selectMonth) {
  734. year = selectMonth.getFullYear()
  735. month = selectMonth.getMonth() + 1
  736. }
  737. if (datePanelType === 'month') {
  738. return GlobalConfig.i18n('vxe.input.date.monthLabel', [year])
  739. } else if (datePanelType === 'year') {
  740. return yearList.length ? `${yearList[0].year} - ${yearList[yearList.length - 1].year}` : ''
  741. }
  742. return GlobalConfig.i18n('vxe.input.date.dayLabel', [year, month ? GlobalConfig.i18n(`vxe.input.date.m${month}`) : '-'])
  743. }
  744. return ''
  745. },
  746. weekDatas () {
  747. const weeks = []
  748. if (this.isDatePicker) {
  749. const { startDay, startWeek } = this
  750. let sWeek = XEUtils.toNumber(XEUtils.isNumber(startDay) || XEUtils.isString(startDay) ? startDay : (XEUtils.isNumber(startWeek) ? startWeek : this.dateOpts.startWeek))
  751. weeks.push(sWeek)
  752. for (let index = 0; index < 6; index++) {
  753. if (sWeek >= 6) {
  754. sWeek = 0
  755. } else {
  756. sWeek++
  757. }
  758. weeks.push(sWeek)
  759. }
  760. }
  761. return weeks
  762. },
  763. dateHeaders () {
  764. if (this.isDatePicker) {
  765. return this.weekDatas.map(day => {
  766. return {
  767. value: day,
  768. label: GlobalConfig.i18n(`vxe.input.date.weeks.w${day}`)
  769. }
  770. })
  771. }
  772. return []
  773. },
  774. weekHeaders () {
  775. if (this.isDatePicker) {
  776. return [{ label: GlobalConfig.i18n('vxe.input.date.weeks.w') }].concat(this.dateHeaders)
  777. }
  778. return []
  779. },
  780. yearList () {
  781. const { selectMonth, currentDate } = this
  782. const months = []
  783. if (selectMonth && currentDate) {
  784. const currFullYear = currentDate.getFullYear()
  785. const startYear = new Date(('' + selectMonth.getFullYear()).replace(/\d{1}$/, '0'), 0, 1)
  786. for (let index = -10; index < yearSize - 10; index++) {
  787. const date = XEUtils.getWhatYear(startYear, index, 'first')
  788. const itemFullYear = date.getFullYear()
  789. months.push({
  790. date,
  791. isCurrent: true,
  792. isNow: currFullYear === itemFullYear,
  793. year: itemFullYear
  794. })
  795. }
  796. }
  797. return months
  798. },
  799. yearDatas () {
  800. return XEUtils.chunk(this.yearList, 4)
  801. },
  802. monthList () {
  803. const { selectMonth, currentDate } = this
  804. const months = []
  805. if (selectMonth && currentDate) {
  806. const currFullYear = currentDate.getFullYear()
  807. const currMonth = currentDate.getMonth()
  808. const selFullYear = XEUtils.getWhatYear(selectMonth, 0, 'first').getFullYear()
  809. for (let index = -4; index < monthSize - 4; index++) {
  810. const date = XEUtils.getWhatYear(selectMonth, 0, index)
  811. const itemFullYear = date.getFullYear()
  812. const itemMonth = date.getMonth()
  813. const isPrev = itemFullYear < selFullYear
  814. months.push({
  815. date,
  816. isPrev,
  817. isCurrent: itemFullYear === selFullYear,
  818. isNow: itemFullYear === currFullYear && itemMonth === currMonth,
  819. isNext: !isPrev && itemFullYear > selFullYear,
  820. month: itemMonth
  821. })
  822. }
  823. }
  824. return months
  825. },
  826. monthDatas () {
  827. return XEUtils.chunk(this.monthList, 4)
  828. },
  829. dayList () {
  830. const { weekDatas, selectMonth, currentDate, hmsTime } = this
  831. const days = []
  832. if (selectMonth && currentDate) {
  833. const currFullYear = currentDate.getFullYear()
  834. const currMonth = currentDate.getMonth()
  835. const currDate = currentDate.getDate()
  836. const selFullYear = selectMonth.getFullYear()
  837. const selMonth = selectMonth.getMonth()
  838. const selDay = selectMonth.getDay()
  839. const prevOffsetDate = -weekDatas.indexOf(selDay)
  840. const startDate = new Date(XEUtils.getWhatDay(selectMonth, prevOffsetDate).getTime() + hmsTime)
  841. for (let index = 0; index < 42; index++) {
  842. const date = XEUtils.getWhatDay(startDate, index)
  843. const itemFullYear = date.getFullYear()
  844. const itemMonth = date.getMonth()
  845. const itemDate = date.getDate()
  846. const isPrev = date < selectMonth
  847. days.push({
  848. date,
  849. isPrev,
  850. isCurrent: itemFullYear === selFullYear && itemMonth === selMonth,
  851. isNow: itemFullYear === currFullYear && itemMonth === currMonth && itemDate === currDate,
  852. isNext: !isPrev && selMonth !== itemMonth,
  853. label: itemDate
  854. })
  855. }
  856. }
  857. return days
  858. },
  859. dayDatas () {
  860. return XEUtils.chunk(this.dayList, 7)
  861. },
  862. weekDates () {
  863. return this.dayDatas.map(list => {
  864. const firstItem = list[0]
  865. const item = {
  866. date: firstItem.date,
  867. isWeekNumber: true,
  868. isPrev: false,
  869. isCurrent: false,
  870. isNow: false,
  871. isNext: false,
  872. label: XEUtils.getYearWeek(firstItem.date)
  873. }
  874. return [item].concat(list)
  875. })
  876. },
  877. dateOpts () {
  878. return Object.assign({}, this.dateConfig, GlobalConfig.input.dateConfig)
  879. },
  880. hourList () {
  881. const list = []
  882. if (this.hasTime) {
  883. for (let index = 0; index < 24; index++) {
  884. list.push({
  885. value: index,
  886. label: ('' + index).padStart(2, 0)
  887. })
  888. }
  889. }
  890. return list
  891. },
  892. minuteList () {
  893. const list = []
  894. if (this.hasTime) {
  895. for (let index = 0; index < 60; index++) {
  896. list.push({
  897. value: index,
  898. label: ('' + index).padStart(2, 0)
  899. })
  900. }
  901. }
  902. return list
  903. },
  904. secondList () {
  905. return this.minuteList
  906. },
  907. inpAttrs () {
  908. const { isDatePicker, isNumber, isPassword, type, name, placeholder, readonly, disabled, maxlength, form, autocomplete, showPwd, editable } = this
  909. let inputType = type
  910. if (isDatePicker || isNumber || (isPassword && showPwd) || type === 'number') {
  911. inputType = 'text'
  912. }
  913. const attrs = {
  914. name,
  915. form,
  916. type: inputType,
  917. placeholder,
  918. maxlength: isNumber && !XEUtils.toNumber(maxlength) ? 16 : maxlength, // 数值最大长度限制 16 位,包含小数
  919. readonly: readonly || type === 'week' || !editable || this.dateOpts.editable === false,
  920. disabled,
  921. autocomplete
  922. }
  923. if (placeholder) {
  924. attrs.placeholder = UtilTools.getFuncText(placeholder)
  925. }
  926. return attrs
  927. },
  928. inpEvents () {
  929. const evnts = {}
  930. XEUtils.each(this.$listeners, (cb, name) => {
  931. if (['change', 'clear', 'prefix-click', 'suffix-click'].indexOf(name) === -1) {
  932. evnts[name] = this.triggerEvent
  933. }
  934. })
  935. if (this.isNumber) {
  936. evnts.keydown = this.keydownEvent
  937. evnts[wheelName] = this.mousewheelEvent
  938. } else if (this.isDatePicker) {
  939. evnts.click = this.clickEvent
  940. }
  941. evnts.input = this.inputEvent
  942. evnts.focus = this.focusEvent
  943. evnts.blur = this.blurEvent
  944. return evnts
  945. }
  946. },
  947. watch: {
  948. value () {
  949. this.changeValue()
  950. },
  951. dateLabelFormat () {
  952. this.dateParseValue(this.datePanelValue)
  953. this.inputValue = this.datePanelLabel
  954. }
  955. },
  956. created () {
  957. this.initValue()
  958. GlobalEvent.on(this, 'mousewheel', this.handleGlobalMousewheelEvent)
  959. GlobalEvent.on(this, 'mousedown', this.handleGlobalMousedownEvent)
  960. GlobalEvent.on(this, 'keydown', this.handleGlobalKeydownEvent)
  961. GlobalEvent.on(this, 'blur', this.handleGlobalBlurEvent)
  962. },
  963. mounted () {
  964. if (this.dateConfig) {
  965. UtilTools.warn('vxe.error.removeProp', ['date-config'])
  966. }
  967. if (this.isDatePicker) {
  968. if (this.transfer) {
  969. document.body.appendChild(this.$refs.panel)
  970. }
  971. }
  972. },
  973. beforeDestroy () {
  974. const panelElem = this.$refs.panel
  975. if (panelElem && panelElem.parentNode) {
  976. panelElem.parentNode.removeChild(panelElem)
  977. }
  978. },
  979. destroyed () {
  980. this.numberStopDown()
  981. GlobalEvent.off(this, 'mousewheel')
  982. GlobalEvent.off(this, 'mousedown')
  983. GlobalEvent.off(this, 'keydown')
  984. GlobalEvent.off(this, 'blur')
  985. },
  986. render (h) {
  987. const { controls, isDatePicker, visiblePanel, isActivated, vSize, type, align, readonly, disabled } = this
  988. const childs = []
  989. const prefix = rendePrefixIcon(h, this)
  990. const suffix = renderSuffixIcon(h, this)
  991. // 前缀图标
  992. if (prefix) {
  993. childs.push(prefix)
  994. }
  995. // 输入框
  996. childs.push(isDatePicker ? renderDateInput(h, this) : renderDefaultInput(h, this))
  997. // 后缀图标
  998. if (suffix) {
  999. childs.push(suffix)
  1000. }
  1001. // 特殊功能图标
  1002. childs.push(renderExtraSuffixIcon(h, this))
  1003. // 面板容器
  1004. if (isDatePicker) {
  1005. childs.push(renderPanel(h, this))
  1006. }
  1007. return h('div', {
  1008. class: ['vxe-input', `type--${type}`, {
  1009. [`size--${vSize}`]: vSize,
  1010. [`is--${align}`]: align,
  1011. 'is--controls': controls,
  1012. 'is--prefix': !!prefix,
  1013. 'is--suffix': !!suffix,
  1014. 'is--readonly': readonly,
  1015. 'is--visivle': visiblePanel,
  1016. 'is--disabled': disabled,
  1017. 'is--active': isActivated
  1018. }]
  1019. }, childs)
  1020. },
  1021. methods: {
  1022. focus () {
  1023. this.isActivated = true
  1024. this.$refs.input.focus()
  1025. return this.$nextTick()
  1026. },
  1027. blur () {
  1028. this.$refs.input.blur()
  1029. this.isActivated = false
  1030. return this.$nextTick()
  1031. },
  1032. triggerEvent (evnt) {
  1033. const { $refs, value } = this
  1034. this.$emit(evnt.type, { $panel: $refs.panel, value, $event: evnt }, evnt)
  1035. },
  1036. emitUpdate (value, evnt) {
  1037. this.$emit('input', value)
  1038. if (XEUtils.toString(this.value) !== value) {
  1039. this.$emit('change', { value, $event: evnt })
  1040. }
  1041. },
  1042. inputEvent (evnt) {
  1043. const { isDatePicker } = this
  1044. const value = evnt.target.value
  1045. this.inputValue = value
  1046. if (!isDatePicker) {
  1047. this.emitUpdate(value, evnt)
  1048. }
  1049. },
  1050. focusEvent (evnt) {
  1051. this.isActivated = true
  1052. this.triggerEvent(evnt)
  1053. },
  1054. blurEvent (evnt) {
  1055. this.afterCheckValue()
  1056. if (!this.visiblePanel) {
  1057. this.isActivated = false
  1058. }
  1059. this.triggerEvent(evnt)
  1060. },
  1061. keydownEvent (evnt) {
  1062. if (this.isNumber) {
  1063. const isCtrlKey = evnt.ctrlKey
  1064. const isShiftKey = evnt.shiftKey
  1065. const isAltKey = evnt.altKey
  1066. const keyCode = evnt.keyCode
  1067. if (!isCtrlKey && !isShiftKey && !isAltKey && (keyCode === 32 || (keyCode >= 65 && keyCode <= 90) || (keyCode >= 186 && keyCode <= 188) || keyCode >= 191)) {
  1068. evnt.preventDefault()
  1069. }
  1070. this.numberKeydownEvent(evnt)
  1071. }
  1072. this.triggerEvent(evnt)
  1073. },
  1074. mousewheelEvent (evnt) {
  1075. if (this.isNumber && this.controls) {
  1076. if (this.isActivated) {
  1077. const delta = -evnt.wheelDelta || evnt.detail
  1078. if (delta > 0) {
  1079. this.numberNextEvent(evnt)
  1080. } else if (delta < 0) {
  1081. this.numberPrevEvent(evnt)
  1082. }
  1083. evnt.preventDefault()
  1084. }
  1085. }
  1086. },
  1087. clickEvent (evnt) {
  1088. const { isDatePicker } = this
  1089. if (isDatePicker) {
  1090. this.datePickerOpenEvent(evnt)
  1091. }
  1092. this.triggerEvent(evnt)
  1093. },
  1094. clickPrefixEvent (evnt) {
  1095. const { $refs, disabled, value } = this
  1096. if (!disabled) {
  1097. this.$emit('prefix-click', { $panel: $refs.panel, value, $event: evnt }, evnt)
  1098. }
  1099. },
  1100. clickSuffixEvent (evnt) {
  1101. const { $refs, disabled, value } = this
  1102. if (!disabled) {
  1103. if (DomTools.hasClass(evnt.currentTarget, 'is--clear')) {
  1104. this.emitUpdate('', evnt)
  1105. this.clearValueEvent(evnt, '')
  1106. } else {
  1107. this.$emit('suffix-click', { $panel: $refs.panel, value, $event: evnt }, evnt)
  1108. }
  1109. }
  1110. },
  1111. clearValueEvent (evnt, value) {
  1112. const { $refs, type, isNumber } = this
  1113. if (this.isDatePicker) {
  1114. this.hidePanel()
  1115. }
  1116. if (isNumber || ['text', 'password'].indexOf(type) > -1) {
  1117. this.focus()
  1118. }
  1119. this.$emit('clear', { $panel: $refs.panel, value, $event: evnt }, evnt)
  1120. },
  1121. /**
  1122. * 检查初始值
  1123. */
  1124. initValue () {
  1125. const { type, isDatePicker, value, digitsValue } = this
  1126. if (isDatePicker) {
  1127. this.changeValue()
  1128. } else if (type === 'float') {
  1129. if (value) {
  1130. const validValue = toFloatValueFixed(value, digitsValue)
  1131. if (value !== validValue) {
  1132. this.emitUpdate(validValue, { type: 'init' })
  1133. }
  1134. }
  1135. }
  1136. },
  1137. /**
  1138. * 值变化时处理
  1139. */
  1140. changeValue () {
  1141. if (this.isDatePicker) {
  1142. this.dateParseValue(this.value)
  1143. this.inputValue = this.datePanelLabel
  1144. }
  1145. },
  1146. afterCheckValue () {
  1147. const { type, inpAttrs, value, inputValue, isDatePicker, isNumber, datetimePanelValue, dateLabelFormat, min, max, digitsValue } = this
  1148. if (!inpAttrs.readonly) {
  1149. if (isNumber) {
  1150. if (value) {
  1151. let inpVal = type === 'integer' ? XEUtils.toInteger(value) : XEUtils.toNumber(value)
  1152. if (!this.vaildMinNum(inpVal)) {
  1153. inpVal = min
  1154. } else if (!this.vaildMaxNum(inpVal)) {
  1155. inpVal = max
  1156. }
  1157. this.emitUpdate(type === 'float' ? toFloatValueFixed(inpVal, digitsValue) : XEUtils.toString(inpVal), { type: 'check' })
  1158. }
  1159. } else if (isDatePicker) {
  1160. let inpVal = inputValue
  1161. if (inpVal) {
  1162. if (type === 'time') {
  1163. inpVal = toStringTime(inpVal, dateLabelFormat)
  1164. } else {
  1165. inpVal = XEUtils.toStringDate(inpVal, dateLabelFormat)
  1166. }
  1167. if (XEUtils.isValidDate(inpVal)) {
  1168. if (type === 'time') {
  1169. inpVal = XEUtils.toDateString(inpVal, dateLabelFormat)
  1170. if (value !== inpVal) {
  1171. this.emitUpdate(inpVal, { type: 'check' })
  1172. }
  1173. this.inputValue = inpVal
  1174. } else {
  1175. if (!XEUtils.isDateSame(value, inpVal, dateLabelFormat)) {
  1176. if (type === 'datetime') {
  1177. datetimePanelValue.setHours(inpVal.getHours())
  1178. datetimePanelValue.setMinutes(inpVal.getMinutes())
  1179. datetimePanelValue.setSeconds(inpVal.getSeconds())
  1180. }
  1181. this.dateChange(inpVal)
  1182. } else {
  1183. this.inputValue = XEUtils.toDateString(value, dateLabelFormat)
  1184. }
  1185. }
  1186. } else {
  1187. this.dateRevert()
  1188. }
  1189. } else {
  1190. this.emitUpdate('', { type: 'check' })
  1191. }
  1192. }
  1193. }
  1194. },
  1195. // 密码
  1196. passwordToggleEvent (evnt) {
  1197. const { disabled, readonly, showPwd } = this
  1198. if (!disabled && !readonly) {
  1199. this.showPwd = !showPwd
  1200. }
  1201. this.$emit('toggle-visible', { visible: this.showPwd, $event: evnt })
  1202. },
  1203. // 密码
  1204. // 搜索
  1205. searchEvent (evnt) {
  1206. this.$emit('search-click', { $event: evnt })
  1207. },
  1208. // 搜索
  1209. // 数值
  1210. vaildMinNum (num) {
  1211. return this.min === null || num >= XEUtils.toNumber(this.min)
  1212. },
  1213. vaildMaxNum (num) {
  1214. return this.max === null || num <= XEUtils.toNumber(this.max)
  1215. },
  1216. numberStopDown () {
  1217. clearTimeout(this.downbumTimeout)
  1218. },
  1219. numberDownPrevEvent (evnt) {
  1220. this.downbumTimeout = setTimeout(() => {
  1221. this.numberPrevEvent(evnt)
  1222. this.numberDownPrevEvent(evnt)
  1223. }, 60)
  1224. },
  1225. numberDownNextEvent (evnt) {
  1226. this.downbumTimeout = setTimeout(() => {
  1227. this.numberNextEvent(evnt)
  1228. this.numberDownNextEvent(evnt)
  1229. }, 60)
  1230. },
  1231. numberKeydownEvent (evnt) {
  1232. const { keyCode } = evnt
  1233. const isUpArrow = keyCode === 38
  1234. const isDwArrow = keyCode === 40
  1235. if (isUpArrow || isDwArrow) {
  1236. evnt.preventDefault()
  1237. if (isUpArrow) {
  1238. this.numberPrevEvent(evnt)
  1239. } else {
  1240. this.numberNextEvent(evnt)
  1241. }
  1242. }
  1243. },
  1244. numberMousedownEvent (evnt) {
  1245. this.numberStopDown()
  1246. if (evnt.button === 0) {
  1247. const isPrevNumber = DomTools.hasClass(evnt.currentTarget, 'is--prev')
  1248. if (isPrevNumber) {
  1249. this.numberPrevEvent(evnt)
  1250. } else {
  1251. this.numberNextEvent(evnt)
  1252. }
  1253. this.downbumTimeout = setTimeout(() => {
  1254. if (isPrevNumber) {
  1255. this.numberDownPrevEvent(evnt)
  1256. } else {
  1257. this.numberDownNextEvent(evnt)
  1258. }
  1259. }, 500)
  1260. }
  1261. },
  1262. numberPrevEvent (evnt) {
  1263. const { disabled, readonly } = this
  1264. clearTimeout(this.downbumTimeout)
  1265. if (!disabled && !readonly) {
  1266. this.numberChange(true, evnt)
  1267. }
  1268. this.$emit('prev-number', { $event: evnt })
  1269. },
  1270. numberNextEvent (evnt) {
  1271. const { disabled, readonly } = this
  1272. clearTimeout(this.downbumTimeout)
  1273. if (!disabled && !readonly) {
  1274. this.numberChange(false, evnt)
  1275. }
  1276. this.$emit('next-number', { $event: evnt })
  1277. },
  1278. numberChange (isPlus, evnt) {
  1279. const { type, digitsValue, value, stepValue } = this
  1280. const inputValue = type === 'integer' ? XEUtils.toInteger(value) : XEUtils.toNumber(value)
  1281. const newValue = isPlus ? XEUtils.add(inputValue, stepValue) : XEUtils.subtract(inputValue, stepValue)
  1282. if (this.vaildMinNum(newValue) && this.vaildMaxNum(newValue)) {
  1283. this.emitUpdate(type === 'float' ? toFloatValueFixed(newValue, digitsValue) : XEUtils.toString(newValue), evnt)
  1284. }
  1285. },
  1286. // 数值
  1287. // 日期
  1288. datePickerOpenEvent (evnt) {
  1289. const { readonly } = this
  1290. if (!readonly) {
  1291. evnt.preventDefault()
  1292. this.showPanel()
  1293. }
  1294. },
  1295. dateMonthHandle (date, offsetMonth) {
  1296. this.selectMonth = XEUtils.getWhatMonth(date, offsetMonth, 'first')
  1297. },
  1298. dateNowHandle () {
  1299. const currentDate = XEUtils.getWhatDay(Date.now(), 0, 'first')
  1300. this.currentDate = currentDate
  1301. this.dateMonthHandle(currentDate, 0)
  1302. },
  1303. dateToggleTypeEvent () {
  1304. let { datePanelType } = this
  1305. if (datePanelType === 'month') {
  1306. datePanelType = 'year'
  1307. } else {
  1308. datePanelType = 'month'
  1309. }
  1310. this.datePanelType = datePanelType
  1311. },
  1312. datePrevEvent (evnt) {
  1313. const { isDisabledPrevDateBtn, type, datePanelType } = this
  1314. if (!isDisabledPrevDateBtn) {
  1315. if (type === 'year') {
  1316. this.selectMonth = XEUtils.getWhatYear(this.selectMonth, -yearSize, 'first')
  1317. } else if (type === 'month') {
  1318. if (datePanelType === 'year') {
  1319. this.selectMonth = XEUtils.getWhatYear(this.selectMonth, -yearSize, 'first')
  1320. } else {
  1321. this.selectMonth = XEUtils.getWhatYear(this.selectMonth, -1, 'first')
  1322. }
  1323. } else {
  1324. if (datePanelType === 'year') {
  1325. this.selectMonth = XEUtils.getWhatYear(this.selectMonth, -yearSize, 'first')
  1326. } else if (datePanelType === 'month') {
  1327. this.selectMonth = XEUtils.getWhatYear(this.selectMonth, -1, 'first')
  1328. } else {
  1329. this.selectMonth = XEUtils.getWhatMonth(this.selectMonth, -1, 'first')
  1330. }
  1331. }
  1332. this.$emit('date-prev', { type, $event: evnt })
  1333. }
  1334. },
  1335. dateTodayMonthEvent (evnt) {
  1336. this.dateNowHandle()
  1337. this.dateChange(this.currentDate)
  1338. this.hidePanel()
  1339. this.$emit('date-today', { type: this.type, $event: evnt })
  1340. },
  1341. dateNextEvent (evnt) {
  1342. const { isDisabledNextDateBtn, type, datePanelType } = this
  1343. if (!isDisabledNextDateBtn) {
  1344. if (type === 'year') {
  1345. this.selectMonth = XEUtils.getWhatYear(this.selectMonth, yearSize, 'first')
  1346. } else if (type === 'month') {
  1347. if (datePanelType === 'year') {
  1348. this.selectMonth = XEUtils.getWhatYear(this.selectMonth, yearSize, 'first')
  1349. } else {
  1350. this.selectMonth = XEUtils.getWhatYear(this.selectMonth, 1, 'first')
  1351. }
  1352. } else {
  1353. if (datePanelType === 'year') {
  1354. this.selectMonth = XEUtils.getWhatYear(this.selectMonth, yearSize, 'first')
  1355. } else if (datePanelType === 'month') {
  1356. this.selectMonth = XEUtils.getWhatYear(this.selectMonth, 1, 'first')
  1357. } else {
  1358. this.selectMonth = XEUtils.getWhatMonth(this.selectMonth, 1, 'first')
  1359. }
  1360. }
  1361. this.$emit('date-prev', { type, $event: evnt })
  1362. }
  1363. },
  1364. dateSelectEvent (item) {
  1365. if (!isDateDisabled(this, item)) {
  1366. this.dateSelectItem(item.date)
  1367. }
  1368. },
  1369. dateSelectItem (date) {
  1370. const { type, datePanelType } = this
  1371. if (type === 'month') {
  1372. if (datePanelType === 'year') {
  1373. this.datePanelType = 'month'
  1374. this.dateCheckMonth(date)
  1375. } else {
  1376. this.dateChange(date)
  1377. this.hidePanel()
  1378. }
  1379. } else if (type === 'year') {
  1380. this.hidePanel()
  1381. this.dateChange(date)
  1382. } else {
  1383. if (datePanelType === 'month') {
  1384. this.datePanelType = type === 'week' ? type : 'day'
  1385. this.dateCheckMonth(date)
  1386. } else if (datePanelType === 'year') {
  1387. this.datePanelType = 'month'
  1388. this.dateCheckMonth(date)
  1389. } else {
  1390. this.dateChange(date)
  1391. this.hidePanel()
  1392. }
  1393. }
  1394. },
  1395. dateMouseenterEvent (item) {
  1396. if (!isDateDisabled(this, item)) {
  1397. const { datePanelType } = this
  1398. if (datePanelType === 'month') {
  1399. this.dateMoveMonth(item.date)
  1400. } else if (datePanelType === 'year') {
  1401. this.dateMoveYear(item.date)
  1402. } else {
  1403. this.dateMoveDay(item.date)
  1404. }
  1405. }
  1406. },
  1407. dateHourEvent (evnt, item) {
  1408. this.datetimePanelValue.setHours(item.value)
  1409. this.dateTimeChangeEvent(evnt)
  1410. },
  1411. dateConfirmEvent () {
  1412. this.dateChange(this.dateValue || this.currentDate)
  1413. this.hidePanel()
  1414. },
  1415. dateMinuteEvent (evnt, item) {
  1416. this.datetimePanelValue.setMinutes(item.value)
  1417. this.dateTimeChangeEvent(evnt)
  1418. },
  1419. dateSecondEvent (evnt, item) {
  1420. this.datetimePanelValue.setSeconds(item.value)
  1421. this.dateTimeChangeEvent(evnt)
  1422. },
  1423. dateTimeChangeEvent (evnt) {
  1424. this.datetimePanelValue = new Date(this.datetimePanelValue.getTime())
  1425. this.updateTimePos(evnt.currentTarget)
  1426. },
  1427. updateTimePos (liElem) {
  1428. if (liElem) {
  1429. const height = liElem.offsetHeight
  1430. liElem.parentNode.scrollTop = liElem.offsetTop - height * 4
  1431. }
  1432. },
  1433. dateMoveDay (offsetDay) {
  1434. if (!isDateDisabled(this, { date: offsetDay })) {
  1435. if (!this.dayList.some(item => XEUtils.isDateSame(item.date, offsetDay, 'yyyy-MM-dd'))) {
  1436. this.dateCheckMonth(offsetDay)
  1437. }
  1438. this.dateParseValue(offsetDay)
  1439. }
  1440. },
  1441. dateMoveMonth (offsetMonth) {
  1442. if (!isDateDisabled(this, { date: offsetMonth })) {
  1443. if (!this.monthList.some(item => XEUtils.isDateSame(item.date, offsetMonth, 'yyyy-MM'))) {
  1444. this.dateCheckMonth(offsetMonth)
  1445. }
  1446. this.dateParseValue(offsetMonth)
  1447. }
  1448. },
  1449. dateMoveYear (offsetYear) {
  1450. if (!isDateDisabled(this, { date: offsetYear })) {
  1451. if (!this.yearList.some(item => XEUtils.isDateSame(item.date, offsetYear, 'yyyy'))) {
  1452. this.dateCheckMonth(offsetYear)
  1453. }
  1454. this.dateParseValue(offsetYear)
  1455. }
  1456. },
  1457. dateParseValue (date) {
  1458. const { type, dateLabelFormat, valueFormat, parseFormat } = this
  1459. let dValue = null
  1460. let dLabel = ''
  1461. if (date) {
  1462. if (type === 'time') {
  1463. dValue = toStringTime(date, valueFormat || parseFormat || this.dateOpts.parseFormat)
  1464. } else {
  1465. dValue = XEUtils.toStringDate(date, valueFormat || parseFormat || this.dateOpts.parseFormat)
  1466. }
  1467. }
  1468. if (XEUtils.isValidDate(dValue)) {
  1469. dLabel = XEUtils.toDateString(dValue, dateLabelFormat)
  1470. } else {
  1471. dValue = null
  1472. }
  1473. this.datePanelValue = dValue
  1474. this.datePanelLabel = dLabel
  1475. },
  1476. dateOffsetEvent (evnt) {
  1477. const { isActivated, datePanelValue, datePanelType } = this
  1478. if (isActivated) {
  1479. evnt.preventDefault()
  1480. const keyCode = evnt.keyCode
  1481. const isLeftArrow = keyCode === 37
  1482. const isUpArrow = keyCode === 38
  1483. const isRightArrow = keyCode === 39
  1484. const isDwArrow = keyCode === 40
  1485. if (datePanelType === 'year') {
  1486. let offsetYear = XEUtils.getWhatYear(datePanelValue || Date.now(), 0, 'first')
  1487. if (isLeftArrow) {
  1488. offsetYear = XEUtils.getWhatYear(offsetYear, -1)
  1489. } else if (isUpArrow) {
  1490. offsetYear = XEUtils.getWhatYear(offsetYear, -4)
  1491. } else if (isRightArrow) {
  1492. offsetYear = XEUtils.getWhatYear(offsetYear, 1)
  1493. } else if (isDwArrow) {
  1494. offsetYear = XEUtils.getWhatYear(offsetYear, 4)
  1495. }
  1496. this.dateMoveYear(offsetYear)
  1497. } else if (datePanelType === 'month') {
  1498. let offsetMonth = XEUtils.getWhatMonth(datePanelValue || Date.now(), 0, 'first')
  1499. if (isLeftArrow) {
  1500. offsetMonth = XEUtils.getWhatMonth(offsetMonth, -1)
  1501. } else if (isUpArrow) {
  1502. offsetMonth = XEUtils.getWhatMonth(offsetMonth, -4)
  1503. } else if (isRightArrow) {
  1504. offsetMonth = XEUtils.getWhatMonth(offsetMonth, 1)
  1505. } else if (isDwArrow) {
  1506. offsetMonth = XEUtils.getWhatMonth(offsetMonth, 4)
  1507. }
  1508. this.dateMoveMonth(offsetMonth)
  1509. } else {
  1510. let offsetDay = datePanelValue || XEUtils.getWhatDay(Date.now(), 0, 'first')
  1511. if (isLeftArrow) {
  1512. offsetDay = XEUtils.getWhatDay(offsetDay, -1)
  1513. } else if (isUpArrow) {
  1514. offsetDay = XEUtils.getWhatWeek(offsetDay, -1)
  1515. } else if (isRightArrow) {
  1516. offsetDay = XEUtils.getWhatDay(offsetDay, 1)
  1517. } else if (isDwArrow) {
  1518. offsetDay = XEUtils.getWhatWeek(offsetDay, 1)
  1519. }
  1520. this.dateMoveDay(offsetDay)
  1521. }
  1522. }
  1523. },
  1524. datePgOffsetEvent (evnt) {
  1525. const { isActivated } = this
  1526. if (isActivated) {
  1527. const isPgUp = evnt.keyCode === 33
  1528. evnt.preventDefault()
  1529. if (isPgUp) {
  1530. this.datePrevEvent(evnt)
  1531. } else {
  1532. this.dateNextEvent(evnt)
  1533. }
  1534. }
  1535. },
  1536. dateChange (date) {
  1537. const { value, datetimePanelValue, dateValueFormat } = this
  1538. if (this.type === 'week') {
  1539. const sWeek = XEUtils.toNumber(XEUtils.isNumber(this.startWeek) ? this.startWeek : this.dateOpts.startWeek)
  1540. date = XEUtils.getWhatWeek(date, 0, sWeek)
  1541. } else if (this.hasTime) {
  1542. date.setHours(datetimePanelValue.getHours())
  1543. date.setMinutes(datetimePanelValue.getMinutes())
  1544. date.setSeconds(datetimePanelValue.getSeconds())
  1545. }
  1546. const inpVal = XEUtils.toDateString(date, dateValueFormat)
  1547. this.dateCheckMonth(date)
  1548. if (!XEUtils.isEqual(value, inpVal)) {
  1549. this.emitUpdate(inpVal, { type: 'update' })
  1550. }
  1551. },
  1552. dateCheckMonth (date) {
  1553. const month = XEUtils.getWhatMonth(date, 0, 'first')
  1554. if (!XEUtils.isEqual(month, this.selectMonth)) {
  1555. this.selectMonth = month
  1556. }
  1557. },
  1558. dateOpenPanel () {
  1559. const { type, dateValue } = this
  1560. if (['year', 'month', 'week'].indexOf(type) > -1) {
  1561. this.datePanelType = type
  1562. } else {
  1563. this.datePanelType = 'day'
  1564. }
  1565. this.currentDate = XEUtils.getWhatDay(Date.now(), 0, 'first')
  1566. if (dateValue) {
  1567. this.dateMonthHandle(dateValue, 0)
  1568. this.dateParseValue(dateValue)
  1569. } else {
  1570. this.dateNowHandle()
  1571. }
  1572. if (this.hasTime) {
  1573. this.datetimePanelValue = this.datePanelValue || XEUtils.getWhatDay(Date.now(), 0, 'first')
  1574. this.$nextTick(() => {
  1575. XEUtils.arrayEach(this.$refs.timeBody.querySelectorAll('li.is--selected'), this.updateTimePos)
  1576. })
  1577. }
  1578. },
  1579. dateRevert () {
  1580. this.inputValue = this.datePanelLabel
  1581. },
  1582. // 日期
  1583. // 弹出面板
  1584. updateZindex () {
  1585. if (this.panelIndex < UtilTools.getLastZIndex()) {
  1586. this.panelIndex = UtilTools.nextZIndex()
  1587. }
  1588. },
  1589. showPanel () {
  1590. const { disabled, visiblePanel, isDatePicker } = this
  1591. if (!disabled && !visiblePanel) {
  1592. clearTimeout(this.hidePanelTimeout)
  1593. this.isActivated = true
  1594. this.animatVisible = true
  1595. if (isDatePicker) {
  1596. this.dateOpenPanel()
  1597. }
  1598. setTimeout(() => {
  1599. this.visiblePanel = true
  1600. }, 10)
  1601. this.updateZindex()
  1602. this.updatePlacement()
  1603. }
  1604. },
  1605. hidePanel () {
  1606. this.visiblePanel = false
  1607. this.hidePanelTimeout = setTimeout(() => {
  1608. this.animatVisible = false
  1609. }, 350)
  1610. },
  1611. updatePlacement () {
  1612. return this.$nextTick().then(() => {
  1613. const { $refs, transfer, placement, panelIndex } = this
  1614. const targetElem = $refs.input
  1615. const panelElem = $refs.panel
  1616. if (targetElem && panelElem) {
  1617. const targetHeight = targetElem.offsetHeight
  1618. const targetWidth = targetElem.offsetWidth
  1619. const panelHeight = panelElem.offsetHeight
  1620. const panelWidth = panelElem.offsetWidth
  1621. const marginSize = 5
  1622. const panelStyle = {
  1623. zIndex: panelIndex
  1624. }
  1625. const { boundingTop, boundingLeft, visibleHeight, visibleWidth } = DomTools.getAbsolutePos(targetElem)
  1626. let panelPlacement = 'bottom'
  1627. if (transfer) {
  1628. let left = boundingLeft
  1629. let top = boundingTop + targetHeight
  1630. if (placement === 'top') {
  1631. panelPlacement = 'top'
  1632. top = boundingTop - panelHeight
  1633. } else if (!placement) {
  1634. // 如果下面不够放,则向上
  1635. if (top + panelHeight + marginSize > visibleHeight) {
  1636. panelPlacement = 'top'
  1637. top = boundingTop - panelHeight
  1638. }
  1639. // 如果上面不够放,则向下(优先)
  1640. if (top < marginSize) {
  1641. panelPlacement = 'bottom'
  1642. top = boundingTop + targetHeight
  1643. }
  1644. }
  1645. // 如果溢出右边
  1646. if (left + panelWidth + marginSize > visibleWidth) {
  1647. left -= left + panelWidth + marginSize - visibleWidth
  1648. }
  1649. // 如果溢出左边
  1650. if (left < marginSize) {
  1651. left = marginSize
  1652. }
  1653. Object.assign(panelStyle, {
  1654. left: `${left}px`,
  1655. top: `${top}px`,
  1656. minWidth: `${targetWidth}px`
  1657. })
  1658. } else {
  1659. if (placement === 'top') {
  1660. panelPlacement = 'top'
  1661. panelStyle.bottom = `${targetHeight}px`
  1662. } else if (!placement) {
  1663. // 如果下面不够放,则向上
  1664. if (boundingTop + targetHeight + panelHeight > visibleHeight) {
  1665. // 如果上面不够放,则向下(优先)
  1666. if (boundingTop - targetHeight - panelHeight > marginSize) {
  1667. panelPlacement = 'top'
  1668. panelStyle.bottom = `${targetHeight}px`
  1669. }
  1670. }
  1671. }
  1672. }
  1673. this.panelStyle = panelStyle
  1674. this.panelPlacement = panelPlacement
  1675. return this.$nextTick()
  1676. }
  1677. })
  1678. },
  1679. // 弹出面板
  1680. // 全局事件
  1681. handleGlobalMousedownEvent (evnt) {
  1682. const { $refs, $el, disabled, visiblePanel, isActivated } = this
  1683. if (!disabled && isActivated) {
  1684. this.isActivated = DomTools.getEventTargetNode(evnt, $el).flag || DomTools.getEventTargetNode(evnt, $refs.panel).flag
  1685. if (!this.isActivated) {
  1686. // 如果是日期类型
  1687. if (this.isDatePicker) {
  1688. if (visiblePanel) {
  1689. this.hidePanel()
  1690. this.afterCheckValue()
  1691. }
  1692. } else {
  1693. this.afterCheckValue()
  1694. }
  1695. }
  1696. }
  1697. },
  1698. handleGlobalKeydownEvent (evnt) {
  1699. const { isDatePicker, visiblePanel, clearable, disabled } = this
  1700. if (!disabled) {
  1701. const keyCode = evnt.keyCode
  1702. const isTab = keyCode === 9
  1703. const isDel = keyCode === 46
  1704. const isEsc = keyCode === 27
  1705. const isEnter = keyCode === 13
  1706. const isLeftArrow = keyCode === 37
  1707. const isUpArrow = keyCode === 38
  1708. const isRightArrow = keyCode === 39
  1709. const isDwArrow = keyCode === 40
  1710. const isPgUp = keyCode === 33
  1711. const isPgDn = keyCode === 34
  1712. const operArrow = isLeftArrow || isUpArrow || isRightArrow || isDwArrow
  1713. let isActivated = this.isActivated
  1714. if (isTab) {
  1715. if (isActivated) {
  1716. this.afterCheckValue()
  1717. }
  1718. isActivated = false
  1719. this.isActivated = isActivated
  1720. } else if (operArrow) {
  1721. if (isDatePicker) {
  1722. if (isActivated) {
  1723. if (visiblePanel) {
  1724. this.dateOffsetEvent(evnt)
  1725. } else if (isUpArrow || isDwArrow) {
  1726. this.datePickerOpenEvent(evnt)
  1727. }
  1728. }
  1729. }
  1730. } else if (isEnter) {
  1731. if (isDatePicker) {
  1732. if (visiblePanel) {
  1733. if (this.datePanelValue) {
  1734. this.dateSelectItem(this.datePanelValue)
  1735. } else {
  1736. this.hidePanel()
  1737. }
  1738. } else if (isActivated) {
  1739. this.datePickerOpenEvent(evnt)
  1740. }
  1741. }
  1742. } else if (isPgUp || isPgDn) {
  1743. if (isDatePicker) {
  1744. if (isActivated) {
  1745. this.datePgOffsetEvent(evnt)
  1746. }
  1747. }
  1748. }
  1749. if (isTab || isEsc) {
  1750. if (visiblePanel) {
  1751. this.hidePanel()
  1752. }
  1753. } else if (isDel && clearable) {
  1754. if (isActivated) {
  1755. this.clearValueEvent(evnt, null)
  1756. }
  1757. }
  1758. }
  1759. },
  1760. handleGlobalMousewheelEvent (evnt) {
  1761. const { $refs, disabled, visiblePanel } = this
  1762. if (!disabled) {
  1763. if (visiblePanel) {
  1764. if (DomTools.getEventTargetNode(evnt, $refs.panel).flag) {
  1765. this.updatePlacement()
  1766. } else {
  1767. this.hidePanel()
  1768. this.afterCheckValue()
  1769. }
  1770. }
  1771. }
  1772. },
  1773. handleGlobalBlurEvent () {
  1774. const { isActivated, visiblePanel } = this
  1775. if (visiblePanel) {
  1776. this.hidePanel()
  1777. this.afterCheckValue()
  1778. } else if (isActivated) {
  1779. this.afterCheckValue()
  1780. }
  1781. }
  1782. // 全局事件
  1783. }
  1784. }