为什么我的Vue方法没有引用正确的上下文(数据)?
当addTodo
被触发,我检查其中的this
,上下文是浏览器窗口,而不是data
对象。因此todos
最终未定义。为什么我的Vue方法没有引用正确的上下文(数据)?
任何想法我失踪?
HTML:
<div id="todo-list">
<input type="text" v-model="newTodo">
<button v-on:click="addTodo">Add</button>
<ul>
<li v-if="todos.length" v-for="todo in todos" class="todo-item">
{{ todo }}
</li>
</ul>
</div>
JS:
new Vue({
el: '#todo-list',
data: {
todos: [],
newTodo: ''
},
methods: {
addTodo:() => {
this.todos.push(this.newTodo);
this.clearNewTodo();
},
clearNewTodo:() => {
this.newTodo = '';
}
}
});
快速修复:don't use arrow functions to declare your Vue methods.
什么问题?
你期待的ES6箭头功能() => {}
语法来设置上下文(this
)一样的旧函数声明语法function() {}
会。
这是为什么?
从MDN:
直到箭头的功能,每一个新的功能定义了自己的这个值(在构造函数中,在严格模式下的函数调用不确定的情况下,一个新的对象,上下文对象,如果被调用的函数作为“对象方法”等)。事实证明,这是一种面向对象的编程风格。
所以,你的方法对象应该是这样的(使用旧的函数语法):
methods: {
addTodo: function() {
this.todos.push(this.newTodo);
this.clearNewTodo();
},
clearNewTodo: function() {
this.newTodo = '';
}
}
或者这(使用new method definition syntax)
methods: {
addTodo() {
this.todos.push(this.newTodo);
this.clearNewTodo();
},
clearNewTodo() {
this.newTodo = '';
}
}
我不知道大约是关于Vue.js如何设置/处理上下文的情况,但是看起来您的方法正在从您的模板/ DOM中调用,并且上下文将从那里传递到您的方法中。由于箭头函数继承其上下文,因此this
引用window
对象。
使用实际函数声明将保留对您想要的this
的适当引用。
您可以改为使用'addTodo(){...}'。 –
@BillCriswell你是对的 - 无论如何,这完全是es6。好决定。相应更新。 –
它看起来像ES6箭头语法是你的问题。将其更改为使用传统的()函数的语法,它会工作:
addTodo: function() {
this.todos.push(this.newTodo);
this.clearNewTodo();
},
clearNewTodo: function() {
this.newTodo = '';
}
啊太晚了!当我打字时,你已经明白了! :) – SteveB
另外OP可以使用'addTodo()'而不是'addTodo:function(){'如果简洁是他的顾虑。 –
你的箭头Vue的方法已经得到this
对象作为第一个参数,所以:
methods: {
addTodo: (_this) => {
_this.todos.push(_this.newTodo);
_this.clearNewTodo();
},
clearNewTodo: (_this) => {
_this.newTodo = '';
}
}
的伎俩,但我不知道,箭头的功能都在这里贡献什么。
为什么使用addTodo:()=> {而不是addTodo:function(){} - 无论如何你的代码是正确的,this.todos应该被定义。尝试比较你的代码和示例:https://vuejs.org/examples/svg.html – Xatenev
@Xatenev我想我觉得它更短,更干净。这是ES6。但是,您提到的这一点提醒我,设置上下文(this)时,ES6箭头函数与旧函数语法的行为不同,并且将其更改为旧语法可以修复问题。除非你这么做,否则我会写一个答案来解释为什么这个工作在一秒钟内完成。 –
'()=>'将'this'的值更改为封闭的上下文。在这种情况下,'this'可能等于'window'。这是你的问题。如果你想简洁一些,你可以使用'addTodos(){}'而不是'addTodos:function(){}'。 –