Evan You 5 лет назад
Родитель
Сommit
80303bcf5a

+ 4 - 7
packages/runtime-core/src/compat/renderFn.ts

@@ -113,7 +113,7 @@ export function compatH(
 ): VNode
 export function compatH(
   type: string | Component,
-  props?: LegacyVNodeProps,
+  props?: Data & LegacyVNodeProps,
   children?: LegacyVNodeChildren
 ): VNode
 
@@ -190,16 +190,12 @@ function convertLegacyProps(
     } else if (key === 'on' || key === 'nativeOn') {
       const listeners = legacyProps[key]
       for (const event in listeners) {
-        const handlerKey = convertLegacyEventKey(event)
+        let handlerKey = convertLegacyEventKey(event)
+        if (key === 'nativeOn') handlerKey += `Native`
         const existing = converted[handlerKey]
         const incoming = listeners[event]
         if (existing !== incoming) {
           if (existing) {
-            // for the rare case where the same handler is attached
-            // twice with/without .native modifier...
-            if (key === 'nativeOn' && String(existing) === String(incoming)) {
-              continue
-            }
             converted[handlerKey] = [].concat(existing as any, incoming as any)
           } else {
             converted[handlerKey] = incoming
@@ -307,6 +303,7 @@ function convertLegacySlots(vnode: VNode): VNode {
 }
 
 export function defineLegacyVNodeProperties(vnode: VNode) {
+  /* istanbul ignore if */
   if (
     isCompatEnabled(
       DeprecationTypes.RENDER_FUNCTION,

+ 20 - 0
packages/vue-compat/__tests__/componentAsync.spec.ts

@@ -59,4 +59,24 @@ describe('COMPONENT_ASYNC', () => {
       )
     ).toHaveBeenWarned()
   })
+
+  test('object syntax', async () => {
+    const comp = () => ({
+      component: Promise.resolve({ template: 'foo' })
+    })
+
+    const vm = new Vue({
+      template: `<div><comp/></div>`,
+      components: { comp }
+    }).$mount()
+    expect(vm.$el.innerHTML).toBe(`<!---->`)
+    await timeout(0)
+    expect(vm.$el.innerHTML).toBe(`foo`)
+
+    expect(
+      (deprecationData[DeprecationTypes.COMPONENT_ASYNC].message as Function)(
+        comp
+      )
+    ).toHaveBeenWarned()
+  })
 })

+ 47 - 0
packages/vue-compat/__tests__/global.spec.ts

@@ -1,5 +1,6 @@
 import Vue from '@vue/compat'
 import { effect, isReactive } from '@vue/reactivity'
+import { nextTick } from '@vue/runtime-core'
 import {
   DeprecationTypes,
   deprecationData,
@@ -333,4 +334,50 @@ describe('GLOBAL_PRIVATE_UTIL', () => {
       deprecationData[DeprecationTypes.GLOBAL_PRIVATE_UTIL].message
     ).toHaveBeenWarned()
   })
+
+  test('defineReactive on instance', async () => {
+    const vm = new Vue({
+      beforeCreate() {
+        // @ts-ignore
+        Vue.util.defineReactive(this, 'foo', 1)
+      },
+      template: `<div>{{ foo }}</div>`
+    }).$mount() as any
+    expect(vm.$el.textContent).toBe('1')
+    vm.foo = 2
+    await nextTick()
+    expect(vm.$el.textContent).toBe('2')
+  })
+
+  test('defineReactive with object value', () => {
+    const obj: any = {}
+    const val = { a: 1 }
+    // @ts-ignore
+    Vue.util.defineReactive(obj, 'foo', val)
+
+    let n
+    effect(() => {
+      n = obj.foo.a
+    })
+    expect(n).toBe(1)
+    // mutating original
+    val.a++
+    expect(n).toBe(2)
+  })
+
+  test('defineReactive with array value', () => {
+    const obj: any = {}
+    const val = [1]
+    // @ts-ignore
+    Vue.util.defineReactive(obj, 'foo', val)
+
+    let n
+    effect(() => {
+      n = obj.foo.length
+    })
+    expect(n).toBe(1)
+    // mutating original
+    val.push(2)
+    expect(n).toBe(2)
+  })
 })

+ 22 - 2
packages/vue-compat/__tests__/renderFn.spec.ts

@@ -123,9 +123,29 @@ describe('compat: render function', () => {
       })
     ).toMatchObject({
       props: {
-        onClick: fn, // should dedupe
+        onClick: fn,
+        onClickNative: fn,
         onFooBar: fn,
-        'onBar-baz': fn
+        'onBar-bazNative': fn
+      }
+    })
+  })
+
+  test('v2 legacy event prefixes', () => {
+    const fn = () => {}
+    expect(
+      h('div', {
+        on: {
+          '&click': fn,
+          '~keyup': fn,
+          '!touchend': fn
+        }
+      })
+    ).toMatchObject({
+      props: {
+        onClickPassive: fn,
+        onKeyupOnce: fn,
+        onTouchendCapture: fn
       }
     })
   })