Med Begränsad Slots i Vue.js till Abstrakt Funktionalitet

0
23

Låt oss börja med en kort introduktion till Vue.js slots koncept. Slots är användbara när du vill, att injicera innehållet på en viss plats av en komponent. De specifika platser som du kan definiera kallas slots.

Till exempel, du vill skapa ett omslag komponent som är utformade på ett visst sätt, men du vill kunna överföra något innehåll återges inuti som omslag (det kan vara en sträng, ett beräknat värde, eller ens en annan komponent).

Det finns tre typer av slots:

  • standard / namnlösa slots: används när du har ett enda spår på en komponent. Vi skapar dem genom att lägga till <slot> i mallen där vi vill kunna injicera vårt innehåll. <Slot> – taggen kommer att ersättas med något innehåll som skickas till komponentens mall.
  • heter slots: används när du har flera slots i en komponent och vi vill bjuda på olika innehåll på olika platser (slots). Vi skapar dem genom att lägga till <slot> med ett name-attribut (t ex <slot name=”header”></slot>). Sedan när vi gör vår del, att vi ger en slot innehåll för varje namngiven slot genom att lägga till ett spår-attribut med slot namn.

<base-layout>
<mallen slot=”header”>
<h1>Min awsome rubrik</h1>
</template>
<mallen slot=”footer”>
<p>Min awsome sidfot</p>
</template>
</bas-layout>

Genom att göra det, <slot> – taggar i den del som kommer att ersättas av innehåll som skickas till komponent.

  • inzoomat slot: används när du vill ha en mall inne i en plats för att få tillgång till data från barn-komponent som gör slot innehåll. Detta är särskilt användbart när du behöver frihet att skapa egna mallar att använda barnet komponentens egenskaper för data.

Verkliga Exempel: Skapa en Google Map Loader komponent

Föreställ dig en komponent som konfigurerar och förbereder ett yttre API för att användas i en annan komponent, men är inte tätt tillsammans med någon specifik mall. En sådan komponent kan sedan återanvändas på flera ställen rendering olika mallar, men med samma bas objekt med särskilda API.

Jag har skapat en komponent (GoogleMapLoader.vue) att:

  1. initierar Google Maps API
  2. skapar google och karta objekt
  3. visar de objekt som den överordnade delen där GoogleMapLoader används

Nedan är ett exempel på hur detta kan uppnås. Vi kommer att analysera koden bit-för-bit och se vad som faktiskt händer i nästa avsnitt.

Låt oss först etablera vår GoogleMapLoader.vue mall:

<mall>
<div>
<div class=”google-karta” data-google-karta></div>
<mallen v-if=”Boolean(det här.google) && Boolean(det här.kartan)”>
<slot :google=”google” :karta=”kartan” />
</template>
</div>
</template>

Nu är vårt skript behöver för att klara en del rekvisita till den komponent som tillåter oss att ställa in Google Maps API och objekt på Kartan:

importera GoogleMapsApiLoader från “google-maps-api-loader”;

export standard {
rekvisita: {
mapConfig: Object,
apiKey: String
},
data() {
return {
google: null,
karta: null
};
},
async monterad() {
const googleMapApi = väntar GoogleMapsApiLoader({
apiKey: här.apiKey
});
detta.google = googleMapApi;
detta.initializeMap();
},
metoder: {
initializeMap() {
const mapContainer =.$el.querySelector(“[data-google-karta]”);
detta.map = new detta.google.kartor.Karta(mapContainer, detta.mapConfig);
}
}
};

Detta är bara en del av ett fungerande exempel. Du kan dyka ner djupare i detta exempel.

OK, nu när vi har vår användning fall satt upp, låt oss gå vidare till att bryta koden ner för att utforska vad det gör.

1. Skapa en komponent som initierar vår karta

I mallen, vi skapar en behållare för den karta som ska användas för att montera objekt på Kartan hämtats från Google Maps API.

// GoogleMapLoader.vue
<mall>
<div>
<div class=”google-karta” data-google-karta></div>
</div>
</template>

Nästa upp, vårt manus måste få rekvisita från den överordnade delen som kommer att tillåta oss att ställa in Google-Karta. Dessa rekvisita består av:

  • mapConfig: Google Maps config objekt
  • apiKey: Vår personliga api-nyckel som krävs av Google Maps

// GoogleMapLoader.vue
importera GoogleMapsApiLoader från “google-maps-api-loader”;

export standard {
rekvisita: {
mapConfig: Object,
apiKey: String
},

Sedan satte vi de ursprungliga värdena för google och karta till null:

data() {
return {
google: null,
karta: null
};
},

På monterad krok, skapar vi en instans av googleMapApi och objekt på kartan från det. Vi måste också ställa in värden av google och en karta som skapats fall:

async monterad() {
const googleMapApi = väntar GoogleMapsApiLoader({
apiKey: här.apiKey
});
detta.google = googleMapApi;
detta.initializeMap();
},
metoder: {
initializeMap() {
const mapContainer =.$el.querySelector(“[data-google-karta]”);
detta.map = new detta.google.kartor.Karta(mapContainer, detta.mapConfig);
}
}
};

Så långt, så bra. Med allt som sker, vi kan fortsätta att lägga till andra objekt i kartan (Markörer, Flerlinjer, etc.) och använda den som en vanlig karta komponent.

Men, vi vill använda våra GoogleMapLoader komponent endast som en lastare som förbereder karta — vi vill inte göra någonting på det.

För att uppnå detta, måste vi ge den överordnade delen som kommer att använda vår GoogleMapLoader att få tillgång till detta.google och den här.karta som är inne i det GoogleMapLoader komponent. Det är där begränsad slots verkligen lysa. Inzoomat slots det möjligt för oss att exponera de fastigheter som ligger i en underordnad komponent till den överordnade delen. Det kanske låter som en början, men bär med mig en minut som vi bryter ner det ytterligare.

2. Skapa en komponent som använder vår initializer komponent

I mallen, vi gör GoogleMapLoader komponent och passera rekvisita som krävs för att initiera karta.

// TravelMap.vue
<mall>
<GoogleMapLoader
:mapConfig=”mapConfig”
apiKey=”yourApiKey”
/>
</template>

Vårt script-taggen ser ut så här:

importera GoogleMapLoader från “./GoogleMapLoader”;
import { mapSettings } från “@/konstanterna/mapSettings”;

export standard {
komponenter: {
GoogleMapLoader,
},
beräknad: {
mapConfig() {
return {
…mapSettings,
center: { lat: 0, lng: 0 }
};
},
}
};

Fortfarande ingen begränsad slots, så låt oss lägga till en.

3. Exponera google-karta och egenskaper till den överordnade delen genom att lägga till en inzoomad slot

Äntligen kan vi lägga till en inzoomad slot som kommer att göra jobbet och ger oss tillgång till de barn komponent rekvisita i den överordnade delen. Vi gör det genom att lägga till <slot> – taggen i barn komponent och passerar den rekvisita som vi vill exponera (med hjälp av v-bind direktiv eller :propName stenografi). Det skiljer sig inte från att passera den rekvisita ner till barnet komponent, men gör det i <slot> – taggen kommer att vända riktningen på dataflödet.

// GoogleMapLoader.vue
<mall>
<div>
<div class=”google-karta” data-google-karta></div>
<mallen v-if=”Boolean(det här.google) && Boolean(det här.kartan)”>
<slot
:google=”google”
:karta=”karta”
/>
</template>
</div>
</template>

Nu, när vi har slot i barn-komponent, måste vi ta emot och konsumera den utsatta rekvisita i den överordnade delen.

4. Ta emot utsatta rekvisita i den överordnade delen med slot-scope-attribut

För att få rekvisita i den överordnade delen, vi deklarera en mall element och använda den slot-scope-attribut. Detta attribut har tillgång till objekt bär alla rekvisita exponerade från barn komponent. Vi kan ta hela objektet eller vi kan de-struktur som objekt och inte bara vad vi behöver.

Låt de-struktur denna sak för att få vad vi behöver.

// TravelMap.vue
<mall>
<GoogleMapLoader
:mapConfig=”mapConfig”
apiKey=”yourApiKey”
>
<mallen slot-scope=”{ google, karta }”>
{{ kort }}
{{ google }}
</template>
</GoogleMapLoader>
</template>

Även om google och karta rekvisita finns inte i TravelMap omfattning, den komponent som har tillgång till dem, och vi kan använda dem i mallen.

Ja, OK, men varför skulle jag göra sånt? Vad är det för alla?

Glad att du frågade! Inzoomat slots det möjligt för oss att passera en mall till facket i stället för en renderad element. Det kallas en inzoomad slot eftersom det kommer att ha tillgång till vissa barn komponent data även om mallen är utförda i den överordnade delen omfattning. Det ger oss en frihet att fylla mallen med anpassat innehåll från den överordnade delen.

5. Skapa fabriken för Markörer och Flerlinjer

Nu, när vi har vår karta redo, vi kommer att skapa två fabriken som kommer att användas för att lägga till element till TravelMap.

// GoogleMapMarker.vue
import { POINT_MARKER_ICON_CONFIG } från “@/konstanterna/mapSettings”;

export standard {
rekvisita: {
google: {
typ: Object,
krävs: sanna
},
karta: {
typ: Object,
krävs: sanna
},
markör: {
typ: Object,
krävs: sanna
}
},
monterad() {
ny här.google.kartor.Markör({
position: här.markör.position,
markör: det här.markör,
karta: här.karta
ikon: POINT_MARKER_ICON_CONFIG
});
},
};
// GoogleMapLine.vue
import { LINE_PATH_CONFIG } från “@/konstanterna/mapSettings”;

export standard {
rekvisita: {
google: {
typ: Object,
krävs: sanna
},
karta: {
typ: Object,
krävs: sanna
},
sökväg: {
typ: Array,
krävs: sanna
}
},
monterad() {
ny här.google.kartor.Polyline({
sökväg: här.väg,
karta: här.karta
…LINE_PATH_CONFIG
});
},
};

Båda dessa får google som vi använder för att extrahera den önskade objekt (Markör eller Polyline) samt karta som ger en hänvisning till den karta som vi vill att vår del.

Varje komponent förväntar sig också ett extra stöd för att skapa en motsvarande del. I detta fall har vi markör och väg, respektive.

På monterad krok, vi skapar en del (Markör/Polyline) och bifoga det till vår karta genom att skicka karta egendom till objektet konstruktör.

Det är ännu ett steg att gå…

6. Lägg till element till karta

Låt oss använda vår fabrik komponenter för att lägga till element till vår karta. Vi måste göra fabriken komponent och passera google och karta objekt så som data flödar till rätt platser.

Vi måste också tillhandahålla de uppgifter som krävs av element i sig. I vårt fall, som är markör för objekt med position markör och vägen objekt med Polyline koordinater.

Här går vi, att integrera data poäng direkt i mallen:

// TravelMap.vue
<mall>
<GoogleMapLoader
:mapConfig=”mapConfig”
apiKey=”yourApiKey”
>
<mallen slot-scope=”{ google, karta }”>
<GoogleMapMarker
v-for=”markör markörer”
:key=”markör.id”
:markör=”markör”
:google=”google”
:karta=”karta”
/>
<GoogleMapLine
v-for=”linje i linjer”
:key=”linje.id”
:väg.synkronisera=”linje.stig”
:google=”google”
:karta=”karta”
/>
</template>
</GoogleMapLoader>
</template>

Vi måste importera krävs fabriken i vårt manus och ange data som kommer att skickas till den markörer och linjer:

import { mapSettings } från “@/konstanterna/mapSettings”;

export standard {
komponenter: {
GoogleMapLoader,
GoogleMapMarker,
GoogleMapLine
},
data() {
return {
markörer: [
{ id: “en”, position: { lat: 3, lng: 101 } },
{ id: “b”, position: { lat: 5, lng: 99 } },
{ id: “c”, position: { lat: 6, lng: 97 } }
],
rader: [
{ id: “1”, stig: [{ lat: 3, lng: 101 }, { lat: 5, lng: 99 }] },
{ id: “2”, stig: [{ lat: 5, lng: 99 }, { lat: 6, lng: 97 }] }
]
};
},
beräknad: {
mapConfig() {
return {
…mapSettings,
center: här.albania
};
},
albania() {
tillbaka detta.markörer[1].ståndpunkt.
}
}
};

Och vi är klara!

Med alla dessa bitar avslutad, kan vi nu åter använda GoogleMapLoader komponent som en bas för alla våra kartor genom att skicka olika mallar för att var och en av dem. Föreställ dig att du behöver för att skapa en annan karta med olika Markörer eller bara Markörer utan Flerlinjer. Med hjälp av ett mönster av begränsad slots, blir det mycket lätt eftersom allt vi behöver till pass nu är att få olika innehåll till GoogleMapLoader komponent.

Detta mönster är inte strikt kopplad till Google Maps, det kan användas med alla bibliotek för att ställa in bas komponent och exponera bibliotekets API som kan användas i den del som kallas den komponent som bas.

Det kan vara frestande att skapa en mer komplex eller robust lösning, men detta får oss uttag som vi behöver och det blir en självständig del av vår kodbas. Om vi komma till den punkt, då kan det vara värt att tänka på utvinning av en add-on.