Skip to content

Berechnete Eigenschaften

Grundlegendes Beispiel

Vorlageninterne Ausdrücke sind sehr praktisch, aber sie sind für einfache Operationen gedacht. Wenn Sie zu viel Logik in Ihre Vorlagen einbauen, können diese aufgebläht und schwer zu pflegen werden. Zum Beispiel, wenn wir ein Objekt mit einem verschachtelten Array haben:

js
export default {
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  }
}
js
const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})

Und wir wollen unterschiedliche Meldungen anzeigen, je nachdem, ob Autor bereits einige Bücher hat oder nicht:

template
<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>

An diesem Punkt wird die Vorlage ein wenig unübersichtlich. Wir müssen sie eine Sekunde lang betrachten, um zu erkennen, dass sie eine Berechnung in Abhängigkeit von author.books durchführt. Noch wichtiger ist, dass wir uns wahrscheinlich nicht wiederholen wollen, wenn wir diese Berechnung mehr als einmal in die Vorlage aufnehmen müssen.

Aus diesem Grund wird für komplexe Logik, die reaktive Daten enthält, die Verwendung einer berechneten Eigenschaft empfohlen. Hier ist das gleiche Beispiel, umstrukturiert:

js
export default {
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  },
  computed: {
    // a computed getter
    publishedBooksMessage() {
      // `this` points to the component instance
      return this.author.books.length > 0 ? 'Yes' : 'No'
    }
  }
}
template
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>

Versuchen Sie es auf dem Spielplatz

Hier haben wir eine berechnete Eigenschaft publishedBooksMessage deklariert.

Versuchen Sie, den Wert des Arrays books in der Anwendung data zu ändern und Sie werden sehen, wie sich publishedBooksMessage entsprechend ändert.

Sie können Daten an berechnete Eigenschaften in Templates binden, genau wie eine normale Eigenschaft. Vue ist sich bewusst, dass this.publishedBooksMessage von this.author.books abhängt, also wird es alle Bindungen, die von this.publishedBooksMessage abhängen, aktualisieren, wenn this.author.books sich ändert.

Siehe auch: Typing Computed Properties

vue
<script setup>
import { reactive, computed } from 'vue'

const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})

// a computed ref
const publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'Yes' : 'No'
})
</script>

<template>
  <p>Has published books:</p>
  <span>{{ publishedBooksMessage }}</span>
</template>

Versuchen Sie es auf dem Spielplatz

Hier haben wir eine berechnete Eigenschaft publishedBooksMessage deklariert. Die Funktion "berechnet()" erwartet die Übergabe einer Getter-Funktion, und der zurückgegebene Wert ist eine berechnete Referenz. Ähnlich wie bei normalen Refs kann man auf das berechnete Ergebnis als publishedBooksMessage.value zugreifen. Berechnete Refs werden auch automatisch in Templates entpackt, so dass man sie ohne .value in Template-Ausdrücken referenzieren kann.

Eine berechnete Eigenschaft verfolgt automatisch ihre reaktiven Abhängigkeiten. Vue ist sich bewusst, dass die Berechnung von publishedBooksMessage von author.books abhängt, also wird es alle Bindungen, die von publishedBooksMessage abhängen, aktualisieren, wenn sich author.books ändert.

Siehe auch: Typing Computed

Berechnetes Caching vs. Methoden

Sie haben vielleicht bemerkt, dass wir das gleiche Ergebnis durch den Aufruf einer Methode im Ausdruck erreichen können:

template
<p>{{ calculateBooksMessage() }}</p>
js
// in component
methods: {
  calculateBooksMessage() {
    return this.author.books.length > 0 ? 'Yes' : 'No'
  }
}
js
// in component
function calculateBooksMessage() {
  return author.books.length > 0 ? 'Yes' : 'No'
}

Anstelle einer berechneten Eigenschaft können wir die gleiche Funktion als Methode definieren. Was das Endergebnis betrifft, sind die beiden Ansätze tatsächlich genau gleich. Der Unterschied besteht jedoch darin, dass berechnete Eigenschaften auf der Grundlage ihrer reaktiven Abhängigkeiten zwischengespeichert werden. Eine berechnete Eigenschaft wird nur dann neu ausgewertet, wenn sich einige ihrer reaktiven Abhängigkeiten geändert haben. Das heißt, solange sich author.books nicht geändert hat, wird ein mehrfacher Zugriff auf publishedBooksMessage sofort das zuvor berechnete Ergebnis zurückgeben, ohne dass die Getter-Funktion erneut ausgeführt werden muss.

Das bedeutet auch, dass die folgende berechnete Eigenschaft nie aktualisiert wird, da "date.now()" keine reaktive Abhängigkeit ist:

js
computed: {
  now() {
    return Date.now()
  }
}
js
const now = computed(() => Date.now())

Im Vergleich dazu wird bei einem Methodenaufruf die Funktion immer ausgeführt, wenn eine Neuberechnung erfolgt.

Warum brauchen wir eine Zwischenspeicherung? Stellen Sie sich vor, wir haben eine teure berechnete Eigenschaft list, die eine Schleife durch ein großes Array und viele Berechnungen erfordert. Dann haben wir vielleicht andere berechnete Eigenschaften, die wiederum von list abhängen. Ohne Zwischenspeicherung würden wir den Getter von list viel öfter als nötig ausführen! In Fällen, in denen Sie keine Zwischenspeicherung wünschen, verwenden Sie stattdessen einen Methodenaufruf.

Beschreibbar Berechnet

Berechnete Eigenschaften sind standardmäßig nur Getter-Eigenschaften. Wenn Sie versuchen, einer berechneten Eigenschaft einen neuen Wert zuzuweisen, erhalten Sie eine Laufzeitwarnung. In den seltenen Fällen, in denen Sie eine "beschreibbare" berechnete Eigenschaft benötigen, können Sie eine erstellen, indem Sie sowohl einen Getter als auch einen Setter bereitstellen:

js
export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    }
  },
  computed: {
    fullName: {
      // getter
      get() {
        return this.firstName + ' ' + this.lastName
      },
      // setter
      set(newValue) {
        // Note: we are using destructuring assignment syntax here.
        [this.firstName, this.lastName] = newValue.split(' ')
      }
    }
  }
}

Wenn Sie nun this.fullName = 'John Doe' ausführen, wird der Setter aufgerufen und this.firstName und this.lastName werden entsprechend aktualisiert.

vue
<script setup>
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  // getter
  get() {
    return firstName.value + ' ' + lastName.value
  },
  // setter
  set(newValue) {
    // Note: we are using destructuring assignment syntax here.
    [firstName.value, lastName.value] = newValue.split(' ')
  }
})
</script>

Wenn Sie nun fullName.value = 'John Doe' ausführen, wird der Setter aufgerufen und firstName und lastName werden entsprechend aktualisiert.

Beste Praktiken

Getter sollten nebenwirkungsfrei sein

Es ist wichtig, daran zu denken, dass berechnete Getter-Funktionen nur reine Berechnungen durchführen und frei von Nebeneffekten sein sollten. Stellen Sie sich eine berechnete Eigenschaft als eine deklarative Beschreibung vor, die beschreibt, wie ein Wert auf der Grundlage anderer Werte abgeleitet wird - ihre einzige Aufgabe sollte die Berechnung und Rückgabe dieses Wertes sein. Später im Handbuch werden wir besprechen, wie wir Seiteneffekte in Reaktion auf Zustandsänderungen mit watchers.

Mutation des berechneten Wertes vermeiden

Der von einer berechneten Eigenschaft zurückgegebene Wert ist ein abgeleiteter Zustand. Betrachten Sie ihn als einen temporären Schnappschuss - jedes Mal, wenn sich der Quellzustand ändert, wird ein neuer Schnappschuss erstellt. Es ist nicht sinnvoll, einen Schnappschuss zu verändern, daher sollte ein berechneter Rückgabewert als schreibgeschützt behandelt und niemals verändert werden - aktualisieren Sie stattdessen den Quellzustand, von dem er abhängt, um neue Berechnungen auszulösen.

Berechnete Eigenschaften has loaded