renderHelpers.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import {
  2. camelize,
  3. extend,
  4. hyphenate,
  5. isArray,
  6. isObject,
  7. isReservedProp,
  8. normalizeClass,
  9. } from '@vue/shared'
  10. import type { ComponentInternalInstance, Data } from '../component'
  11. import type { Slot } from '../componentSlots'
  12. import { createSlots } from '../helpers/createSlots'
  13. import { renderSlot } from '../helpers/renderSlot'
  14. import { toHandlers } from '../helpers/toHandlers'
  15. import { type VNode, mergeProps } from '../vnode'
  16. function toObject(arr: Array<any>): Object {
  17. const res = {}
  18. for (let i = 0; i < arr.length; i++) {
  19. if (arr[i]) {
  20. extend(res, arr[i])
  21. }
  22. }
  23. return res
  24. }
  25. export function legacyBindObjectProps(
  26. data: any,
  27. _tag: string,
  28. value: any,
  29. _asProp: boolean,
  30. isSync?: boolean,
  31. ): any {
  32. if (value && isObject(value)) {
  33. if (isArray(value)) {
  34. value = toObject(value)
  35. }
  36. for (const key in value) {
  37. if (isReservedProp(key)) {
  38. data[key] = value[key]
  39. } else if (key === 'class') {
  40. data.class = normalizeClass([data.class, value.class])
  41. } else if (key === 'style') {
  42. data.style = normalizeClass([data.style, value.style])
  43. } else {
  44. const attrs = data.attrs || (data.attrs = {})
  45. const camelizedKey = camelize(key)
  46. const hyphenatedKey = hyphenate(key)
  47. if (!(camelizedKey in attrs) && !(hyphenatedKey in attrs)) {
  48. attrs[key] = value[key]
  49. if (isSync) {
  50. const on = data.on || (data.on = {})
  51. on[`update:${key}`] = function ($event: any) {
  52. value[key] = $event
  53. }
  54. }
  55. }
  56. }
  57. }
  58. }
  59. return data
  60. }
  61. export function legacyBindObjectListeners(props: any, listeners: any): Data {
  62. return mergeProps(props, toHandlers(listeners))
  63. }
  64. export function legacyRenderSlot(
  65. instance: ComponentInternalInstance,
  66. name: string,
  67. fallback?: VNode[],
  68. props?: any,
  69. bindObject?: any,
  70. ): VNode {
  71. if (bindObject) {
  72. props = mergeProps(props, bindObject)
  73. }
  74. return renderSlot(instance.slots, name, props, fallback && (() => fallback))
  75. }
  76. type LegacyScopedSlotsData = Array<
  77. | {
  78. key: string
  79. fn: Function
  80. }
  81. | LegacyScopedSlotsData
  82. >
  83. export function legacyresolveScopedSlots(
  84. fns: LegacyScopedSlotsData,
  85. raw?: Record<string, Slot>,
  86. // the following are added in 2.6
  87. hasDynamicKeys?: boolean,
  88. ): ReturnType<typeof createSlots> {
  89. // v2 default slot doesn't have name
  90. return createSlots(
  91. raw || ({ $stable: !hasDynamicKeys } as any),
  92. mapKeyToName(fns),
  93. )
  94. }
  95. function mapKeyToName(slots: LegacyScopedSlotsData) {
  96. for (let i = 0; i < slots.length; i++) {
  97. const fn = slots[i]
  98. if (fn) {
  99. if (isArray(fn)) {
  100. mapKeyToName(fn)
  101. } else {
  102. ;(fn as any).name = fn.key || 'default'
  103. }
  104. }
  105. }
  106. return slots as any
  107. }
  108. const staticCacheMap = /*@__PURE__*/ new WeakMap<
  109. ComponentInternalInstance,
  110. any[]
  111. >()
  112. export function legacyRenderStatic(
  113. instance: ComponentInternalInstance,
  114. index: number,
  115. ): any {
  116. let cache = staticCacheMap.get(instance)
  117. if (!cache) {
  118. staticCacheMap.set(instance, (cache = []))
  119. }
  120. if (cache[index]) {
  121. return cache[index]
  122. }
  123. const fn = (instance.type as any).staticRenderFns[index]
  124. const ctx = instance.proxy
  125. return (cache[index] = fn.call(ctx, null, ctx))
  126. }
  127. export function legacyCheckKeyCodes(
  128. instance: ComponentInternalInstance,
  129. eventKeyCode: number,
  130. key: string,
  131. builtInKeyCode?: number | number[],
  132. eventKeyName?: string,
  133. builtInKeyName?: string | string[],
  134. ): boolean | undefined {
  135. const config = instance.appContext.config as any
  136. const configKeyCodes = config.keyCodes || {}
  137. const mappedKeyCode = configKeyCodes[key] || builtInKeyCode
  138. if (builtInKeyName && eventKeyName && !configKeyCodes[key]) {
  139. return isKeyNotMatch(builtInKeyName, eventKeyName)
  140. } else if (mappedKeyCode) {
  141. return isKeyNotMatch(mappedKeyCode, eventKeyCode)
  142. } else if (eventKeyName) {
  143. return hyphenate(eventKeyName) !== key
  144. }
  145. }
  146. function isKeyNotMatch<T>(expect: T | T[], actual: T): boolean {
  147. if (isArray(expect)) {
  148. return !expect.includes(actual)
  149. } else {
  150. return expect !== actual
  151. }
  152. }
  153. export function legacyMarkOnce(tree: VNode): VNode {
  154. return tree
  155. }
  156. export function legacyBindDynamicKeys(props: any, values: any[]): any {
  157. for (let i = 0; i < values.length; i += 2) {
  158. const key = values[i]
  159. if (typeof key === 'string' && key) {
  160. props[values[i]] = values[i + 1]
  161. }
  162. }
  163. return props
  164. }
  165. export function legacyPrependModifier(value: any, symbol: string): any {
  166. return typeof value === 'string' ? symbol + value : value
  167. }