为什么在v-on属性值中不需要`this`?

时间:2019-07-12 06:32:32

标签: vue.js vuejs2

除了我目前的理解之外,v-on属性的v-on属性语法是否还有更精确的规范? :

  

除了调用方法和引用道具或计算道具外,您大部分都可以使用普通的JavaScript语法,并且您在任何地方都不需要this。有点...

原本出色的vue docs在这里不是很有帮助。我已经习惯于写作:

<foo-bar @someevent="method"/>

甚至

<foo-bar @someevent="event => method('someArg', event)"/>

但这总是让我感到困惑,因为我不需要this,并且全局函数不能像以下那样工作:

<foo-bar @someevent="console.log"/>

给出:属性或方法“控制台”未在实例上定义,但在渲染过程中被引用。

这些v-on属性如何工作,它们的语法是什么-真的吗?深入吗?

我确实注意到这两项工作:

<foo-bar @someevent="(event) => $emit('someevent', event)"/>
<foo-bar @someevent="(...args) => reEmitMethod('someevent', ...args)"/>

但不是

<foo-bar @someevent="(...args) => $emit('someevent', ...args)"/>

给出了神秘的错误消息: [Vue警告]:v-on处理程序中的错误:“ TypeError:vm is undefined”

为什么当上面两个都行的时候那行不通?

我猜测我不明白上一个示例失败的原因是因为我从根本上不了解v-on属性如何工作,全局函数为何不工作以及这种可能性我不需要this

我想这只是template syntax的特例,但阅读仍然没有使我产生深刻的理解...

1 个答案:

答案 0 :(得分:2)

Vue.js模板编译器在评估模板内部的表达式时会作弊。我不认为它存在于文档中,并且如您所描述的那样,它在直观的水平上已经足够好了,也许这是需要在文档中适当描述的主题。

如果您想了解Vue.js模板编译器的总体工作方式,可以使用comprehensible talk by Evan You (Vue.js author)interactive tool来完善模板编译的结果。请注意,模板浏览器右上角的“为此分隔”复选框,因为很容易错过渲染功能中的with(this){ ... }表达式。

问题是模板编译器(在编写v2.6.10时)使用几个正则表达式检查v-on子句的内容,并根据哪个regexp与内容匹配来编写处理程序函数。因此,您的表达式不会在运行时出于某种目的而被某种JS编译器处理为AST 的目的,只是很快就被放入四个存储桶之一。但是它先由名为buble的编译器进行处理,该编译器处理传播算子,箭头功能和其他ES2015功能。

下面是我对代码的理解,you can see here

I。表达式是方法路径,这意味着方法处理程序将直接传递

<div @click="method"></div>
// compiled to
return _c('div', {
  on: {
    "click": method
  }
})

II。表达式是函数表达式

<div  @click="function() { console.log('why do I fail?') }"></div>
// compiled to (using with)
return _c('div', {
  on: {
    "click": function () {
      console.log('why do I fail?')
      /*
        console is no longer in your global scope replaced by rendering context
        arguments can be defined in this function definition
      */
    }
  }
})

III。表达式是函数调用

<div @click="method(myOtherArgument)"></div>
// compiled to
return _c('div', {
  on: {
    "click": function ($event) {
      return method(myOtherArgument)
      /*
        this is why you usually want to call method with
        $event to pass event with some other argument, because $event is in lexical scope
      */
    }
  }
})

IIIa。 ES2015函数调用

<div @click="(...args) => $emit('someevent', ...args)">Why do I fail?</div>
// transpiled (not using with!)
return _c('div', {
 on: {
  "click": function () {
    var args = [],
      len = arguments.length;
    while (len--) args[len] = arguments[len];

    return _vm.$emit.apply(void 0, ['someevent'].concat(args));
    // apply gets called with undefined as its first argument, looks like a bug
  }
 }
})

IV。表达式是一个“原始表达式”(基本上,上述都不是)

<div  @click="method && method"></div>
// compiled to
return _c('div', {
  on: {
    "click": function ($event) { // note that $event has appeared in function definition
      method && method // note no 'return' statement
    }
  }
})

重申一下,Vue模板编译器使用了两个故意的技巧来最小化框架用户需要编写的代码,但是当用户开始在其中添加更复杂的表达式时,这样做的代价是会丢失一些更详细的信息。处理程序