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

Pet*_*rch 5 vue.js vuejs2

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

您可以在大多数情况下使用普通的 JavaScript 语法,除了仅调用方法和引用 props 或计算 props 并且您不需要this任何地方。有点...

其他优秀的vue 文档在这里并不是很有帮助。我已经习惯了写:

<foo-bar @someevent="method"/>
Run Code Online (Sandbox Code Playgroud)

乃至

<foo-bar @someevent="event => method('someArg', event)"/>
Run Code Online (Sandbox Code Playgroud)

但它一直困扰着我,我不需要this在那里,并且全局函数不能像以下那样工作:

<foo-bar @someevent="console.log"/>
Run Code Online (Sandbox Code Playgroud)

给出:属性或方法“控制台”未在实例上定义,但在渲染期间引用

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

具体来说,我注意到这两个工作:

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

但不是

<foo-bar @someevent="(...args) => $emit('someevent', ...args)"/>
Run Code Online (Sandbox Code Playgroud)

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

为什么那不起作用,当上述两个起作用时?

我猜我不明白为什么最后一个例子失败的原因是因为我没有从根本上理解v-on属性是如何工作的,为什么全局函数不起作用以及我怎么可能不需要this任何地方。

我想这只是模板语法的一个特例,但阅读它仍然没有让我有深刻理解的感觉......

小智 3

Vue.js 模板编译器在评估模板内的表达式时有点作弊。我不认为它在文档中,并且正如您所描述的那样,它在直观层面上工作得足够好,也许这是一个需要在文档中正确描述的主题。

如果您想了解 Vue.js 模板编译器的一般工作原理,Evan You(Vue.js 作者)提供了一个易于理解的演讲,并提供了一个交互式工具,可让您查看模板编译的结果。请注意模板资源管理器右上角的“strip this”复选框,因为很容易错过渲染函数中的with(this){ ... }表达式。

问题是模板编译器(在编写 v2.6.10 时)使用几个正则表达式检查 v-on 子句的内容,并根据哪个正则表达式与内容匹配来编写处理程序函数。因此,您的表达式不会在运行时被某种 JS 编译器处理为 AST,以确定它是什么类型的表达式,它只是快速放入四个桶之一。但它buble由之前调用的转译器处理的,该转译器处理扩展运算符、箭头函数和其他 ES2015 功能。

下面是我对代码的理解,你可以在这里看到

一、Expression是方法路径,即直接传递方法处理程序

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

二. 表达式是函数表达式

<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
      */
    }
  }
})
Run Code Online (Sandbox Code Playgroud)

三.表达式是函数调用

<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
      */
    }
  }
})
Run Code Online (Sandbox Code Playgroud)

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
  }
 }
})
Run Code Online (Sandbox Code Playgroud)

四.表达式是一个“原始表达式”(基本上,以上都不是)

<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
    }
  }
})
Run Code Online (Sandbox Code Playgroud)

重申一下,Vue 模板编译器使用了一些故意的技巧来最大限度地减少框架用户需要编写的代码,但是当用户开始在处理程序中放入更复杂的表达式时,它的代价是丢失一些更精细的细节