Vue-Äquivalent zu setTimeout?

75

Ich mache mit Laravel und Vue ein Warenkorbsystem. Wenn ich einen Artikel in den Warenkorb lege, wird eine Bestätigungsmeldung angezeigt, indem eine Vue-Variable umgeschaltet wird, die von einem v-if überwacht wird:

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

Und der JS:

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

(Und ja, ich werde dies in Kürze in einem Dann-Fang hinzufügen).

Dies funktioniert gut und die Meldung wird angezeigt. Ich möchte jedoch, dass die Nachricht nach einer bestimmten Zeit wieder verschwindet, beispielsweise nach einigen Sekunden. Wie kann ich das mit Vue machen? Ich habe es versucht, setTimeOutaber Vue scheint es nicht zu mögen und sagt, es sei undefiniert.

EDIT: Ich habe falsch geschrieben setTimeoutwie ein Idiot. Es funktioniert jedoch immer noch nicht:

Meine Funktion ist jetzt:

addToBasket: function(){
                item = this.photo;
                this.$http.post('/api/buy/addToBasket', item);
                this.basketAddSuccess = true;
                setTimeout(function(){
                    this.basketAddSuccess = false;
                }, 2000);
            }
flurpleplurple
quelle
8
versuchensetTimeout(()=>{ this.basketAddSuccess = false; }, 2000);
Alexander Farkas
3
Wahrscheinlich thisinnerhalb der setTimeoutbezieht sich nicht auf das Hauptobjekt.
Akinuri
@alexanderfarkas das funktioniert, danke!
flurpleplurple
@akinuri Die Verwendung der ES6- und Pfeilfunktion thissollte sich auf den richtigen Bereich beziehen. Dies war ein Problem, das zuvor mit dem typischen gelöst wurde var self=this. Bitte korrigiere mich wenn ich falsch liege. Nicht getestet.
Ibsenleo
Es wäre cool, eine Antwort auf "Vue-Äquivalent von setTimeOut?" - Stattdessen haben wir eine Reihe regelmäßiger Antworten darauf , wie dies in einer setTimeout-Situation funktioniert. Ich suche immer noch nach einer Antwort, die speziell Vue verwendet - anstatt Ereignisse an den Stapel zu übergeben.
Sheriffderek

Antworten:

107

Pfeilfunktion

Der beste und einfachste Weg, um dieses Problem zu lösen, ist die Verwendung einer Pfeilfunktion () => {}:

    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);
    }

Dies funktioniert , weil die thisPfeilfunktionen an den gebundenen thisseinen umschließenden Umfang - in Vue, dass die Eltern / umschließenden Komponente ist. Innerhalb einer traditionellen Funktion, die von aufgerufen wird setTimeout, wird jedoch thisauf das windowObjekt verwiesen (weshalb beim Versuch, this.basketAddSuccessin diesem Kontext auf etwas zuzugreifen , Fehler aufgetreten sind).

Argument übergeben

Eine andere Möglichkeit, dies zu tun, besteht darin, thisals Argument an Ihre Funktion durch setTimeoutden Prototyp zu übergeben , der dessen setTimeout(callback, delay, arg1, arg2, ...)Form verwendet:

    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);
    }

(Es ist jedoch anzumerken, dass die Arg-Passing-Syntax nicht mit IE 9 und niedriger kompatibel ist.)

Lokale Variable

Ein anderer möglicher , aber weniger beredter und weniger ermutigter Weg besteht darin, sich thisan eine Var außerhalb von zu binden 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);
    }

Die Verwendung einer Pfeilfunktion würde die Notwendigkeit dieser zusätzlichen Variablen jedoch vollständig beseitigen und sollte wirklich verwendet werden, es sei denn, etwas anderes verhindert ihre Verwendung.

g.annunziata
quelle
17
Dies sollte eine
Pfeilfunktion verwenden,
Was ist, wenn der Benutzer währenddessen die Komponente / Seite ändert und die aktuelle (diese / selbst ...) Komponente zerstört wird?
robert.little
Wenn Sie eine komplexere Verhaltensbehandlung mit Timeout / Wartezeit benötigen, brechen Sie die Behandlung ab, wechseln Sie die Seite, entprellen Sie, ecc. Verwenden Sie besser etwas wie RxJS oder ähnliches. Sie können hier beginnen: rxmarbles.com
g.annunziata
Die Pfeilfunktion funktioniert in IE11 und darunter nicht. Die beiden letztgenannten Lösungen tun dies.
Luboš Miřatský
95

Nachdem ich auf dasselbe Problem gestoßen war, landete ich in diesem Thread. Für die zukünftige Generation: Die aktuell am häufigsten gewählte Antwort versucht, "dies" an eine Variable zu binden, um zu vermeiden, dass der Kontext beim Aufrufen der im setTimeout definierten Funktion geändert wird.

Ein alternativer und empfohlener Ansatz (unter Verwendung von Vue.JS 2.2 und ES6) besteht darin, eine Pfeilfunktion zu verwenden, um den Kontext an das übergeordnete Element zu binden (im Grunde "this" von "addToBasket" und "this" von "setTimeout") würde sich immer noch auf dasselbe Objekt beziehen):

addToBasket: function(){
        item = this.photo;
        this.$http.post('/api/buy/addToBasket', item);
        this.basketAddSuccess = true;
        setTimeout(() => {
            this.basketAddSuccess = false;
        }, 2000);
    }
Samuel Bergström
quelle
2
"Um der zukünftigen Generation willen"!
Fábio ZC
21

Fügen Sie bind (this) zu Ihrer setTimeout-Rückruffunktion hinzu

setTimeout(function () {
    this.basketAddSuccess = false
}.bind(this), 2000)
Kevin Muchwat
quelle
1
Vielen Dank - 3 Jahre später war dies eine große Hilfe.
Trey Tyler
16

ES6 kann 'dies' binden

setTimeout(() => {

 },5000);

陈奕 璇
quelle
4

Sie können Vue.nextTick verwenden

addToBasket: function(){
                item = this.photo;
                this.$http.post('/api/buy/addToBasket', item);
                this.basketAddSuccess = true;
                Vue.nextTick(() =>{
                    this.basketAddSuccess = false;
                });
            }
Samundra Khatri
quelle
Dies würde, selbst wenn es funktionieren würde, die Div sofort schließen.
Gurghet
Sie können nexTick unter setTimeout
Samundra Khatri
2
@SamundraKhatri Sie können möglicherweise positive Stimmen für Ihre Antwort erhalten, wenn Sie die Frage beantwortet haben, anstatt in einem Kommentar zu sagen: "Sie können tun, was die Frage verlangt".
Jared Thirsk
4

vuejs 2

Fügen Sie dies zuerst zu den Methoden hinzu

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

Rufen Sie danach diese Methode auf gemountet auf

mounted () {
  this.sayHi()
}
Mohamad
quelle
4

Kevin Muchwat oben hat die BESTE Antwort, trotz nur 10 positiven Stimmen und nicht ausgewählter Antwort.

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

Lassen Sie mich erklären, warum.

"Pfeilfunktion" ist ECMA6 / ECMA2015. Es ist perfekt in kompilierten Code- oder kontrollierten Client-Situationen (Cordova-Telefon-Apps, Node.js) gültig und nett und prägnant. Es wird wahrscheinlich sogar Ihre Tests bestehen!

Microsoft hat jedoch in seiner unendlichen Weisheit entschieden, dass Internet Explorer ECMA2015 NIEMALS UNTERSTÜTZEN wird!

Ihr neuer Edge-Browser funktioniert, aber das ist nicht gut genug für öffentlich zugängliche Websites.

Das Ausführen einer Standardfunktion () {} und das Hinzufügen von .bind (this) ist jedoch die ECMA5.1-Syntax (die vollständig unterstützt wird) für genau dieselbe Funktionalität.

Dies ist auch bei Ajax / Post .then / else-Aufrufen wichtig. Am Ende Ihrer .then (Funktion) {}) müssen Sie (dies) auch dort binden, also: .then (Funktion () {this.flag = true} .bind (this))

Ich hätte dies als Kommentar zu Kevins Antwort hinzugefügt, aber aus irgendeinem dummen Grund braucht es weniger Punkte, um Antworten zu posten, als um Kommentare zu Antworten

MACHEN SIE NICHT DEN GLEICHEN FEHLER, DEN ICH GEMACHT HABE!

Ich habe auf einem Mac codiert und den Kommentar mit 48 Punkten verwendet, der großartig funktioniert hat! Bis ich einige Anrufe bei meinen Skripten bekam, die fehlschlugen und ich nicht herausfinden konnte, warum. Ich musste zurückgehen und Dutzende Aufrufe von der Pfeilsyntax auf function () {}. Bind (this) syntax aktualisieren.

Zum Glück habe ich diesen Thread wieder gefunden und die richtige Antwort bekommen. Kevin, ich bin für immer dankbar.

Gemäß der "Akzeptierten Antwort" gibt es andere potenzielle Probleme im Zusammenhang mit zusätzlichen Bibliotheken (Probleme beim ordnungsgemäßen Zugriff auf / Aktualisieren von Vue-Eigenschaften / -Funktionen)

Peter
quelle
2
Wenn
Zeit weiterzumachen. :)
sheriffderek
1
@dave Ich bin mir nicht sicher, wie das einen Unterschied macht, wenn das Argument lautet, dass der IE dies nicht unterstützt. Edge unterstützt dies seit 2015.
FINDarkside
Und Sie können jederzeit einen EcmaScript-Transpiler wie babel verwenden, um Ihre Pfeilfunktionen zur Unterstützung des IE konvertieren zu lassen.
A1rPun
3

bind(this)Wenn Sie Pfeilfunktionen verwenden, ist dies nicht erforderlich :

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

Wenn Sie dieses Schlüsselwort in Ihrer Funktion verwenden möchten, müssen Sie die Funktion setTimeout in ES6 schreiben

setTimeout(() => {
   this.filters.max_budget_gt_eq = this.budgetHigherValue;
}, 1000);
Wouter Schoofs
quelle
3

Pfeilfunktion

Der beste und einfachste Weg, um dieses Problem zu lösen, ist die Verwendung einer Pfeilfunktion () => {}:

    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);
    }

Dies funktioniert , weil die thisPfeilfunktionen an den gebundenen thisseinen umschließenden Umfang - in Vue, dass die Eltern / umschließenden Komponente ist. Innerhalb einer traditionellen Funktion, die von aufgerufen wird setTimeout, wird jedoch thisauf das windowObjekt verwiesen (weshalb beim Versuch, this.basketAddSuccessin diesem Kontext auf etwas zuzugreifen , Fehler aufgetreten sind).

Argument übergeben

Eine andere Möglichkeit, dies zu tun, besteht darin, thisals Argument an Ihre Funktion durch setTimeoutden Prototyp zu übergeben , der dessen setTimeout(callback, delay, arg1, arg2, ...)Form verwendet:

    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);
    }

(Es ist jedoch anzumerken, dass die Arg-Passing-Syntax nicht mit IE 9 und niedriger kompatibel ist.)

zcoop98
quelle
0

benutze this.animationStop, nicht benutze this.animationStop ()

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

Es ist wahrscheinlich ein Umfangsproblem. Versuchen Sie stattdessen Folgendes:

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