\
take a component
<component-name></component-name>
in html <a>ssfs</a>
like this we can write in betewen ending and starting tag <component-name>name</compoinent-name>
thats called slot
slots is a defailt html tag and it represents placeholder in the compoinetn tree
with attribut emethod
<app-button
name="vamsi"
></app-button>
<template>
<button>{{name}}</button>
</template>
<script>
export default {
name: 'App Button',
props:{
name:{
type: String,
required: true,
},
},
with html mehtod
<app-slot-button
>press me</app-slot-button>
<template>
<button><slot></slot></button>
</template>
everything we pass via attributes,props,eventlistenrs,slots <app-slot-button
@click="log"
const log = () =>{
console.log('works');
};
component
<template>
<button v-on="$listeners"><slot></slot></button>
</template>
<script>
export default {
name: 'App Slot Button',
props:{
},
components: {
},
data() {
return {
};
},
mounted(){
},
computed: {
},
methods:{
},
};
</script>
<app-slot-button
>press me</app-slot-button>
named slots
multiple slots in components
named slots
<app-layout
>
<template v-slot:header>slots are awesome </template>
<template v-slot:main>slots are main </template>
<app-slot-button
@click="log"
>press me</app-slot-button>
<template v-slot:footer>slots are footer </template>
</app-layout>
import AppSlotButton from '../../components/AppSlotButton.vue';
import AppLayout from '../../components/AppLayout.vue';
const log = () =>{
console.log('works');
};
<template>
<button>
<slot></slot></button>
</template>
<script>
export default {
name: 'App Slot Button',
props:{
},
components: {
},
data() {
return {
};
},
mounted(){
},
computed: {
},
methods:{
},
};
</script>
<template>
<header> <slot name="header" /></header>
<main> <slot name="main" /> </main>
<footer> <slot name="footer" /> </footer>
<button>
<slot></slot></button>
</template>
<script>
export default {
name: 'App Layout',
props:{
},
components: {
},
data() {
return {
};
},
mounted(){
},
computed: {
},
methods:{
},
};
</script>
short hand for named slots
<app-layout
>
<template #header>slots are awesome </template>
<template #main>slots are main </template>
<app-slot-button
@click="log"
>press me</app-slot-button>
<template #footer>slots are footer </template>
</app-layout>
reuable vuesjs component with slots
oce we have prop we can render it
passing data to parent component using scoped slot
attribute bound to slot elements that are alled slot props
<slot name="footer" :item="item" />
Refactor User List Component Using Slots
falll back content to slots
user.location.country
nesting slotsslot with condition
if slot not required we wil l not call that slot
in some components
with count
usign scoped slots with function
pass data to parent compoent
app.vue
https://github.com/vueschool/reusable-vuejs-components-with-slotss
app.vue
<template>
<div class="page">
<select v-model="selected">
<option
v-for="option in options"
:value="option.value"
:key="option.value">
{{option.label}}
</option>
</select>
<AppUserList >
<template #secondrow="slotProps">{{slotProps}}</template>
<template #loading>
<b-spinner class="align-middle"></b-spinner>
</template>
</AppUserList>
</div>
</template>
<script>
import AppUserList from "../../components/AppUserListThree";
import AppUserCardsList from "../../components/AppUserCardsList";
export default {
components: {
AppUserList,
AppUserCardsList
},
data() {
return {
selected: 'first',
options: [
{ value: 'first', label: 'first name'},
{ value: 'last', label: 'last name'},
{ value: 'full', label: 'fullname'},
{ value: 'fullWithTitle', label: 'fullname with title'},
]
}
},
methods: {
getEmail(user) {
return user.email;
}
}
};
</script>
<style>
.page {
padding: 2rem;
}
.page > * + * {
margin-top: 2rem;
}
</style>
appuserlist.vue
<template>
<section>
<slot name="title">Users</slot>
<slot
name="userlist"
:count="data.results.length"
:list="data.results"
:remove="remove"
v-if="state === 'loaded'"
>
<ul class="userlist">
<li v-for="item in data.results" :key="item.email">
<slot name="listitem" :user="item">
<div>
<img
width="48"
height="48"
:src="item.picture.large"
:alt="item.name.first + ' ' + item.name.last"
/>
<div>
<div>{{ item.name.first }}</div>
<slot name="secondrow" :item="item"></slot>
<!-- {{secondrow(item)}} -->
</div>
</div>
</slot>
</li>
</ul>
</slot>
<slot v-else name="loading">
loading...
</slot>
<slot v-if="state === 'failed'" name="error">
Oops, something went wrong.
</slot>
</section>
</template>
<script>
const states = {
idle: "idle",
loading: "loading",
loaded: "loaded",
failed: "failed"
};
export default {
props: {
secondrow: {
type: Function,
default: () => {}
}
},
data() {
return {
state: "idle",
data: undefined,
error: undefined,
states
};
},
mounted() {
this.load();
},
methods: {
async load() {
this.state = "loading";
this.error = undefined;
this.data = undefined;
try {
setTimeout(async () => {
const response = await fetch("https://randomuser.me/api/?results=5");
const json = await response.json();
this.state = "loaded";
this.data = json;
return response;
}, 1000);
} catch (error) {
this.state = "failed";
this.error = error;
return error;
}
},
remove(item) {
this.data.results = this.data.results.filter(entry => entry.email !== item.email)
}
}
};
</script>
<style scoped>
.userlist {
margin: 10px;
}
.userlist img {
border-radius: 50%;
margin-right: 1rem;
}
.userlist li + li {
margin-top: 10px;
}
.userlist li > div {
display: flex;
align-items: center;
}
.userlist li div div {
flex: 1;
}
</style>
<template #listitem="{user}">
{{user}}
</template>
<slot name="listitem" :user="item">
<div>
<img
width="48"
height="48"
:src="item.picture.large"
:alt="item.name.first + ' ' + item.name.last"
/>
<div>
<div>{{ item.name.first }}</div>
<slot name="secondrow" :item="item"></slot>
<!-- {{secondrow(item)}} -->
</div>
</div>
</slot>
<template #userlist="{list, count}">
{{count}}
{{list}}
</template>
<slot
name="userlist"
:count="data.results.length"
:list="data.results"
:remove="remove"
v-if="state === 'loaded'"
>
<ul class="userlist">
<li v-for="item in data.results" :key="item.email">
<slot name="listitem" :user="item">
<div>
<img
width="48"
height="48"
:src="item.picture.large"
:alt="item.name.first + ' ' + item.name.last"
/>
<div>
<div>{{ item.name.first }}</div>
<slot name="secondrow" :item="item"></slot>
<!-- {{secondrow(item)}} -->
</div>
</div>
</slot>
</li>
</ul>
</slot>
we are passign props to appusercards list
<template #userlist="{list, count}">
{{count}}
<AppUserCardsList :list="list"/>
</template>
<template #secondrow="{remove, item:user}">
<button @click="remove(user)">{{user.name.first}}<button>
</template>
item is equal tto user
remove the user
<template #secondrow="{remove, item:user}">
<button @click="remove(user)">{{user.name.first}}</button>
</template>
<slot name="secondrow" :item="item" :remove="remove"></slot>
remove(item) {
this.data.results = this.data.results.filter(entry => entry.email !== item.email)
}
========
s