Vue еквівалент setTimeout?


80

Я створюю систему кошиків для покупок з Laravel та Vue. Коли я додаю товар у кошик, я відображаю повідомлення підтвердження, перемикаючи змінну Vue, яку спостерігає v-if:

<div class="alert alert-success" v-if="basketAddSuccess" transition="expand">Added to the basket</div>

І JS:

addToBasket: function(){
                item = this.product;
                this.$http.post('/api/buy/addToBasket', item);
                this.basketAddSuccess = true;
            }

(І так, незабаром я додаю це в тодішньому улові).

Це працює нормально, і повідомлення з’являється. Однак я хотів би, щоб повідомлення знову зникло через певний час, скажімо, кілька секунд. Як я можу це зробити за допомогою Vue? Я пробував, setTimeOutале Vue, схоже, не подобається, кажучи, що це невизначено.

EDIT: Я неправильно писав, setTimeoutяк ідіот. Однак це все одно не працює:

Моя функція:

addToBasket: function(){
                item = this.photo;
                this.$http.post('/api/buy/addToBasket', item);
                this.basketAddSuccess = true;
                setTimeout(function(){
                    this.basketAddSuccess = false;
                }, 2000);
            }

8
спробуватиsetTimeout(()=>{ this.basketAddSuccess = false; }, 2000);
Олександр Фаркас

3
Можливо, thisвсередині the setTimeoutне посилається на основний об'єкт.
akinuri

@alexanderfarkas це працює, дякую!
flurpleplurple

@akinuri Використання ES6 та функції стрілки thisповинно посилатися на правильний обсяг. Це була проблема, перш ніж вирішувати з типовим var self=this. Будь ласка, виправте мене, якщо я помиляюсь. Не перевірено.
ibsenleo

Було б круто отримати відповідь на "Vue еквівалент setTimeOut?" - але замість цього ми маємо набір регулярних відповідей "як це працює" у ситуації setTimeout. Я все ще шукаю відповідь, яка спеціально використовує Vue - замість того, щоб передавати події в стек.
sheriffderek

Відповіді:


112

Функція стрілки

Найкращий і найпростіший спосіб вирішити цю проблему - за допомогою функції стрілки () => {}:

    addToBasket() {
        var item = this.photo;
        this.$http.post('/api/buy/addToBasket', item);
        this.basketAddSuccess = true;
        // now 'this' is referencing the Vue object and not the 'setTimeout' scope
        setTimeout(() => this.basketAddSuccess = false, 2000);
    }

Це працює , тому що thisфункції стрілки , прив'язані до thisйого області видимості - в Vue, це / огороджувальні компоненти батька. setTimeoutОднак усередині традиційної функції, що викликається ,, thisпосилається на windowоб'єкт (саме тому у вас виникли помилки при спробі отримати доступ this.basketAddSuccessу цьому контексті).

Аргумент передається

Іншим способом зробити це буде передача thisяк аргументу вашої функції через setTimeoutпрототип '', використовуючи її setTimeout(callback, delay, arg1, arg2, ...)форму:

    addToBasket() {
        item = this.photo;
        this.$http.post('/api/buy/addToBasket', item);
        this.basketAddSuccess = true;
        //Add scope argument to func, pass this after delay in setTimeout
        setTimeout(function(scope) {
             scope.basketAddSuccess = false;
        }, 2000, this);
    }

(Варто зазначити, що синтаксис передачі аргументів несумісний з IE 9 і нижче, однак.)

Місцева змінна

Інший можливий , але менш красномовний і менш заохочуваний спосіб - це прив’язати thisдо var поза setTimeout:

    addToBasket() {
        item = this.photo;
        this.$http.post('/api/buy/addToBasket', item);
        this.basketAddSuccess = true;
        //Declare self, which is accessible inside setTimeout func
        var self = this;
        setTimeout(function() {
             self.basketAddSuccess = false;
        }, 2000);
    }

Однак використання функції стрілки повністю виключить потребу в цій додатковій змінній, і насправді її слід використовувати, якщо щось інше не перешкоджає її використанню.


17
Для цього слід використовувати функцію стрілки, а не self для посилання на це
glaba

Що робити, якщо користувач тим часом змінює компонент / сторінку, а поточний (цей / сам ...) компонент знищується?
robert.little

Якщо вам потрібна більш складна обробка поведінки, з тайм-аутом / очікуванням, скасуванням обробки, зміною сторінки, зняттям зобов’язань тощо. краще використовувати щось на зразок RxJS або подібне. Ви можете розпочати тут: rxmarbles.com
g.annunziata

Функція стрілки не працює в IE11 і нижче. Два останні рішення роблять.
Luboš Miřatský

96

зіткнувшись з тією ж проблемою, я опинився в цій темі. Для майбутнього покоління: поточна найбільш голосована відповідь намагається прив’язати „це” до змінної, щоб уникнути зміни контексту при виклику функції, визначеної в setTimeout.

Альтернативний та більш рекомендований підхід (з використанням Vue.JS 2.2 та ES6) полягає у використанні функції стрілки для прив’язки контексту до батьківського елемента (в основному „addToBasket“ s „this“ та „setTimeout“ s „this“ все одно посилався б на той самий об'єкт):

addToBasket: function(){
        item = this.photo;
        this.$http.post('/api/buy/addToBasket', item);
        this.basketAddSuccess = true;
        setTimeout(() => {
            this.basketAddSuccess = false;
        }, 2000);
    }

2
"Заради майбутнього покоління"!
Fábio ZC

24

Додайте bind (this) до функції зворотного виклику setTimeout

setTimeout(function () {
    this.basketAddSuccess = false
}.bind(this), 2000)

2
Дякую - через 3 роки це було великою допомогою.
Трей Тайлер


4

Ви можете використовувати Vue.nextTick

addToBasket: function(){
                item = this.photo;
                this.$http.post('/api/buy/addToBasket', item);
                this.basketAddSuccess = true;
                Vue.nextTick(() =>{
                    this.basketAddSuccess = false;
                });
            }

Це, навіть якби це спрацювало, негайно закрило б div.
gurghet

Ви можете обернути nexTick під setTimeout
Самундра Хатрі

2
@SamundraKhatri Ви можете отримати голоси за свою відповідь, якщо ви відповіли на запитання, а не сказали в коментарі "ви можете робити те, що запитання задає".
Джаред Тірск,

4

vuejs 2

спочатку додайте це до методів

methods:{
    sayHi: function () {
      var v = this;
      setTimeout(function () {
        v.message = "Hi Vue!";
    }, 3000);
   }

після цього викличте цей метод на mount

mounted () {
  this.sayHi()
}

4

Кевін Мухват вище має КРАЩУ відповідь, незважаючи на лише 10 голосів проти і не вибрану відповідь.

setTimeout(function () {
    this.basketAddSuccess = false
}.bind(this), 2000)

Дозвольте пояснити, ЧОМУ.

"Функція стрілки" - це ECMA6 / ECMA2015. Це чудово діє в складеному коді або в контрольованих ситуаціях клієнта (додатки для телефонів cordova, Node.js), і це приємно і лаконічно. Це навіть, мабуть, пройде ваше тестування!

Однак, Microsoft у своїй нескінченній мудрості вирішив, що Internet Explorer НІКОЛИ НЕ ПІДТРИМУЄ ECMA2015!

Їхній новий браузер Edge працює, але це недостатньо добре для веб-сайтів, що стоять перед громадськістю.

Виконання стандартної функції () {} та додавання .bind (це), однак, є синтаксисом ECMA5.1 (який ІС повністю підтримується) для точно тієї ж функціональності.

Це також важливо у викликах ajax / post .then / else. В кінці вашого .then (функція) {}) вам також потрібно прив’язати (this), так що: .then (function () {this.flag = true} .bind (this))

Я б додав це як коментар до відповіді Кевіна, але з якихось дурних причин публікує відповіді менше балів, ніж коментує відповіді

НЕ ПОВИНЮЙТЕ ТУЮ САМУ ПОМИЛКУ, ЯКУ Я ПОРУШИВ!

Я кодую на Mac і використовую коментарі, які проголосували за 48 балів, що чудово працювало! Поки мені не дзвонили на мої сценарії, і я не міг зрозуміти, чому. Мені довелося повернутися назад і оновити десятки викликів із синтаксису стрілки до функції () {}. Bind (цей) синтаксис.

На щастя, я знову знайшов цю тему та отримав правильну відповідь. Кевіне, я вічно вдячний.

Відповідно до "Прийнятої відповіді", це має інші потенційні проблеми, пов'язані з додатковими бібліотеками (мали проблеми з належним доступом / оновленням властивостей / функцій Vue)


2
Коли Edge переходить до Chromium, досить скоро це не буде проблемою (нарешті)
Дейв,

Час рухатись далі. :)
sheriffderek

1
@dave Не впевнений, як це має значення, коли аргумент полягає в тому, що IE цього не підтримує. Edge підтримує це з 2015 року
FINDarkside

І ви завжди можете використовувати перекладач EcmaScript, такий як babel, щоб перетворити функції стрілок на підтримку IE.
A1rPun

3

У цьому немає необхідності bind(this) коли ви використовуєте функції стрілок:

  setTimeout( ()=> {
    // some code
   }, 500)

3

Якщо ви хочете використовувати це ключове слово у своїй функції, вам потрібно написати функцію setTimeout у ES6

setTimeout(() => {
   this.filters.max_budget_gt_eq = this.budgetHigherValue;
}, 1000);

3

Функція стрілки

Найкращий і найпростіший спосіб вирішити цю проблему - за допомогою функції стрілки () => {}:

    addToBasket() {
        var item = this.photo;
        this.$http.post('/api/buy/addToBasket', item);
        this.basketAddSuccess = true;
        // now 'this' is referencing the Vue object and not the 'setTimeout' scope
        setTimeout(() => this.basketAddSuccess = false, 2000);
    }

Це працює , тому що thisфункції стрілки , прив'язані до thisйого області видимості - в Vue, це / огороджувальні компоненти батька. setTimeoutОднак усередині традиційної функції, що викликається ,, thisпосилається на windowоб'єкт (саме тому у вас виникли помилки при спробі отримати доступ this.basketAddSuccessу цьому контексті).

Аргумент передається

Іншим способом зробити це буде передача thisяк аргументу вашої функції через setTimeoutпрототип '', використовуючи її setTimeout(callback, delay, arg1, arg2, ...)форму:

    addToBasket() {
        item = this.photo;
        this.$http.post('/api/buy/addToBasket', item);
        this.basketAddSuccess = true;
        //Add scope argument to func, pass this after delay in setTimeout
        setTimeout(function(scope) {
             scope.basketAddSuccess = false;
        }, 2000, this);
    }

(Варто зазначити, що синтаксис передачі аргументів несумісний з IE 9 і нижче, однак.)


0

використовуйте this.animationStop, а не використовуйте this.animationStop ()

animationRun(){
    this.sliderClass.anim = true;
    setTimeout(this.animationStop, 500);
},

0

Ймовірно, це питання сфери застосування. Спробуйте замість цього:

addToBasket: function(){
    item = this.photo;
    this.$http.post('/api/buy/addToBasket', item);
    this.basketAddSuccess = true;
    var self = this;
    setTimeout(function(){
        self.basketAddSuccess = false;
    }, 2000);
}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.