8,559 lekti
8,559 lekti

Vue.js: pwopriyete pwopriyete kòm yon Pro

pa Andrei Sieedugin7m2025/05/03
Read on Terminal Reader

Twò lontan; Pou li

Lè ou kreye konpozan pou pwojè ou, tout kòmanse plezi ak fasil. Kreye 'MyButton.vue' ak ajoute yon kèk estil, ak voilà. Lè sa a, ou imedyatman konprann ke ou bezwen yon douz nan pwopriyete, paske ekip konsepsyon ou vle li yo dwe nan koulè ak gwosè diferan, ak ikòn nan bò solèy ak dwat, ak kontè. Nan fen a, ou pa ka gen bouton yo "Cancel" ak "Ok" nan menm koulè, epi ou bezwen yo reponn a interaksyon itilizatè.
featured image - Vue.js: pwopriyete pwopriyete kòm yon Pro
Andrei Sieedugin HackerNoon profile picture

Lè ou kreye eleman pou pwojè ou, tout kòmanse plezi ak fasil.MyButton.vueLè sa a, ajoute yon ti kras estil, epi isit la.

<template>
  <button class="my-fancy-style">
    <slot></slot>
  </button>
</template>


Lè sa a, ou imedyatman rekòmande ke ou bezwen yon douzè pwopriyete, paske ekip konsepsyon ou vle li dwe nan koulè ak gwosè diferan, ak ikòn sou bò a ak bò a, ak kontè...

const props = withDefaults(defineProps<{
  theme?: ComponentTheme;
  small?: boolean;
  icon?: IconSvg; // I’ve described how I cook icons in my previous article
  rightIcon?: IconSvg;
  counter?: number;
}>(), {
  theme: ComponentTheme.BLUE,
  icon: undefined,
  rightIcon: undefined,
  counter: undefined
});


Li toujou ok; li se rezonab. Nan fen a, ou pa ka gen bouton yo "cancel" ak "ok" nan menm koulè, epi ou bezwen yo reponn a interaksyon itilizatè. Oh, byen, interaksyon.

const props = withDefaults(defineProps<{
  theme?: ComponentTheme;
  small?: boolean;
  icon?: IconSvg;
  rightIcon?: IconSvg;
  counter?: number;
  disabled?: boolean;
  loading?: boolean;
}>(), {
  theme: ComponentTheme.BLUE,
  icon: undefined,
  rightIcon: undefined,
  counter: undefined
});


Bon, ou jwenn lide a: pral gen yon bagay vil, tankou pasewidth: 100%oswa ajoute autofocus - nou tout konnen ki jan li sanble senp nan Figma jiskaske lavi reyèl la frape difisil.


Koulye a, imajine yon bouton lyen: li sanble menm, men lè ou klike sou li, ou ta dwe ale nan lyen ekstèn oswa enteryè. Ou ka enkli yo nan<RouterLink>ou<a>tags chak fwa, men tanpri pa. Ou ka tou ajoutetoakhrefpwopriyete nan konpozan orijinal ou, men ou pral santi asfòse byen bonè:

<component
  :is="to ? RouterLink : href ? 'a' : 'button'"
  <!-- ugh! -->


Natirèlman, ou pral bezwen yon konpozan "dezyèm-nivo" ki enkli bouton ou a (li pral tou fè fas a default hyperlink kontinyèl yo ak kèk lòt bagay enteresan, men mwen pral omite yo pou rezon nan senplisite):

<template>
  <component
    :is="props.to ? RouterLink : 'a'"
    :to="props.to"
    :href="props.href"
    class="my-link-button"
  >
    <MyButton v-bind="$attrs">
      <slot></slot>
    </MyButton>
  </component>
</template>

<script lang="ts" setup>
import MyButton from './MyButton.vue';
import { RouteLocationRaw, RouterLink } from 'vue-router';

const props = defineProps<{
  to?: RouteLocationRaw;
  href?: string;
}>();
</script>

Li se kote istwa nou an kòmanse.

Square One

Pwensipal 1

Bon, nan fondamantalman li pral travay, mwen pa pral men. Ou ka toujou enskri<MyLinkButton :counter=“2">, epi li pral ok. Men, pa pral gen okenn autocomplete pou pwopòsyon derive, ki se pa cool:


Only "href" and "to"


Nou ka pwopriyete pwopriyete nan silenn, men IDE a pa konnen yon bagay sou yo, ak sa a se yon mal.


Solisyon a senp ak evidan se pwopriyete yo eksplisitman:

<template>
  <component
    :is="props.to ? RouterLink : 'a'"
    :to="props.to"
    :href="props.href"
    class="my-link-button"
  >
    <MyButton
      :theme="props.theme"
      :small="props.small"
      :icon="props.icon"
      :right-icon="props.rightIcon"
      :counter="props.counter"
      :disabled="props.disabled"
      :loading="props.loading"
    >
      <slot></slot>
    </MyButton>
  </component>
</template>

<script lang="ts" setup>
// imports...

const props = withDefaults(
  defineProps<{
    theme?: ComponentTheme;
    small?: boolean;
    icon?: IconSvg;
    rightIcon?: IconSvg;
    counter?: number;
    disabled?: boolean;
    loading?: boolean;

    to?: RouteLocationRaw;
    href?: string;
  }>(),
  {
    theme: ComponentTheme.BLUE,
    icon: undefined,
    rightIcon: undefined,
    counter: undefined,
  }
);
</script>


Li pral travay. IDE a pral gen autocomplete apwopriye. Nou pral gen anpil doulè ak regret sipòte li.


Evidentman, prensip la "pa repete tèt ou" pa te aplike isit la, ki vle di ke nou pral bezwen sinkronize chak ajou. Yon jou, ou pral bezwen ajoute yon lòt pwopriyete, epi ou pral gen yo jwenn chak konpozan ki enpak la prensipal la. Se konsa, bouton ak LinkButton yo pwobableman ase, men imajine TextInput ak yon douzèn de konpozan ki depann sou li: PasswordInput, EmailInput, NumberInput, DateInput, HellKnowsWhatElseInput. Ajoute yon pwopriyete pa ta dwe fè mal.


Se poutèt sa, li se grenn. Epi plis pwofi nou gen, pi grenn li vin.

Clean It Up

Pwoteje li

Li se byen difisil yo re- itilize yon tip anonim, se konsa, kite li yon non.

// MyButton.props.ts

export interface MyButtonProps {
  theme?: ComponentTheme;
  small?: boolean;
  icon?: IconSvg;
  rightIcon?: IconSvg;
  counter?: number;
  disabled?: boolean;
  loading?: boolean;
}


Nou pa ka ekspòte yon interface soti nan.vuedosye akòz yon kèk enteryèscript setupmagik, se konsa nou bezwen kreye yon.tsSou bò a klere, tcheke sa nou gen isit la:

const props = withDefaults(defineProps<MyButtonProps>(), {
  theme: ComponentTheme.BLUE,
  icon: undefined,
  rightIcon: undefined,
  counter: undefined,
});


Plis klere, se pa? Ak isit la se yon moun ki gen eritaj:

interface MyLinkButtonProps {
  to?: RouteLocationRaw;
  href?: string;
}

const props = defineProps<MyButtonProps & MyLinkButtonProps>();


Sepandan, isit la se yon pwoblèm: kounye a, lè pwopriyete baz yo trete kòmMyLinkButton's props, yo pa propage akv-bind=”$attrs”plis, se konsa nou bezwen fè li pwòp tèt nou.

<!-- MyLinkButton.vue -->

<component
  :is="props.to ? RouterLink : 'a'"
  :to="props.to"
  :href="props.href"
  class="my-link-button"
>
  <MyButton v-bind="props"> <!-- there we go -->
    <slot></slot>
  </MyButton>
</component>


Tout se bon, men nou pase yon ti kras plis pase nou vle:


W3C disapproves


Kòm ou ka wè, kounye a bouton anba nou an tou gen yonhrefAtribit. Li se pa yon tragedie, jis yon ti kras ankouraje ak ekstra byte, sepandan pa cool.

<template>
  <component
    :is="props.to ? RouterLink : 'a'"
    :to="props.to"
    :href="props.href"
    class="my-link-button"
  >
    <MyButton v-bind="propsToPass">
      <slot></slot>
    </MyButton>
  </component>
</template>

<script lang="ts" setup>
// imports and definitions…

const props = defineProps<MyButtonProps & MyLinkButtonProps>();

const propsToPass = computed(() =>
  Object.fromEntries(
    Object.entries(props).filter(([key, _]) => !["to", "href"].includes(key))
  )
);
</script>


Koulye a, nou sèlman pase sa ki gen yo pase, men tout sa yo literal string pa gade bèl, se yo? Epi sa a se istwa a TypeScript ki pi trankil, zanmi. Permet m 'te di ou sou li.

Interfaces vs Abstract Interfaces

Entèfas vs abstrak Entèfas

Si ou te janm te travay ak bon lang objè oryante, ou ka konnen sou bagay sa yo tankouRefleksyon, ki pèmèt nou jwenn metadata sou estrikti nou yo. Malgre ke nan TypeScript, entèfas yo efemeral; yo pa egziste nan kouri tan, epi nou pa ka fasil konnen ki jaden ki nanMyButtonProps.


Li vle di ke nou gen de opsyon. Premye, nou ka kenbe bagay la kòm li se: chak fwa nou ajoute yon pwopriyetèMyLinkButtonEpitou, nou bezwen elimine li soti nanpropsToPass(Epitou si nou oblije sou li, li se pa yon gwo pwoblèm).


Yon dezyèm fason se lè l sèvi avèk objè olye pou entèfas. Li ta ka sonje sansib, men pèmèt m 'kode yon bagay: li pa pral horrible; Mwen pwomèt. Nou, omwen paSa aTèm nan.

// MyButton.props.ts

export const defaultMyButtonProps: MyButtonProps = {
  theme: ComponentTheme.BLUE,
  small: false,
  icon: undefined,
  rightIcon: undefined,
  counter: undefined,
  disabled: false,
  loading: false,
};


Li pa vle kreye yon objè jis pou kreye yon objè, men nou ka sèvi ak li pou pwopriyete default la. Deklarasyon an nanMyButton.vueLi vin pi klè:

const props = withDefaults(defineProps<MyButtonProps>(), defaultMyButtonProps);


Koulye a, nou sèlman bezwen mete ajoupropsToPassnanMyLinkButton.vue:

const propsToPass = computed(() =>
  Object.fromEntries(
    Object.entries(props).filter(([key, _]) =>
      Object.hasOwn(defaultMyButtonProps, key)
    )
  )
);


Pou fè travay sa a, nou bezwen eksplisit definye toutundefinedaknullZòn nandefaultMyButtonProps; si yo pa, objè a pa "te gen pwòp".


Nan fason sa a, chak fwa ou ajoute yon pwopriyetè nan konpozan prensipal la, ou pral tou bezwen ajoute li nan objè a ak valè default yo. Se konsa, si, li se de kote ankò, e ka li pa pi bon pase solisyon an soti nan chapit la anvan. Li depann sou ou ki moun ou pral jwenn pi netwaye.

I’m Done

Mwen te fè

Li se pa yon pwopriyete, men li se pwobableman pi bon nou ka fè nan limitasyon yo nan TypeScript.


Li tou sanble ke gen tip prop nan dosye a SFC se pi bon, men mwen pa ka di ke deplase yo nan yon dosye separe te fè li anpil pi mal. Men, li definitivman te fè reuse prop pi bon, se konsa mwen pral konsidere li kòm yon ti victorie nan yon batay sansasyonèl nou rele travay.


Ou ka jwenn kòd la nan atik sa a sou GitHub.

GitHub nan

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks