소스 검색

support v-on .native modifier on components

Evan You 9 년 전
부모
커밋
ea9c6c37c3
7개의 변경된 파일32개의 추가작업 그리고 7개의 파일을 삭제
  1. 1 0
      flow/compiler.js
  2. 2 1
      flow/vnode.js
  3. 2 2
      src/compiler/codegen/events.js
  4. 3 0
      src/compiler/codegen/index.js
  5. 7 1
      src/compiler/helpers.js
  6. 2 3
      src/core/vdom/create-component.js
  7. 15 0
      test/unit/features/directives/on.spec.js

+ 1 - 0
flow/compiler.js

@@ -102,6 +102,7 @@ declare type ASTElement = {
   styleBinding?: string,
   hooks?: ASTElementHooks,
   events?: ASTElementHandlers,
+  nativeEvents?: ASTElementHandlers,
 
   transition?: string | true,
   transitionOnAppear?: boolean,

+ 2 - 1
flow/vnode.js

@@ -44,7 +44,8 @@ declare interface VNodeData {
   domProps?: { [key: string]: any };
   staticAttrs?: { [key: string]: string };
   hook?: { [key: string]: Function };
-  on?: { [key: string]: Function | Array<Function> };
+  on?: ?{ [key: string]: Function | Array<Function> };
+  nativeOn?: { [key: string]: Function | Array<Function> };
   transition?: Object;
   inlineTemplate?: {
     render: Function,

+ 2 - 2
src/compiler/codegen/events.js

@@ -21,8 +21,8 @@ const modifierCode = {
   self: 'if($event.target !== $event.currentTarget)return;'
 }
 
-export function genHandlers (events: ASTElementHandlers): string {
-  let res = 'on:{'
+export function genHandlers (events: ASTElementHandlers, native?: boolean): string {
+  let res = native ? 'nativeOn:{' : 'on:{'
   for (const name in events) {
     res += `"${name}":${genHandler(events[name])},`
   }

+ 3 - 0
src/compiler/codegen/index.js

@@ -166,6 +166,9 @@ function genData (el: ASTElement): string | void {
   if (el.events) {
     data += `${genHandlers(el.events)},`
   }
+  if (el.nativeEvents) {
+    data += `${genHandlers(el.nativeEvents, true)}`
+  }
   // inline-template
   if (el.inlineTemplate) {
     const ast = el.children[0]

+ 7 - 1
src/compiler/helpers.js

@@ -52,12 +52,18 @@ export function addHandler (
   value: string,
   modifiers: ?{ [key: string]: true }
 ) {
-  const events = el.events || (el.events = {})
   // check capture modifier
   if (modifiers && modifiers.capture) {
     delete modifiers.capture
     name = '!' + name // mark the event as captured
   }
+  let events
+  if (modifiers && modifiers.native) {
+    delete modifiers.native
+    events = el.nativeEvents || (el.nativeEvents = {})
+  } else {
+    events = el.events || (el.events = {})
+  }
   const newHandler = { value, modifiers }
   const handlers = events[name]
   /* istanbul ignore if */

+ 2 - 3
src/core/vdom/create-component.js

@@ -89,9 +89,8 @@ export function createComponent (
   // extract listeners, since these needs to be treated as
   // child component listeners instead of DOM listeners
   const listeners = data.on
-  if (listeners) {
-    delete data.on
-  }
+  // replace with listeners with .native modifier
+  data.on = data.nativeOn
 
   // return a placeholder vnode
   const name = Ctor.options.name || tag

+ 15 - 0
test/unit/features/directives/on.spec.js

@@ -152,6 +152,21 @@ describe('Directive v-on', () => {
     expect(spy).toHaveBeenCalledWith('foo', 'bar')
   })
 
+  it('should be able to bind native events for a child component', () => {
+    Vue.component('bar', {
+      template: '<span>Hello</span>'
+    })
+    vm = new Vue({
+      el,
+      template: '<bar @click.native="foo"></bar>',
+      methods: { foo: spy }
+    })
+    vm.$children[0].$emit('click')
+    expect(spy).not.toHaveBeenCalled()
+    triggerEvent(vm.$children[0].$el, 'click')
+    expect(spy).toHaveBeenCalled()
+  })
+
   it('remove listener', done => {
     const spy2 = jasmine.createSpy('remove listener')
     vm = new Vue({