Ответ 1
Как правило, внутри методов, или вычисляемых свойств или обработчиков жизненного цикла в Vue, вы будете использовать this
для ссылки на компонент, к которому присоединен метод /computed/handler. this
относится к контексту, в котором функция в настоящее время выполняется.
При использовании this
метода возникают проблемы, когда в контексте текущей функции объявляется новая функция, как это происходит при написании обратного вызова для обещания (axios.post
, axios.get
). Рассмотрим этот код:
AddTicket: function () {
// "this", on this line, refers to the Vue
// and you can safely use "this" to get any of the
// data properties of the Vue
axios.post('/api/Tickets', ...)
.then(function (response) {
// "this" HERE, does NOT refer to the Vue!!
// The reason why explained below
})
}
В приведенном выше коде первый комментарий может быть заменен кодом, который использует this
для получения свойств данных или вызова методов Vue (this.tickets
). Второй комментарий, однако, находится внутри нового контекста функции, и this
НЕ будет ссылаться на Vue. Это связано с тем, что в Javascript, когда вы объявляете новую функцию с использованием синтаксиса function() {}
, эта функция имеет собственный контекст функции, который отличается от функции, в которой она объявлена.
Есть несколько способов справиться с этим в Javascript. Чаще всего в эти дни либо использовать замыкание, чтобы захватить правильное this
, или использовать функцию стрелки. Рассмотрим этот код:
AddTicket: function () {
// As before, "this" here is the Vue
axios.post('/api/Tickets', ...)
.then((response) => {
// "this" HERE is ALSO the Vue
})
}
Обратите внимание, что в этом примере обратный вызов определяется с помощью функции стрелки (() => {}
). Функции стрелок НЕ создают свой собственный контекст функции и используют контекст, в котором они объявлены. Это также известно как наличие лексической области.
Другой наиболее распространенный обходной путь - использование замыкания.
AddTicket: function () {
const self = this // Here we save a reference to the "this" we want
axios.post('/api/Tickets', ...)
.then(function(response){
// and HERE, even though the context has changed, and we can't use
// "this", we can use the reference we declared (self) which *is*
// pointing to the Vue
self.tickets = response
})
}
Наконец, вы можете использовать метод bind для создания функции со специфическим this
, хотя в наши дни это не так часто встречается при наличии функций стрелок.
AddTicket: function () {
axios.post('/api/Tickets', ...)
.then(function(response){
this.tickets = response
}.bind(this)) // NOTE the ".bind(this)" added to the end of the function here
}
Практически ни в коем случае не следует ли вам действительно делать то, что вы делаете в своем вопросе: сохранить ссылку на Vue в переменной vm
и использовать эту переменную внутри самого объекта Vue. Это плохая практика.
В любом случае, как использовать правильно this
подробно описано в многочисленных сообщениях по всему Интернету и здесь, fooobar.com/questions/1337/..., а также.
Наконец, вот код вопроса, пересмотренный так, что this
должно использоваться правильно.
var vm = new Vue({
el: '#app',
data: {
tickets: [],
top: 100,
search: '',
showAdd: false,
ticket: null
},
mounted: function () {
// there is no need for $nextTick here
this.GetTickets(100)
},
methods: {
GetTickets: function (top) {
axios.get('/api/Tickets', { params: { Top: top }})
.then(response => this.tickets = response.data)
.catch(error => console.log(error));
},
ClearTicket: function () {
var t = {
"ticketSubject": '',
"contactName": '',
"createdAt": moment()
}
this.ticket = t;
this.showAdd = !this.showAdd;
},
AddTicket: function () {
axios.post('/api/Tickets', this.ticket)
.then(() => this.GetTickets(100))
.catch(error => console.log(error));
this.showAdd = false;
}
},
})