index.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. import { CreateElement } from 'vue'
  2. import XEUtils from 'xe-utils'
  3. import { renderer, getComponent } from '../../ui'
  4. import { getOnName, getModelEvent, getChangeEvent } from '../../ui/src/vn'
  5. import { errLog } from '../../ui/src/log'
  6. import type { VxeGlobalRendererHandles } from '../../../types'
  7. const componentDefaultModelProp = 'value'
  8. /**
  9. * 已废弃
  10. * @deprecated
  11. */
  12. function getOldComponentName (name: string | undefined) {
  13. return `vxe-${`${name || ''}`.replace('$', '')}`
  14. }
  15. /**
  16. * 已废弃
  17. * @deprecated
  18. */
  19. function getOldComponent ({ name }: VxeGlobalRendererHandles.RenderFormItemContentOptions) {
  20. return getOldComponentName(name)
  21. }
  22. function getDefaultComponent ({ name }: VxeGlobalRendererHandles.RenderFormItemContentOptions) {
  23. return getComponent(name as any) || name
  24. }
  25. function getNativeAttrs (renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions) {
  26. let { name, attrs } = renderOpts
  27. if (name === 'input') {
  28. attrs = Object.assign({ type: 'text' }, attrs)
  29. }
  30. return attrs
  31. }
  32. function getComponentFormItemProps (renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any, value: any, defaultProps?: any) {
  33. return XEUtils.assign({}, defaultProps, renderOpts.props, { [componentDefaultModelProp]: value })
  34. }
  35. /**
  36. * 原生事件处理
  37. * @param renderOpts
  38. * @param params
  39. * @param modelFunc
  40. * @param changeFunc
  41. */
  42. function getElementOns (renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any, modelFunc?: any, changeFunc?: any) {
  43. const { events } = renderOpts
  44. const modelEvent = getModelEvent(renderOpts)
  45. const changeEvent = getChangeEvent(renderOpts)
  46. const isSameEvent = changeEvent === modelEvent
  47. const ons: any = {}
  48. if (events) {
  49. XEUtils.objectEach(events, (func, key: any) => {
  50. ons[getOnName(key)] = function (...args: any[]) {
  51. func(params, ...args)
  52. }
  53. })
  54. }
  55. if (modelFunc) {
  56. ons[getOnName(modelEvent)] = function (targetEvnt: any) {
  57. modelFunc(targetEvnt)
  58. if (isSameEvent && changeFunc) {
  59. changeFunc(targetEvnt)
  60. }
  61. if (events && events[modelEvent]) {
  62. events[modelEvent](params, targetEvnt)
  63. }
  64. }
  65. }
  66. if (!isSameEvent && changeFunc) {
  67. ons[getOnName(changeEvent)] = function (...args: any[]) {
  68. changeFunc(...args)
  69. if (events && events[changeEvent]) {
  70. events[changeEvent](params, ...args)
  71. }
  72. }
  73. }
  74. return ons
  75. }
  76. /**
  77. * 组件事件处理
  78. * @param renderOpts
  79. * @param params
  80. * @param modelFunc
  81. * @param changeFunc
  82. */
  83. function getComponentOns (renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any, eFns?: {
  84. model: (cellValue: any) => void
  85. change?: (...args: any[]) => void
  86. }, eventOns?: Record<string, any>) {
  87. const { events } = renderOpts
  88. const { model: modelFunc, change: changeFunc } = eFns || {}
  89. const modelEvent = getModelEvent(renderOpts)
  90. const changeEvent = getChangeEvent(renderOpts)
  91. const ons: any = {}
  92. XEUtils.objectEach(events, (func, key: any) => {
  93. ons[getOnName(key)] = function (...args: any[]) {
  94. if (!XEUtils.isFunction(func)) {
  95. errLog('vxe.error.errFunc', [`[form] ${func}`])
  96. }
  97. func(params, ...args)
  98. }
  99. })
  100. if (modelFunc) {
  101. ons[getOnName(modelEvent)] = function (targetEvnt: any) {
  102. modelFunc(targetEvnt)
  103. if (events && events[modelEvent]) {
  104. events[modelEvent](params, targetEvnt)
  105. }
  106. }
  107. }
  108. if (changeFunc) {
  109. ons[getOnName(changeEvent)] = function (...args: any[]) {
  110. changeFunc(...args)
  111. if (events && events[changeEvent]) {
  112. events[changeEvent](params, ...args)
  113. }
  114. }
  115. }
  116. return eventOns ? Object.assign(ons, eventOns) : ons
  117. }
  118. function getItemOns (renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  119. const { $form, data, field } = params
  120. return getComponentOns(renderOpts, params, {
  121. model (value: any) {
  122. // 处理 model 值双向绑定
  123. XEUtils.set(data, field, value)
  124. },
  125. change () {
  126. // 处理 change 事件相关逻辑
  127. $form.updateStatus(params)
  128. }
  129. })
  130. }
  131. function getNativeItemOns (renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  132. const { $form, data, field } = params
  133. return getElementOns(renderOpts, params, (evnt: any) => {
  134. // 处理 model 值双向绑定
  135. const itemValue = evnt.target.value
  136. XEUtils.set(data, field, itemValue)
  137. }, () => {
  138. // 处理 change 事件相关逻辑
  139. $form.updateStatus(params)
  140. })
  141. }
  142. function renderNativeOptgroup (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any, renderOptionsMethods: any) {
  143. const { optionGroups, optionGroupProps = {} } = renderOpts
  144. const groupOptions = optionGroupProps.options || 'options'
  145. const groupLabel = optionGroupProps.label || 'label'
  146. if (optionGroups) {
  147. return optionGroups.map((group: any, gIndex: any) => {
  148. return h('optgroup', {
  149. key: gIndex,
  150. attrs: {
  151. label: group[groupLabel]
  152. }
  153. }, renderOptionsMethods(group[groupOptions], renderOpts, params))
  154. })
  155. }
  156. return []
  157. }
  158. /**
  159. * 渲染表单-项
  160. * 用于渲染原生的标签
  161. */
  162. function nativeItemRender (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  163. const { data, field } = params
  164. const { name } = renderOpts
  165. const attrs = getNativeAttrs(renderOpts)
  166. const itemValue = XEUtils.get(data, field)
  167. return [
  168. h(`${name}`, {
  169. class: `vxe-default-${name}`,
  170. attrs,
  171. domProps: {
  172. value: attrs && name === 'input' && (attrs.type === 'submit' || attrs.type === 'reset') ? null : itemValue
  173. },
  174. on: getNativeItemOns(renderOpts, params)
  175. })
  176. ]
  177. }
  178. function defaultItemRender (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: VxeGlobalRendererHandles.RenderFormItemContentParams) {
  179. const { data, field } = params
  180. const itemValue = XEUtils.get(data, field)
  181. return [
  182. h(getDefaultComponent(renderOpts), {
  183. props: getComponentFormItemProps(renderOpts, params, itemValue),
  184. on: getItemOns(renderOpts, params)
  185. })
  186. ]
  187. }
  188. /**
  189. * 已废弃
  190. * @deprecated
  191. */
  192. function oldItemRender (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  193. const { data, field } = params
  194. const itemValue = XEUtils.get(data, field)
  195. return [
  196. h(getOldComponent(renderOpts), {
  197. props: getComponentFormItemProps(renderOpts, params, itemValue),
  198. on: getItemOns(renderOpts, params)
  199. })
  200. ]
  201. }
  202. /**
  203. * 已废弃
  204. * @deprecated
  205. */
  206. function oldButtonItemRender (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  207. return [
  208. h('vxe-button', {
  209. props: getComponentFormItemProps(renderOpts, params, null),
  210. on: getComponentOns(renderOpts, params)
  211. })
  212. ]
  213. }
  214. /**
  215. * 已废弃
  216. * @deprecated
  217. */
  218. function oldButtonsItemRender (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  219. const { children } = renderOpts
  220. return children ? children.map((childRenderOpts: any) => oldButtonItemRender(h, childRenderOpts, params)[0]) : []
  221. }
  222. /**
  223. * 渲染原生的 select 标签
  224. */
  225. function renderNativeFormOptions (h: CreateElement, options: any, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  226. const { data, field } = params
  227. const { optionProps = {} } = renderOpts
  228. const labelProp = optionProps.label || 'label'
  229. const valueProp = optionProps.value || 'value'
  230. const disabledProp = optionProps.disabled || 'disabled'
  231. const cellValue = XEUtils.get(data, field)
  232. if (options) {
  233. return options.map((item: any, oIndex: any) => {
  234. return h('option', {
  235. key: oIndex,
  236. props: {
  237. value: item[valueProp],
  238. disabled: item[disabledProp],
  239. /* eslint-disable eqeqeq */
  240. selected: item[valueProp] == cellValue
  241. }
  242. }, item[labelProp])
  243. })
  244. }
  245. return []
  246. }
  247. /**
  248. * 渲染表单-项
  249. */
  250. function defaultFormItemRender (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  251. const { data, field } = params
  252. const itemValue = XEUtils.get(data, field)
  253. return [
  254. h(getDefaultComponent(renderOpts), {
  255. props: getComponentFormItemProps(renderOpts, params, itemValue),
  256. on: getItemOns(renderOpts, params)
  257. })
  258. ]
  259. }
  260. function formItemRadioAndCheckboxRender (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  261. const { options, optionProps } = renderOpts
  262. const { data, field } = params
  263. const itemValue = XEUtils.get(data, field)
  264. return [
  265. h(getDefaultComponent(renderOpts), {
  266. props: {
  267. options,
  268. optionProps,
  269. ...getComponentFormItemProps(renderOpts, params, itemValue)
  270. },
  271. on: getItemOns(renderOpts, params)
  272. })
  273. ]
  274. }
  275. /**
  276. * 已废弃
  277. * @deprecated
  278. */
  279. function oldFormItemRadioAndCheckboxRender (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  280. const { name, options, optionProps = {} } = renderOpts
  281. const { data, field } = params
  282. const labelProp = optionProps.label || 'label'
  283. const valueProp = optionProps.value || 'value'
  284. const disabledProp = optionProps.disabled || 'disabled'
  285. const itemValue = XEUtils.get(data, field)
  286. const compName = getOldComponentName(name)
  287. // 如果是分组
  288. if (options) {
  289. return [
  290. h(`${compName}-group`, {
  291. props: getComponentFormItemProps(renderOpts, params, itemValue),
  292. on: getItemOns(renderOpts, params),
  293. scopedSlots: {
  294. default: () => {
  295. return options.map((item: any, index: any) => {
  296. return h(compName, {
  297. key: index,
  298. props: {
  299. label: item[valueProp],
  300. content: item[labelProp],
  301. disabled: item[disabledProp]
  302. }
  303. })
  304. })
  305. }
  306. }
  307. })
  308. ]
  309. }
  310. return [
  311. h(compName, {
  312. props: getComponentFormItemProps(renderOpts, params, itemValue),
  313. on: getItemOns(renderOpts, params)
  314. })
  315. ]
  316. }
  317. /**
  318. * 表单 - 渲染器
  319. */
  320. renderer.mixin({
  321. input: {
  322. formItemAutoFocus: 'input',
  323. renderFormItemContent: nativeItemRender
  324. },
  325. textarea: {
  326. formItemAutoFocus: 'textarea',
  327. renderFormItemContent: nativeItemRender
  328. },
  329. select: {
  330. formItemAutoFocus: 'input',
  331. renderFormItemContent (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  332. return [
  333. h('select', {
  334. class: 'vxe-default-select',
  335. attrs: {
  336. ...getNativeAttrs(renderOpts)
  337. },
  338. on: getNativeItemOns(renderOpts, params)
  339. },
  340. renderOpts.optionGroups ? renderNativeOptgroup(h, renderOpts, params, renderNativeFormOptions) : renderNativeFormOptions(h, renderOpts.options, renderOpts, params))
  341. ]
  342. }
  343. },
  344. VxeInput: {
  345. formItemAutoFocus: 'input',
  346. renderFormItemContent: defaultItemRender
  347. },
  348. VxeNumberInput: {
  349. formItemAutoFocus: 'input',
  350. renderFormItemContent: defaultItemRender
  351. },
  352. VxePasswordInput: {
  353. formItemAutoFocus: 'input',
  354. renderFormItemContent: defaultItemRender
  355. },
  356. VxeTextarea: {
  357. formItemAutoFocus: 'textarea',
  358. renderFormItemContent: defaultItemRender
  359. },
  360. VxeDatePicker: {
  361. formItemAutoFocus: 'input',
  362. renderFormItemContent: defaultItemRender
  363. },
  364. VxeDateRangePicker: {
  365. formItemAutoFocus: 'input',
  366. renderFormItemContent (h, renderOpts, params) {
  367. const { startField, endField } = renderOpts
  368. const { $form, data, field } = params
  369. const itemValue = XEUtils.get(data, field)
  370. const seProps: Record<string, any> = {}
  371. const seOs: Record<string, any> = {}
  372. if (startField && endField) {
  373. seProps.startValue = XEUtils.get(data, startField)
  374. seProps.endValue = XEUtils.get(data, endField)
  375. seOs['update:startValue'] = (value: any) => {
  376. if (startField) {
  377. XEUtils.set(data, startField, value)
  378. }
  379. }
  380. seOs['update:endValue'] = (value: any) => {
  381. if (endField) {
  382. XEUtils.set(data, endField, value)
  383. }
  384. }
  385. }
  386. return [
  387. h(getDefaultComponent(renderOpts), {
  388. props: getComponentFormItemProps(renderOpts, params, itemValue, seProps),
  389. on: getComponentOns(renderOpts, params, {
  390. model (value: any) {
  391. // 处理 model 值双向绑定
  392. XEUtils.set(data, field, value)
  393. },
  394. change () {
  395. // 处理 change 事件相关逻辑
  396. $form.updateStatus(params)
  397. }
  398. }, seOs)
  399. })
  400. ]
  401. }
  402. },
  403. VxeButton: {
  404. renderFormItemContent: defaultFormItemRender
  405. },
  406. VxeButtonGroup: {
  407. renderFormItemContent (h: CreateElement, renderOpts, params) {
  408. const { options } = renderOpts
  409. const { data, field } = params
  410. const itemValue = XEUtils.get(data, field)
  411. return [
  412. h(getDefaultComponent(renderOpts), {
  413. props: {
  414. options,
  415. ...getComponentFormItemProps(renderOpts, params, itemValue)
  416. },
  417. on: getItemOns(renderOpts, params)
  418. })
  419. ]
  420. }
  421. },
  422. VxeSelect: {
  423. formItemAutoFocus: 'input',
  424. renderFormItemContent (h: CreateElement, renderOpts, params) {
  425. const { data, field } = params
  426. const { options, optionProps, optionGroups, optionGroupProps } = renderOpts
  427. const itemValue = XEUtils.get(data, field)
  428. return [
  429. h(getDefaultComponent(renderOpts), {
  430. props: getComponentFormItemProps(renderOpts, params, itemValue, { options, optionProps, optionGroups, optionGroupProps }),
  431. on: getItemOns(renderOpts, params)
  432. })
  433. ]
  434. }
  435. },
  436. VxeTreeSelect: {
  437. formItemAutoFocus: 'input',
  438. renderFormItemContent (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  439. const { data, field } = params
  440. const { options, optionProps } = renderOpts
  441. const itemValue = XEUtils.get(data, field)
  442. return [
  443. h(getDefaultComponent(renderOpts), {
  444. props: getComponentFormItemProps(renderOpts, params, itemValue, { options, optionProps }),
  445. on: getItemOns(renderOpts, params)
  446. })
  447. ]
  448. }
  449. },
  450. VxeTableSelect: {
  451. formItemAutoFocus: 'input',
  452. renderFormItemContent (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  453. const { data, field } = params
  454. const { options, optionProps } = renderOpts
  455. const itemValue = XEUtils.get(data, field)
  456. return [
  457. h(getDefaultComponent(renderOpts), {
  458. props: getComponentFormItemProps(renderOpts, params, itemValue, { options, optionProps }),
  459. on: getItemOns(renderOpts, params)
  460. })
  461. ]
  462. }
  463. },
  464. VxeColorPicker: {
  465. formItemAutoFocus: 'input',
  466. renderFormItemContent (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  467. const { data, field } = params
  468. const { options } = renderOpts
  469. const itemValue = XEUtils.get(data, field)
  470. return [
  471. h(getDefaultComponent(renderOpts), {
  472. props: getComponentFormItemProps(renderOpts, params, itemValue, { colors: options }),
  473. on: getItemOns(renderOpts, params)
  474. })
  475. ]
  476. }
  477. },
  478. VxeIconPicker: {
  479. formItemAutoFocus: 'input',
  480. renderFormItemContent (h: CreateElement, renderOpts: VxeGlobalRendererHandles.RenderFormItemContentOptions, params: any) {
  481. const { data, field } = params
  482. const { options } = renderOpts
  483. const itemValue = XEUtils.get(data, field)
  484. return [
  485. h(getDefaultComponent(renderOpts), {
  486. props: getComponentFormItemProps(renderOpts, params, itemValue, { icons: options }),
  487. on: getItemOns(renderOpts, params)
  488. })
  489. ]
  490. }
  491. },
  492. VxeRadio: {
  493. renderFormItemContent: defaultFormItemRender
  494. },
  495. VxeRadioGroup: {
  496. renderFormItemContent: formItemRadioAndCheckboxRender
  497. },
  498. VxeCheckbox: {
  499. renderFormItemContent: defaultFormItemRender
  500. },
  501. VxeCheckboxGroup: {
  502. renderFormItemContent: formItemRadioAndCheckboxRender
  503. },
  504. VxeSwitch: {
  505. renderFormItemContent: defaultItemRender
  506. },
  507. VxeRate: {
  508. renderFormItemContent: defaultItemRender
  509. },
  510. VxeSlider: {
  511. renderFormItemContent: defaultItemRender
  512. },
  513. VxeImage: {
  514. renderFormItemContent (h: CreateElement, renderOpts, params) {
  515. const { data, field } = params
  516. const { props } = renderOpts
  517. const itemValue = XEUtils.get(data, field)
  518. return [
  519. h(getDefaultComponent(renderOpts), {
  520. props: {
  521. ...props,
  522. src: itemValue
  523. },
  524. on: getItemOns(renderOpts, params)
  525. })
  526. ]
  527. }
  528. },
  529. VxeImageGroup: {
  530. renderFormItemContent (h: CreateElement, renderOpts, params) {
  531. const { data, field } = params
  532. const { props } = renderOpts
  533. const itemValue = XEUtils.get(data, field)
  534. return [
  535. h(getDefaultComponent(renderOpts), {
  536. props: {
  537. ...props,
  538. urlList: itemValue
  539. },
  540. on: getItemOns(renderOpts, params)
  541. })
  542. ]
  543. }
  544. },
  545. VxeUpload: {
  546. renderFormItemContent: defaultItemRender
  547. },
  548. // 以下已废弃
  549. $input: {
  550. formItemAutoFocus: 'input',
  551. renderFormItemContent: oldItemRender
  552. },
  553. $textarea: {
  554. formItemAutoFocus: 'textarea',
  555. renderFormItemContent: oldItemRender
  556. },
  557. $button: {
  558. renderFormItemContent: oldButtonItemRender
  559. },
  560. $buttons: {
  561. renderFormItemContent: oldButtonsItemRender
  562. },
  563. $select: {
  564. formItemAutoFocus: 'input',
  565. renderFormItemContent (h: CreateElement, renderOpts, params) {
  566. const { data, field } = params
  567. const { options, optionProps, optionGroups, optionGroupProps } = renderOpts
  568. const itemValue = XEUtils.get(data, field)
  569. return [
  570. h(getOldComponent(renderOpts), {
  571. props: getComponentFormItemProps(renderOpts, params, itemValue, { options, optionProps, optionGroups, optionGroupProps }),
  572. on: getItemOns(renderOpts, params)
  573. })
  574. ]
  575. }
  576. },
  577. $radio: {
  578. renderFormItemContent: oldFormItemRadioAndCheckboxRender
  579. },
  580. $checkbox: {
  581. renderFormItemContent: oldFormItemRadioAndCheckboxRender
  582. },
  583. $switch: {
  584. renderFormItemContent: oldItemRender
  585. }
  586. // 以上已废弃
  587. })