Przejdź bezpośrednio do treści

Właściwości (Props)

Ta strona zakłada, że przeczytałeś już Podstawy Komponentów. Przeczytaj to najpierw, jeśli jesteś nowy w komponentach.

Deklaracja właściwości

Komponenty Vue wymagają jawnej deklaracji właściwości (props), dzięki czemu Vue wie, które zewnętrzne właściwości przekazane do komponentu powinny być traktowane jako atrybuty przelotowe (które zostaną omówione w dedykowanej sekcji).

W SFC używających <script setup>, właściwości (props) można deklarować za pomocą makra defineProps():

vue
<script setup>
const props = defineProps(['foo'])

console.log(props.foo)
</script>

W komponentach nie używających <script setup>, właściwości (props) są deklarowane za pomocą opcji props:

js
export default {
  props: ['foo'],
  setup(props) {
    // setup() przyjmuje właściwości (props) jako pierwszy argument.
    console.log(props.foo)
  }
}

Zauważ, że argument przekazany do defineProps() jest taki sam jak wartość przekazana do opcji props: to samo API opcji właściwości (props) jest współdzielone między dwoma stylami deklaracji.

Właściwości (props) są deklarowane za pomocą opcji props:

js
export default {
  props: ['foo'],
  created() {
    // właściwości (props) są dostępne w `this`
    console.log(this.foo)
  }
}

Oprócz deklarowania właściwości (props) za pomocą tablicy ciągów znaków, możemy również użyć składni obiektowej:

js
export default {
  props: {
    title: String,
    likes: Number
  }
}
js
// wewnątrz <script setup>
defineProps({
  title: String,
  likes: Number
})
js
// wewnątrz nie-<script setup>
export default {
  props: {
    title: String,
    likes: Number
  }
}

Dla każdej właściwości w składni deklaracji obiektu klucz jest nazwą właściwości (prop), podczas gdy wartość powinna być funkcją konstruktora oczekiwanego typu.

Pozwala to nie tylko udokumentować twój komponent, ale również ostrzeże innych programistów używających twojego komponentu w konsoli przeglądarki, jeśli przekażą nieprawidłowy typ. Więcej szczegółów na temat walidacji właściwości omówimy w dalszej części tej strony.

Jeśli używasz TypeScriptu ze <script setup>, możliwe jest również deklarowanie właściwości przy użyciu czystych adnotacji typów:

vue
<script setup lang="ts">
defineProps<{
  title?: string
  likes?: number
}>()
</script>

Więcej szczegółów: Typowanie właściwości komponentu

Szczegóły przekazywania właściwości

Konwencja nazywania właściwości

Deklarujemy długie nazwy właściwości używając camelCase, ponieważ pozwala to uniknąć konieczności używania cudzysłowów podczas używania ich jako kluczy właściwości oraz umożliwia bezpośrednie odwoływanie się do nich w wyrażeniach szablonu, ponieważ są poprawnymi identyfikatorami JavaScript:

js
defineProps({
  greetingMessage: String
})
js
export default {
  props: {
    greetingMessage: String
  }
}
template
<span>{{ greetingMessage }}</span>

Technicznie rzecz biorąc, możesz również używać camelCase podczas przekazywania właściwości do komponentu potomnego (z wyjątkiem szablonów w-DOM). Jednak konwencją jest używanie kebab-case we wszystkich przypadkach, aby zachować spójność z atrybutami HTML:

template
<MyComponent greeting-message="hello" />

Używamy PascalCase dla tagów komponentów, gdy jest to możliwe, ponieważ poprawia to czytelność szablonu poprzez rozróżnienie komponentów Vue od elementów natywnych. Jednak używanie camelCase podczas przekazywania właściwości nie przynosi aż tak wielu praktycznych korzyści, dlatego wybieramy przestrzeganie konwencji każdego języka.

Statyczne vs. dynamiczne właściwości

Do tej pory widziałeś właściwości przekazywane jako wartości statyczne, jak w:

template
<BlogPost title="Moja przygoda z Vue" />

Widziałeś również właściwości przypisywane dynamicznie za pomocą v-bind lub jego skrótu :, tak jak w:

template
<!-- Dynamicznie przypisana wartość zmiennej -->
<BlogPost :title="post.title" />

<!-- Dynamiczne przypisanie wartości złożonego wyrażenia -->
<BlogPost :title="post.title + ' by ' + post.author.name" />

Przekazywanie różnych typów wartości

W dwóch powyższych przykładach przekazujemy wartości tekstowe, ale każdy typ wartości może zostać przekazany do właściwości.

Liczba

template
<!-- Mimo że `42` jest statyczne, potrzebujemy v-bind aby powiedzieć Vue że -->
<!-- to jest wyrażenie JavaScript, a nie ciąg znaków.                       -->
<BlogPost :likes="42" />

<!-- Dynamicznie przypisz do wartości zmiennej. -->
<BlogPost :likes="post.likes" />

Boolean

template
<!-- Uwzględnienie właściwości bez wartości będzie oznaczać `true`. -->
<BlogPost is-published />

<!-- Mimo że `false` jest statyczne, potrzebujemy v-bind aby powiedzieć Vue że -->
<!-- to jest wyrażenie JavaScript, a nie ciąg znaków.                          -->
<BlogPost :is-published="false" />

<!-- Dynamicznie przypisz do wartości zmiennej. -->
<BlogPost :is-published="post.isPublished" />

Tablica

template
<!-- Mimo że tablica jest statyczna, potrzebujemy v-bind aby powiedzieć Vue że -->
<!-- to jest wyrażenie JavaScript, a nie ciąg znaków.                          -->
<BlogPost :comment-ids="[234, 266, 273]" />

<!-- Dynamicznie przypisz do wartości zmiennej. -->
<BlogPost :comment-ids="post.commentIds" />

Obiekt

template
<!-- Mimo że obiekt jest statyczny, potrzebujemy v-bind aby powiedzieć Vue że -->
<!-- to jest wyrażenie JavaScript, a nie ciąg znaków.                         -->
<BlogPost
  :author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
 />

<!-- Dynamicznie przypisz do wartości zmiennej. -->
<BlogPost :author="post.author" />

Wiązanie wielu właściwości przy użyciu obiektu

Jeśli chcesz przekazać wszystkie właściwości obiektu jako props, możesz użyć v-bind bez argumentu (v-bind zamiast :prop-name). Na przykład, mając obiekt post:

js
export default {
  data() {
    return {
      post: {
        id: 1,
        title: 'Moja podróż z Vue'
      }
    }
  }
}
js
const post = {
  id: 1,
  title: 'Moja podróż z Vue'
}

Poniższy szablon:

template
<BlogPost v-bind="post" />

Będzie równoważny z:

template
<BlogPost :id="post.id" :title="post.title" />

Jednokierunkowy przepływ danych

Wszystkie props tworzą jednokierunkowe wiązanie w dół między właściwością dziecka a właściwością rodzica: gdy właściwość rodzica się aktualizuje, przepływa w dół do dziecka, ale nie w drugą stronę. Zapobiega to przypadkowemu modyfikowaniu stanu rodzica przez komponenty potomne, co mogłoby utrudnić zrozumienie przepływu danych w aplikacji.

Dodatkowo, za każdym razem, gdy komponent nadrzędny jest aktualizowany, wszystkie props w komponencie potomnym zostaną odświeżone najnowszą wartością. Oznacza to, że nie powinieneś próbować modyfikować prop wewnątrz komponentu potomnego. Jeśli to zrobisz, Vue ostrzeże Cię w konsoli:

js
const props = defineProps(['foo'])

// ❌ uwaga, props są tylko do odczytu!
props.foo = 'bar'
js
export default {
  props: ['foo'],
  created() {
    // ❌ uwaga, props są tylko do odczytu!
    this.foo = 'bar'
  }
}

Zazwyczaj są dwa przypadki, w których kuszące jest modyfikowanie prop:

  1. Prop jest używany do przekazania wartości początkowej; komponent potomny chce później używać go jako lokalnej właściwości danych. W tym przypadku najlepiej jest zdefiniować lokalną właściwość danych, która używa prop jako wartości początkowej:

    js
    const props = defineProps(['initialCounter'])
    
    // counter używa tylko props.initialCounter jako wartości początkowej;
    // jest odłączony od przyszłych aktualizacji prop.
    const counter = ref(props.initialCounter)
    js
    export default {
      props: ['initialCounter'],
      data() {
        return {
          // counter używa tylko props.initialCounter jako wartości początkowej;
          // jest odłączony od przyszłych aktualizacji prop.
          counter: this.initialCounter
        }
      }
    }
  2. Prop jest przekazywany jako surowa wartość, która wymaga transformacji. W tym przypadku najlepiej jest zdefiniować właściwość obliczaną (computed) używającą wartości prop:

    js
    const props = defineProps(['size'])
    
    // właściwość obliczana, która automatycznie aktualizuje się, gdy prop się zmienia
    const normalizedSize = computed(() => props.size.trim().toLowerCase())
    js
    export default {
      props: ['size'],
      computed: {
        // właściwość obliczana, która automatycznie aktualizuje się, gdy prop się zmienia
        normalizedSize() {
          return this.size.trim().toLowerCase()
        }
      }
    }

Modyfikowanie obiektów / tablic w props

Gdy obiekty i tablice są przekazywane jako props, pomimo że komponent potomny nie może modyfikować wiązania prop, będzie mógł modyfikować zagnieżdżone właściwości obiektu lub tablicy. Dzieje się tak, ponieważ w JavaScript obiekty i tablice są przekazywane przez referencję, a zapobieganie takim modyfikacjom przez Vue byłoby nieracjonalnie kosztowne.

Główną wadą takich modyfikacji jest to, że pozwalają komponentowi potomnemu wpływać na stan rodzica w sposób, który nie jest oczywisty dla komponentu nadrzędnego, potencjalnie utrudniając zrozumienie przepływu danych w przyszłości. Zgodnie z najlepszymi praktykami, powinieneś unikać takich modyfikacji, chyba że rodzic i dziecko są ściśle powiązane przez projekt. W większości przypadków, dziecko powinno emitować zdarzenie, aby pozwolić rodzicowi wykonać modyfikację.

Walidacja props

Komponenty mogą określać wymagania dla swoich props, takie jak typy, które już widziałeś. Jeśli wymaganie nie jest spełnione, Vue ostrzeże Cię w konsoli JavaScript przeglądarki. Jest to szczególnie przydatne podczas tworzenia komponentu, który ma być używany przez innych.

Aby określić walidacje props, możesz dostarczyć obiekt z wymaganiami walidacji do makra defineProps()opcji props, zamiast tablicy ciągów znaków. Na przykład:

js
defineProps({
  // Podstawowe sprawdzanie typu
  //  (wartości `null` i `undefined` pozwolą na dowolny typ)
  propA: Number,
  // Wiele możliwych typów
  propB: [String, Number],
  // Wymagany string
  propC: {
    type: String,
    required: true
  },
  // Wymagany, ale dopuszczający null string
  propD: {
    type: [String, null],
    required: true
  },
  // Liczba z wartością domyślną
  propE: {
    type: Number,
    default: 100
  },
  // Obiekt z wartością domyślną
  propF: {
    type: Object,
    // Domyślne wartości obiektów lub tablic muszą być zwracane
    // z funkcji fabrycznej. Funkcja otrzymuje surowe
    // props otrzymane przez komponent jako argument.
    default(rawProps) {
      return { message: 'hello' }
    }
  },
  // Niestandardowa funkcja walidacyjna
  // pełne props przekazywane jako 2. argument w 3.4+
  propG: {
    validator(value, props) {
      // Wartość musi pasować do jednego z tych stringów
      return ['success', 'warning', 'danger'].includes(value)
    }
  },
  // Funkcja z wartością domyślną
  propH: {
    type: Function,
    // W przeciwieństwie do domyślnego obiektu lub tablicy, to nie jest funkcja
    // fabryczna - jest to funkcja służąca jako wartość domyślna
    default() {
      return 'Default function'
    }
  }
})

TIP

Kod wewnątrz argumentu defineProps() nie może uzyskać dostępu do innych zmiennych zadeklarowanych w <script setup>, ponieważ całe wyrażenie jest przenoszone do zewnętrznego zakresu funkcji podczas kompilacji.

js
export default {
  props: {
    // Podstawowe sprawdzanie typu
    // (wartości `null` i `undefined` pozwolą na użycie dowolnego typu)
    propA: Number,
    // Wiele możliwych typów
    propB: [String, Number],
    // Wymagany string
    propC: {
      type: String,
      required: true
    },
    // Wymagany ale dopuszczający null string
    propD: {
      type: [String, null],
      required: true
    },
    // Liczba z wartością domyślną
    propE: {
      type: Number,
      default: 100
    },
    // Obiekt z wartością domyślną
    propF: {
      type: Object,
      // Wartości domyślne obiektów lub tablic muszą być zwrócone
      // z funkcji fabrykującej. Funkcja otrzymuje surowe
      // propsy przekazane do komponentu jako argument.
      default(rawProps) {
        return { message: 'hello' }
      }
    },
    // Niestandardowa funkcja walidująca
    // pełne propsy przekazane jako 2. argument w wersji 3.4+
    propG: {
      validator(value, props) {
        // Wartość musi pasować do jednego z tych stringów
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    // Funkcja z wartością domyślną
    propH: {
      type: Function,
      // W przeciwieństwie do domyślnego obiektu lub tablicy, to nie jest funkcja
      // fabrykująca - to funkcja służąca jako wartość domyślna
      default() {
        return 'Default function'
      }
    }
  }
}

Dodatkowe szczegóły:

  • Wszystkie propsy są opcjonalne domyślnie, chyba że określono required: true.

  • Nieobecny opcjonalny props inny niż Boolean będzie miał wartość undefined.

  • Nieobecne propsy typu Boolean zostaną rzutowane na false. Możesz to zmienić ustawiając dla nich default — np.: default: undefined aby zachowywały się jak props nie będący typu Boolean.

  • Jeśli określona jest wartość default, zostanie ona użyta gdy wartość propsa zostanie rozwiązana jako undefined - dotyczy to zarówno sytuacji, gdy props jest nieobecny, jak i gdy została jawnie przekazana wartość undefined.

Gdy walidacja propsów nie powiedzie się, Vue wyświetli ostrzeżenie w konsoli (jeśli używana jest wersja deweloperska).

Jeśli używasz Deklaracji propsów opartych na typach , Vue postara się jak najlepiej skompilować adnotacje typów do równoważnych deklaracji propsów w czasie wykonania. Na przykład, defineProps<{ msg: string }> zostanie skompilowane do { msg: { type: String, required: true }}.

Note

Pamiętaj, że propsy są walidowane przed utworzeniem instancji komponentu, więc właściwości instancji (np. data, computed, itp.) nie będą dostępne wewnątrz funkcji default lub validator.

Sprawdzanie typów w czasie wykonania

type może być jednym z następujących natywnych konstruktorów:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol
  • Error

Dodatkowo, type może być również niestandardową klasą lub funkcją konstruktora, a sprawdzenie zostanie wykonane za pomocą instanceof. Na przykład, mając następującą klasę:

js
class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
  }
}

Możesz użyć jej jako typu propsa:

js
defineProps({
  author: Person
})
js
export default {
  props: {
    author: Person
  }
}

Vue użyje instanceof Person do sprawdzenia, czy wartość propsa author jest faktycznie instancją klasy Person.

Typ dopuszczający null

Jeśli typ jest wymagany, ale dopuszcza null, możesz użyć składni tablicowej, która zawiera null:

js
defineProps({
  id: {
    type: [String, null],
    required: true
  }
})
js
export default {
  props: {
    id: {
      type: [String, null],
      required: true
    }
  }
}

Pamiętaj, że jeśli type to po prostu null bez użycia składni tablicowej, dopuści on każdy typ.

Rzutowanie Boolean

Propsy typu Boolean mają specjalne reguły rzutowania, aby naśladować zachowanie natywnych atrybutów logicznych. Biorąc pod uwagę <MyComponent> z następującą deklaracją:

js
defineProps({
  disabled: Boolean
})
js
export default {
  props: {
    disabled: Boolean
  }
}

Komponent może być używany w następujący sposób:

template
<!-- odpowiednik przekazania :disabled="true" -->
<MyComponent disabled />

<!-- odpowiednik przekazania :disabled="false" -->
<MyComponent />

Gdy props jest zadeklarowany tak, aby dopuszczał wiele typów, reguły rzutowania dla Boolean również będą stosowane. Jednakże, istnieje szczególny przypadek gdy dozwolone są zarówno String jak i Boolean - reguła rzutowania Boolean będzie stosowana tylko wtedy, gdy Boolean występuje przed String:

js
// disabled zostanie zrzutowane na true
defineProps({
  disabled: [Boolean, Number]
})

// disabled zostanie zrzutowane na true
defineProps({
  disabled: [Boolean, String]
})

// disabled zostanie zrzutowane na true
defineProps({
  disabled: [Number, Boolean]
})

// disabled zostanie sparsowane jako pusty string (disabled="")
defineProps({
  disabled: [String, Boolean]
})
js
// disabled zostanie zrzutowane na true
export default {
  props: {
    disabled: [Boolean, Number]
  }
}

// disabled zostanie zrzutowane na true
export default {
  props: {
    disabled: [Boolean, String]
  }
}

// disabled zostanie zrzutowane na true
export default {
  props: {
    disabled: [Number, Boolean]
  }
}

// disabled zostanie sparsowane jako pusty string (disabled="")
export default {
  props: {
    disabled: [String, Boolean]
  }
}
Właściwości (Props)Jest załadowany