SlideShare une entreprise Scribd logo
1  sur  68
Télécharger pour lire hors ligne
VUE.JS SLOTS
Non farti sommergere dalle richieste di
personalizzazione!
COMMIT UNIVERSITY
Firenze, 19 Ottobre 2023
1
WHO AM I
Denny Biasiolli
Full Stack Developer
(JavaScript, Python, Go)
Front End Developer UX/ UI
Fingerprint Compliance Services Ltd.
Italy, Savigliano (CN)
@dennybiasiolli
denny.biasiolli@gmail.com
www.dennybiasiolli.com
2
Are you a lazy person?
3
Are you a lazy person?
(the really lazy ones wouldn't have raised their hand)
3.1
Bill Gates
I choose a lazy person to do a hard job.
Because a lazy person
will find an easy way to do it.
4
CUSTOMER'S FIRST REQUEST
Can you write a function that removes
all undefined values from an input
array?
5
FUNCTION SIGNATURE
export function removeUndefined<T>(array: T[]): T[] {
// ...
}
6
TDD APPROACH
import { it, expect } from 'vitest'
import { removeUndefined } from '../filtersV1'
it('removeUndefined removes `undefined` values', () => {
expect(
removeUndefined(['foo', undefined, 'bar'])
).toEqual(
['foo', 'bar']
)
})
7
IMPLEMENTATION
8
9
CUSTOMER'S CHANGE REQUEST
The function does not remove
null values!
10
FUNCTION SIGNATURE
(breaking change!)
// export function removeUndefined<T>(array: T[]): T[] {
export function customFilter<T>(
array: T[],
removeUndefined: boolean = true,
removeNull: boolean = false
): T[] {
// ...
}
11
IMPLEMENTATION
12
CUSTOMER'S CHANGE REQUEST
The function does not remove
empty values!
13
FUNCTION SIGNATURE
export function customFilter<T>(
array: T[],
removeUndefined: boolean = true,
removeNull: boolean = false,
+ removeEmpty: boolean = false
): T[] {
// ...
}
14
CUSTOMER'S CHANGE REQUESTS
The function does not remove
false values!
...zero values!
...zero as string values!
15
FUNCTION SIGNATURE
export function customFilter<T>(
array: T[],
removeUndefined: boolean = true,
removeNull: boolean = false,
removeEmpty: boolean = false,
+ removeFalse: boolean = false,
+ removeZero: boolean = false,
+ removeZeroString: boolean = false
): T[] {
// ...
}
16
IMPLEMENTATION
17
18
A smarter choice
19
IMPLEMENTATION
export function customFilter<T>(
array: T[],
filterFn: (element: T, index: number, array: T[]) => boolean
): T[] {
const retVal: T[] = []
for (let i = 0; i < array.length; i++) {
if (filterFn(array[i], i, array)) {
retVal.push(array[i])
}
}
return retVal
}
20
TESTS
it('should call the filterFn for each array element', () => {
const mockedFn = vi.fn().mockReturnValue(true)
const baseArray = ['foo', 'bar']
customFilter(baseArray, mockedFn)
expect(mockedFn).toHaveBeenCalledTimes(2);
for (let i = 0; i < baseArray.length; i++) {
expect(mockedFn).toHaveBeenNthCalledWith(
i + 1, baseArray[i], i, baseArray)
}
})
it('should filter when filterFn return value is truthy', () =>
const mockedFn = vi.fn()
.mockReturnValueOnce(true)
.mockReturnValueOnce(false)
.mockReturnValueOnce("123")
const retVal = customFilter(['foo', 'bar', 123], mockedFn)
expect(retVal).toEqual(['foo', 123])
})
21
USAGE
const myArray = ['foo', undefined, 'bar', null, false, '', 0,
customFilter(myArray, (elem) => (
elem !== undefined &&
elem !== null &&
elem !== false &&
elem !== '' &&
elem !== 0 &&
elem !== '0' &&
elem !== whateverValueIWantToExclude
))
22
FYI
Array.prototype.filter()
23
COMPONENTS PERSPECTIVE
Create a message box component
24
IMPLEMENTATION
export interface Props {
title?: string
message?: string
}
defineProps<Props>()
25
IMPLEMENTATION
<div class="message-box-title">
{{ title }}
</div>
<div class="message-box-message">
{{ message }}
</div>
26
POSSIBLE REQUESTS
custom title/message style
close button
footer section with
ok button
accept button
ok/cancel buttons
yes/no buttons
27
PSEUDO-IMPLEMENTATION
<div class="message-box-title">
{{ title || yourCustomTitleComponent }}
</div>
<div class="message-box-message">
{{ message || yourCustomMessageComponent }}
</div>
{{ yourCustomFooterComponent }}
28
29
WHAT ARE SLOTS IN VUE.JS?
A way to pass content to a component
30
USAGE OF SLOTS IN VUE.JS
1. define a section of a component’s template that can
be replaced by the parent component
2. the parent component controls the layout and
content of the child component
31
SLOT CONTENT AND OUTLET
1. allow a component to accept dynamic content
2. pass a template fragment to a child component
<button class="fancy-btn">
<slot></slot> <!-- slot outlet -->
</button>
<FancyButton>
Click me! <!-- slot content -->
</FancyButton>
32
SLOT CONTENT AND OUTLET
<button class="fancy-btn">Click me!</button>
33
SLOT CONTENT AND OUTLET
FancyButton is responsible for rendering the
outer <button> and its styling
the inner content (and its style) is provided by the
parent component
34
SLOT CONTENT AND OUTLET
Slot content is not just limited to text!
<FancyButton>
<span style="color:red">Click me!</span>
<AwesomeIcon name="plus" />
</FancyButton>
35
SLOT CONTENT AND OUTLET
<FancyButton> is flexible and reusable.
We can now use it in different places with different
inner content, but all with the same fancy styling.
36
RENDER SCOPE
Slot content
has access to the data scope of the parent
component
does not have access to the child component's data
<span>{{ message }}</span>
<FancyButton>{{ message }}</FancyButton>
37
FALLBACK CONTENT
Default value for a slot content
Rendered only when no content is provided
<button type="submit">
<slot>
Submit <!-- fallback content -->
</slot>
</button>
38
FALLBACK CONTENT
Examples
<SubmitButton />
<!-- rendered as -->
<button type="submit">Submit</button>
<SubmitButton>Save</SubmitButton>
<!-- rendered as -->
<button type="submit">Save</button>
39
NAMED SLOTS
Multiple slot outlets in the same component.
<div class="container">
<header>
<!-- We want header content here -->
</header>
<main>
<!-- We want main content here -->
</main>
<footer>
<!-- We want footer content here -->
</footer>
</div>
40
NAMED SLOTS
<slot> attribute name
<slot> without name
implicitly has the name "default".
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
41
PASSING NAMED SLOTS
<template> element with the v-slot directive
"#" can replace v-slot
<template v-slot:header>
<!-- content for the header slot -->
</template>
<template #header>
<!-- content for the header slot -->
</template>
42
PASSING NAMED SLOTS
43
PASSING NAMED SLOTS
<template #default> can be omitted
<BaseLayout>
<template #header>
<h1>Here might be a page title</h1>
</template>
<template #default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template #footer>
<p>Here's some contact info</p>
</template>
</BaseLayout>
44
PASSING NAMED SLOTS
is the same as
<BaseLayout>
<template #header>
<h1>Here might be a page title</h1>
</template>
<!-- implicit default slot -->
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template #footer>
<p>Here's some contact info</p>
</template>
</BaseLayout>
45
SCOPED SLOTS
Yes, but...
The parent component does not have
access to the child component's data
We can pass attributes to a slot outlet
46
SCOPED SLOTS
Passing attributes to a slot outlet
Receiving slot props in the template
<slot :text="greetingMessage" :count="1"></slot>
<MyComponent v-slot="slotProps">
{{ slotProps.text }} {{ slotProps.count }}
</MyComponent>
<!-- or -->
<MyComponent v-slot="{ text, count}">
{{ text }} {{ count }}
</MyComponent>
47
SCOPED SLOTS
48
SCOPED SLOTS
is the same as
<MyComponent v-slot="{ text, count}">
{{ text }} {{ count }}
</MyComponent>
<MyComponent>
<template #default="{ text, count}">
{{ text }} {{ count }}
</template>
</MyComponent>
49
NAMED SCOPED SLOTS
"name" is reserved, the scope will be
<slot name="header" message="hello"></slot>
{ message: 'hello' }
50
NAMED SCOPED SLOTS
<MyComponent>
<template #header="headerProps">
{{ headerProps }}
</template>
<template #default="defaultProps">
{{ defaultProps }}
</template>
<template #footer="footerProps">
{{ footerProps }}
</template>
</MyComponent>
51
NAMED SCOPED SLOTS
Where is the error?
<template>
<MyComponent v-slot="{ message }">
<p>{{ message }}</p>
<template #footer>
<p>{{ message }}</p>
</template>
</MyComponent>
</template>
52
NAMED SCOPED SLOTS
Where is the error?
<template>
<MyComponent>
<template #default="{ message }">
<p>{{ message }}</p>
</template>
<template #footer>
<!-- message belongs to the default slot
it is not available here -->
<p>{{ message }}</p>
</template>
</MyComponent>
</template>
53
Wait a minute
54
CUSTOMER'S REQUEST
Write a component to display the
composition of a pizza,
with crust style/composition, sauce
and toppings.
55
PIZZA COMPONENT
defineProps([
"name",
"crustStyle",
"crustComposition",
"sauce",
"topping",
])
56
PIZZA TEMPLATE
<div class="pizza-box">
<h1 class="pizza-title">{{ name }}</h1>
<slot name="pizza">
<!-- all other slots -->
</slot>
</div>
57
PIZZA TEMPLATE
<slot name="crust">
<div>
{{ crustStyle.name }}, with {{ crustComposition.name }}
</div>
</slot>
<slot name="sauce">
<div>{{ sauce.name }}</div>
</slot>
<slot name="toppings">
Toppings:
<ul>
<li v-for="topping in toppings" :key="topping.key">
<slot name="topping" :topping="topping">
{{ topping.name }}
</slot>
</li>
</ul>
</slot>
58
DEMO!
59
TEST TIME!
60
HOW TO TEST SLOTS?
Using @vue/test-utils
test-utils.vuejs.org/guide/advanced/slots.html
61
TESTING SLOTS
test('default content', () => {
const wrapper = mount(MyComponent)
expect(wrapper.html()).toMatchSnapshot()
})
62
TESTING SLOTS
test('default slot', () => {
const wrapper = mount(MyComponent, {
slots: {
default: 'Main Content'
}
})
// expect(wrapper.html()).toMatchSnapshot()
expect(wrapper.html()).toContain('Main Content')
// expect(wrapper.find('main').text()).toContain('Main Conte
})
63
TESTING SLOTS
test('named slots', () => {
const wrapper = mount(MyComponent, {
slots: {
header: '<div>Header</div>',
main: '<div>Main Content</div>',
footer: '<div>Footer</div>'
}
})
expect(wrapper.html()).toContain('<div>Header</div>')
expect(wrapper.html()).toContain('<div>Main Content</div>')
expect(wrapper.html()).toContain('<div>Footer</div>')
})
64
TESTING SLOTS
import { h } from 'vue'
import Header from './Header.vue'
test('advanced usage', () => {
const wrapper = mount(MyComponent, {
slots: {
header: Header,
main: h('div', 'Main Content'),
sidebar: { template: '<div>Sidebar</div>' },
footer: '<div>Footer</div>'
}
})
})
65
TESTING SLOTS
test('scoped slots', () => {
const wrapper = mount(MyComponent, {
slots: {
footer: `<template #footer="scopeObj">
{{ scopeObj.msg }}
</template>`,
// or
footer: `<template #footer="{ msg }">
{{ msg }}
</template>`,
// or
footer: '{{ params.msg }}'
}
})
})
66
THANK YOU!
Talk inspired by: "IOC, (inversion of control)" by Omar De Angelis
@dennybiasiolli
vuejs.org/guide/components/slots.html
test-utils.vuejs.org/guide/advanced/slots.html
github.com/dennybiasiolli/vue-slots-examples
www.dennybiasiolli.com
67

Contenu connexe

Similaire à Vue.js slots.pdf

Complete DB code following the instructions Implement the D.pdf
Complete DB code following the instructions Implement the D.pdfComplete DB code following the instructions Implement the D.pdf
Complete DB code following the instructions Implement the D.pdfaccess2future1
 
Python 내장 함수
Python 내장 함수Python 내장 함수
Python 내장 함수용 최
 
20.1 Java working with abstraction
20.1 Java working with abstraction20.1 Java working with abstraction
20.1 Java working with abstractionIntro C# Book
 
Documentation For Tab Setup
Documentation For Tab SetupDocumentation For Tab Setup
Documentation For Tab Setupvkeeton
 
JavaScript Objects and OOP Programming with JavaScript
JavaScript Objects and OOP Programming with JavaScriptJavaScript Objects and OOP Programming with JavaScript
JavaScript Objects and OOP Programming with JavaScriptLaurence Svekis ✔
 
Computer science-2010-cbse-question-paper
Computer science-2010-cbse-question-paperComputer science-2010-cbse-question-paper
Computer science-2010-cbse-question-paperDeepak Singh
 
Mocks Enabling Test-Driven Design
Mocks Enabling Test-Driven DesignMocks Enabling Test-Driven Design
Mocks Enabling Test-Driven DesignAlexandre Martins
 
Quest 1 define a class batsman with the following specifications
Quest  1 define a class batsman with the following specificationsQuest  1 define a class batsman with the following specifications
Quest 1 define a class batsman with the following specificationsrajkumari873
 
C++ Nested loops, matrix and fuctions.pdf
C++ Nested loops, matrix and fuctions.pdfC++ Nested loops, matrix and fuctions.pdf
C++ Nested loops, matrix and fuctions.pdfyamew16788
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with PythonHan Lee
 
Postgres can do THAT?
Postgres can do THAT?Postgres can do THAT?
Postgres can do THAT?alexbrasetvik
 
Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...
Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...
Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...takeoutweight
 
C-Sharp Arithmatic Expression Calculator
C-Sharp Arithmatic Expression CalculatorC-Sharp Arithmatic Expression Calculator
C-Sharp Arithmatic Expression CalculatorNeeraj Kaushik
 
C++ Searching & Sorting5. Sort the following list using the select.pdf
C++ Searching & Sorting5. Sort the following list using the select.pdfC++ Searching & Sorting5. Sort the following list using the select.pdf
C++ Searching & Sorting5. Sort the following list using the select.pdfRahul04August
 

Similaire à Vue.js slots.pdf (20)

Complete DB code following the instructions Implement the D.pdf
Complete DB code following the instructions Implement the D.pdfComplete DB code following the instructions Implement the D.pdf
Complete DB code following the instructions Implement the D.pdf
 
Python 내장 함수
Python 내장 함수Python 내장 함수
Python 내장 함수
 
20.1 Java working with abstraction
20.1 Java working with abstraction20.1 Java working with abstraction
20.1 Java working with abstraction
 
Documentation For Tab Setup
Documentation For Tab SetupDocumentation For Tab Setup
Documentation For Tab Setup
 
JavaScript Objects and OOP Programming with JavaScript
JavaScript Objects and OOP Programming with JavaScriptJavaScript Objects and OOP Programming with JavaScript
JavaScript Objects and OOP Programming with JavaScript
 
python modules1522.pdf
python modules1522.pdfpython modules1522.pdf
python modules1522.pdf
 
Computer science-2010-cbse-question-paper
Computer science-2010-cbse-question-paperComputer science-2010-cbse-question-paper
Computer science-2010-cbse-question-paper
 
Mocks Enabling Test-Driven Design
Mocks Enabling Test-Driven DesignMocks Enabling Test-Driven Design
Mocks Enabling Test-Driven Design
 
Quest 1 define a class batsman with the following specifications
Quest  1 define a class batsman with the following specificationsQuest  1 define a class batsman with the following specifications
Quest 1 define a class batsman with the following specifications
 
C++ Nested loops, matrix and fuctions.pdf
C++ Nested loops, matrix and fuctions.pdfC++ Nested loops, matrix and fuctions.pdf
C++ Nested loops, matrix and fuctions.pdf
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with Python
 
Postgres can do THAT?
Postgres can do THAT?Postgres can do THAT?
Postgres can do THAT?
 
Leveraging Symfony2 Forms
Leveraging Symfony2 FormsLeveraging Symfony2 Forms
Leveraging Symfony2 Forms
 
Managing console
Managing consoleManaging console
Managing console
 
Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...
Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...
Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...
 
Visual Basic 6.0
Visual Basic 6.0Visual Basic 6.0
Visual Basic 6.0
 
Rhino Mocks
Rhino MocksRhino Mocks
Rhino Mocks
 
C++ practical
C++ practicalC++ practical
C++ practical
 
C-Sharp Arithmatic Expression Calculator
C-Sharp Arithmatic Expression CalculatorC-Sharp Arithmatic Expression Calculator
C-Sharp Arithmatic Expression Calculator
 
C++ Searching & Sorting5. Sort the following list using the select.pdf
C++ Searching & Sorting5. Sort the following list using the select.pdfC++ Searching & Sorting5. Sort the following list using the select.pdf
C++ Searching & Sorting5. Sort the following list using the select.pdf
 

Plus de Commit University

Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Commit University
 
Breaking REST Chains_ A Fastify & Mercurius Pathway to GraphQL Glory.pdf
Breaking REST Chains_ A Fastify & Mercurius Pathway to GraphQL Glory.pdfBreaking REST Chains_ A Fastify & Mercurius Pathway to GraphQL Glory.pdf
Breaking REST Chains_ A Fastify & Mercurius Pathway to GraphQL Glory.pdfCommit University
 
Accelerating API Development: A Pit Stop with Gin-Gonic in Golang-Slide.pdf
Accelerating API Development: A Pit Stop with Gin-Gonic in Golang-Slide.pdfAccelerating API Development: A Pit Stop with Gin-Gonic in Golang-Slide.pdf
Accelerating API Development: A Pit Stop with Gin-Gonic in Golang-Slide.pdfCommit University
 
Collaborazione, Decisionalità e Gestione della Complessità nel Tempo: cosa ...
Collaborazione, Decisionalità e Gestione della Complessità nel Tempo: cosa ...Collaborazione, Decisionalità e Gestione della Complessità nel Tempo: cosa ...
Collaborazione, Decisionalità e Gestione della Complessità nel Tempo: cosa ...Commit University
 
Commit - Qwik il framework che ti stupirà.pptx
Commit - Qwik il framework che ti stupirà.pptxCommit - Qwik il framework che ti stupirà.pptx
Commit - Qwik il framework che ti stupirà.pptxCommit University
 
Sviluppare da zero una Angular Web App per la PA
Sviluppare da zero una Angular Web App per la PASviluppare da zero una Angular Web App per la PA
Sviluppare da zero una Angular Web App per la PACommit University
 
Backstage l'Internal Developer Portal Open Source per una migliore Developer ...
Backstage l'Internal Developer Portal Open Source per una migliore Developer ...Backstage l'Internal Developer Portal Open Source per una migliore Developer ...
Backstage l'Internal Developer Portal Open Source per una migliore Developer ...Commit University
 
Prisma the ORM that node was waiting for
Prisma the ORM that node was waiting forPrisma the ORM that node was waiting for
Prisma the ORM that node was waiting forCommit University
 
Decision-making for Software Development Teams - Commit University
Decision-making for Software Development Teams - Commit UniversityDecision-making for Software Development Teams - Commit University
Decision-making for Software Development Teams - Commit UniversityCommit University
 
Component Design Pattern nei Game Engine.pdf
Component Design Pattern nei Game Engine.pdfComponent Design Pattern nei Game Engine.pdf
Component Design Pattern nei Game Engine.pdfCommit University
 
Un viaggio alla scoperta dei Language Models e dell’intelligenza artificiale ...
Un viaggio alla scoperta dei Language Models e dell’intelligenza artificiale ...Un viaggio alla scoperta dei Language Models e dell’intelligenza artificiale ...
Un viaggio alla scoperta dei Language Models e dell’intelligenza artificiale ...Commit University
 
Prototipazione Low-Code con AWS Step Functions
Prototipazione Low-Code con AWS Step FunctionsPrototipazione Low-Code con AWS Step Functions
Prototipazione Low-Code con AWS Step FunctionsCommit University
 
KMM survival guide: how to tackle struggles between Kotlin and Swift
KMM survival guide: how to tackle struggles between Kotlin and SwiftKMM survival guide: how to tackle struggles between Kotlin and Swift
KMM survival guide: how to tackle struggles between Kotlin and SwiftCommit University
 
Da Vuex a Pinia: come fare la migrazione
Da Vuex a Pinia: come fare la migrazioneDa Vuex a Pinia: come fare la migrazione
Da Vuex a Pinia: come fare la migrazioneCommit University
 
Orchestrare Micro-frontend con micro-lc
Orchestrare Micro-frontend con micro-lcOrchestrare Micro-frontend con micro-lc
Orchestrare Micro-frontend con micro-lcCommit University
 
Fastify has defeated Lagacy-Code
Fastify has defeated Lagacy-CodeFastify has defeated Lagacy-Code
Fastify has defeated Lagacy-CodeCommit University
 
Alpine.js: the outsider Javascript framework
Alpine.js: the outsider Javascript frameworkAlpine.js: the outsider Javascript framework
Alpine.js: the outsider Javascript frameworkCommit University
 

Plus de Commit University (20)

Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)
 
Breaking REST Chains_ A Fastify & Mercurius Pathway to GraphQL Glory.pdf
Breaking REST Chains_ A Fastify & Mercurius Pathway to GraphQL Glory.pdfBreaking REST Chains_ A Fastify & Mercurius Pathway to GraphQL Glory.pdf
Breaking REST Chains_ A Fastify & Mercurius Pathway to GraphQL Glory.pdf
 
Accelerating API Development: A Pit Stop with Gin-Gonic in Golang-Slide.pdf
Accelerating API Development: A Pit Stop with Gin-Gonic in Golang-Slide.pdfAccelerating API Development: A Pit Stop with Gin-Gonic in Golang-Slide.pdf
Accelerating API Development: A Pit Stop with Gin-Gonic in Golang-Slide.pdf
 
Slide-10years.pdf
Slide-10years.pdfSlide-10years.pdf
Slide-10years.pdf
 
Collaborazione, Decisionalità e Gestione della Complessità nel Tempo: cosa ...
Collaborazione, Decisionalità e Gestione della Complessità nel Tempo: cosa ...Collaborazione, Decisionalità e Gestione della Complessità nel Tempo: cosa ...
Collaborazione, Decisionalità e Gestione della Complessità nel Tempo: cosa ...
 
Commit - Qwik il framework che ti stupirà.pptx
Commit - Qwik il framework che ti stupirà.pptxCommit - Qwik il framework che ti stupirà.pptx
Commit - Qwik il framework che ti stupirà.pptx
 
Sviluppare da zero una Angular Web App per la PA
Sviluppare da zero una Angular Web App per la PASviluppare da zero una Angular Web App per la PA
Sviluppare da zero una Angular Web App per la PA
 
Backstage l'Internal Developer Portal Open Source per una migliore Developer ...
Backstage l'Internal Developer Portal Open Source per una migliore Developer ...Backstage l'Internal Developer Portal Open Source per una migliore Developer ...
Backstage l'Internal Developer Portal Open Source per una migliore Developer ...
 
Prisma the ORM that node was waiting for
Prisma the ORM that node was waiting forPrisma the ORM that node was waiting for
Prisma the ORM that node was waiting for
 
Decision-making for Software Development Teams - Commit University
Decision-making for Software Development Teams - Commit UniversityDecision-making for Software Development Teams - Commit University
Decision-making for Software Development Teams - Commit University
 
Component Design Pattern nei Game Engine.pdf
Component Design Pattern nei Game Engine.pdfComponent Design Pattern nei Game Engine.pdf
Component Design Pattern nei Game Engine.pdf
 
Un viaggio alla scoperta dei Language Models e dell’intelligenza artificiale ...
Un viaggio alla scoperta dei Language Models e dell’intelligenza artificiale ...Un viaggio alla scoperta dei Language Models e dell’intelligenza artificiale ...
Un viaggio alla scoperta dei Language Models e dell’intelligenza artificiale ...
 
Prototipazione Low-Code con AWS Step Functions
Prototipazione Low-Code con AWS Step FunctionsPrototipazione Low-Code con AWS Step Functions
Prototipazione Low-Code con AWS Step Functions
 
KMM survival guide: how to tackle struggles between Kotlin and Swift
KMM survival guide: how to tackle struggles between Kotlin and SwiftKMM survival guide: how to tackle struggles between Kotlin and Swift
KMM survival guide: how to tackle struggles between Kotlin and Swift
 
Da Vuex a Pinia: come fare la migrazione
Da Vuex a Pinia: come fare la migrazioneDa Vuex a Pinia: come fare la migrazione
Da Vuex a Pinia: come fare la migrazione
 
Orchestrare Micro-frontend con micro-lc
Orchestrare Micro-frontend con micro-lcOrchestrare Micro-frontend con micro-lc
Orchestrare Micro-frontend con micro-lc
 
Fastify has defeated Lagacy-Code
Fastify has defeated Lagacy-CodeFastify has defeated Lagacy-Code
Fastify has defeated Lagacy-Code
 
SwiftUI vs UIKit
SwiftUI vs UIKitSwiftUI vs UIKit
SwiftUI vs UIKit
 
Alpine.js: the outsider Javascript framework
Alpine.js: the outsider Javascript frameworkAlpine.js: the outsider Javascript framework
Alpine.js: the outsider Javascript framework
 

Dernier

The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 

Dernier (20)

The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 

Vue.js slots.pdf

  • 1. VUE.JS SLOTS Non farti sommergere dalle richieste di personalizzazione! COMMIT UNIVERSITY Firenze, 19 Ottobre 2023 1
  • 2. WHO AM I Denny Biasiolli Full Stack Developer (JavaScript, Python, Go) Front End Developer UX/ UI Fingerprint Compliance Services Ltd. Italy, Savigliano (CN) @dennybiasiolli denny.biasiolli@gmail.com www.dennybiasiolli.com 2
  • 3. Are you a lazy person? 3
  • 4. Are you a lazy person? (the really lazy ones wouldn't have raised their hand) 3.1
  • 5. Bill Gates I choose a lazy person to do a hard job. Because a lazy person will find an easy way to do it. 4
  • 6. CUSTOMER'S FIRST REQUEST Can you write a function that removes all undefined values from an input array? 5
  • 7. FUNCTION SIGNATURE export function removeUndefined<T>(array: T[]): T[] { // ... } 6
  • 8. TDD APPROACH import { it, expect } from 'vitest' import { removeUndefined } from '../filtersV1' it('removeUndefined removes `undefined` values', () => { expect( removeUndefined(['foo', undefined, 'bar']) ).toEqual( ['foo', 'bar'] ) }) 7
  • 10. 9
  • 11. CUSTOMER'S CHANGE REQUEST The function does not remove null values! 10
  • 12. FUNCTION SIGNATURE (breaking change!) // export function removeUndefined<T>(array: T[]): T[] { export function customFilter<T>( array: T[], removeUndefined: boolean = true, removeNull: boolean = false ): T[] { // ... } 11
  • 14. CUSTOMER'S CHANGE REQUEST The function does not remove empty values! 13
  • 15. FUNCTION SIGNATURE export function customFilter<T>( array: T[], removeUndefined: boolean = true, removeNull: boolean = false, + removeEmpty: boolean = false ): T[] { // ... } 14
  • 16. CUSTOMER'S CHANGE REQUESTS The function does not remove false values! ...zero values! ...zero as string values! 15
  • 17. FUNCTION SIGNATURE export function customFilter<T>( array: T[], removeUndefined: boolean = true, removeNull: boolean = false, removeEmpty: boolean = false, + removeFalse: boolean = false, + removeZero: boolean = false, + removeZeroString: boolean = false ): T[] { // ... } 16
  • 19. 18
  • 21. IMPLEMENTATION export function customFilter<T>( array: T[], filterFn: (element: T, index: number, array: T[]) => boolean ): T[] { const retVal: T[] = [] for (let i = 0; i < array.length; i++) { if (filterFn(array[i], i, array)) { retVal.push(array[i]) } } return retVal } 20
  • 22. TESTS it('should call the filterFn for each array element', () => { const mockedFn = vi.fn().mockReturnValue(true) const baseArray = ['foo', 'bar'] customFilter(baseArray, mockedFn) expect(mockedFn).toHaveBeenCalledTimes(2); for (let i = 0; i < baseArray.length; i++) { expect(mockedFn).toHaveBeenNthCalledWith( i + 1, baseArray[i], i, baseArray) } }) it('should filter when filterFn return value is truthy', () => const mockedFn = vi.fn() .mockReturnValueOnce(true) .mockReturnValueOnce(false) .mockReturnValueOnce("123") const retVal = customFilter(['foo', 'bar', 123], mockedFn) expect(retVal).toEqual(['foo', 123]) }) 21
  • 23. USAGE const myArray = ['foo', undefined, 'bar', null, false, '', 0, customFilter(myArray, (elem) => ( elem !== undefined && elem !== null && elem !== false && elem !== '' && elem !== 0 && elem !== '0' && elem !== whateverValueIWantToExclude )) 22
  • 25. COMPONENTS PERSPECTIVE Create a message box component 24
  • 26. IMPLEMENTATION export interface Props { title?: string message?: string } defineProps<Props>() 25
  • 27. IMPLEMENTATION <div class="message-box-title"> {{ title }} </div> <div class="message-box-message"> {{ message }} </div> 26
  • 28. POSSIBLE REQUESTS custom title/message style close button footer section with ok button accept button ok/cancel buttons yes/no buttons 27
  • 29. PSEUDO-IMPLEMENTATION <div class="message-box-title"> {{ title || yourCustomTitleComponent }} </div> <div class="message-box-message"> {{ message || yourCustomMessageComponent }} </div> {{ yourCustomFooterComponent }} 28
  • 30. 29
  • 31. WHAT ARE SLOTS IN VUE.JS? A way to pass content to a component 30
  • 32. USAGE OF SLOTS IN VUE.JS 1. define a section of a component’s template that can be replaced by the parent component 2. the parent component controls the layout and content of the child component 31
  • 33. SLOT CONTENT AND OUTLET 1. allow a component to accept dynamic content 2. pass a template fragment to a child component <button class="fancy-btn"> <slot></slot> <!-- slot outlet --> </button> <FancyButton> Click me! <!-- slot content --> </FancyButton> 32
  • 34. SLOT CONTENT AND OUTLET <button class="fancy-btn">Click me!</button> 33
  • 35. SLOT CONTENT AND OUTLET FancyButton is responsible for rendering the outer <button> and its styling the inner content (and its style) is provided by the parent component 34
  • 36. SLOT CONTENT AND OUTLET Slot content is not just limited to text! <FancyButton> <span style="color:red">Click me!</span> <AwesomeIcon name="plus" /> </FancyButton> 35
  • 37. SLOT CONTENT AND OUTLET <FancyButton> is flexible and reusable. We can now use it in different places with different inner content, but all with the same fancy styling. 36
  • 38. RENDER SCOPE Slot content has access to the data scope of the parent component does not have access to the child component's data <span>{{ message }}</span> <FancyButton>{{ message }}</FancyButton> 37
  • 39. FALLBACK CONTENT Default value for a slot content Rendered only when no content is provided <button type="submit"> <slot> Submit <!-- fallback content --> </slot> </button> 38
  • 40. FALLBACK CONTENT Examples <SubmitButton /> <!-- rendered as --> <button type="submit">Submit</button> <SubmitButton>Save</SubmitButton> <!-- rendered as --> <button type="submit">Save</button> 39
  • 41. NAMED SLOTS Multiple slot outlets in the same component. <div class="container"> <header> <!-- We want header content here --> </header> <main> <!-- We want main content here --> </main> <footer> <!-- We want footer content here --> </footer> </div> 40
  • 42. NAMED SLOTS <slot> attribute name <slot> without name implicitly has the name "default". <div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> 41
  • 43. PASSING NAMED SLOTS <template> element with the v-slot directive "#" can replace v-slot <template v-slot:header> <!-- content for the header slot --> </template> <template #header> <!-- content for the header slot --> </template> 42
  • 45. PASSING NAMED SLOTS <template #default> can be omitted <BaseLayout> <template #header> <h1>Here might be a page title</h1> </template> <template #default> <p>A paragraph for the main content.</p> <p>And another one.</p> </template> <template #footer> <p>Here's some contact info</p> </template> </BaseLayout> 44
  • 46. PASSING NAMED SLOTS is the same as <BaseLayout> <template #header> <h1>Here might be a page title</h1> </template> <!-- implicit default slot --> <p>A paragraph for the main content.</p> <p>And another one.</p> <template #footer> <p>Here's some contact info</p> </template> </BaseLayout> 45
  • 47. SCOPED SLOTS Yes, but... The parent component does not have access to the child component's data We can pass attributes to a slot outlet 46
  • 48. SCOPED SLOTS Passing attributes to a slot outlet Receiving slot props in the template <slot :text="greetingMessage" :count="1"></slot> <MyComponent v-slot="slotProps"> {{ slotProps.text }} {{ slotProps.count }} </MyComponent> <!-- or --> <MyComponent v-slot="{ text, count}"> {{ text }} {{ count }} </MyComponent> 47
  • 50. SCOPED SLOTS is the same as <MyComponent v-slot="{ text, count}"> {{ text }} {{ count }} </MyComponent> <MyComponent> <template #default="{ text, count}"> {{ text }} {{ count }} </template> </MyComponent> 49
  • 51. NAMED SCOPED SLOTS "name" is reserved, the scope will be <slot name="header" message="hello"></slot> { message: 'hello' } 50
  • 52. NAMED SCOPED SLOTS <MyComponent> <template #header="headerProps"> {{ headerProps }} </template> <template #default="defaultProps"> {{ defaultProps }} </template> <template #footer="footerProps"> {{ footerProps }} </template> </MyComponent> 51
  • 53. NAMED SCOPED SLOTS Where is the error? <template> <MyComponent v-slot="{ message }"> <p>{{ message }}</p> <template #footer> <p>{{ message }}</p> </template> </MyComponent> </template> 52
  • 54. NAMED SCOPED SLOTS Where is the error? <template> <MyComponent> <template #default="{ message }"> <p>{{ message }}</p> </template> <template #footer> <!-- message belongs to the default slot it is not available here --> <p>{{ message }}</p> </template> </MyComponent> </template> 53
  • 56. CUSTOMER'S REQUEST Write a component to display the composition of a pizza, with crust style/composition, sauce and toppings. 55
  • 58. PIZZA TEMPLATE <div class="pizza-box"> <h1 class="pizza-title">{{ name }}</h1> <slot name="pizza"> <!-- all other slots --> </slot> </div> 57
  • 59. PIZZA TEMPLATE <slot name="crust"> <div> {{ crustStyle.name }}, with {{ crustComposition.name }} </div> </slot> <slot name="sauce"> <div>{{ sauce.name }}</div> </slot> <slot name="toppings"> Toppings: <ul> <li v-for="topping in toppings" :key="topping.key"> <slot name="topping" :topping="topping"> {{ topping.name }} </slot> </li> </ul> </slot> 58
  • 62. HOW TO TEST SLOTS? Using @vue/test-utils test-utils.vuejs.org/guide/advanced/slots.html 61
  • 63. TESTING SLOTS test('default content', () => { const wrapper = mount(MyComponent) expect(wrapper.html()).toMatchSnapshot() }) 62
  • 64. TESTING SLOTS test('default slot', () => { const wrapper = mount(MyComponent, { slots: { default: 'Main Content' } }) // expect(wrapper.html()).toMatchSnapshot() expect(wrapper.html()).toContain('Main Content') // expect(wrapper.find('main').text()).toContain('Main Conte }) 63
  • 65. TESTING SLOTS test('named slots', () => { const wrapper = mount(MyComponent, { slots: { header: '<div>Header</div>', main: '<div>Main Content</div>', footer: '<div>Footer</div>' } }) expect(wrapper.html()).toContain('<div>Header</div>') expect(wrapper.html()).toContain('<div>Main Content</div>') expect(wrapper.html()).toContain('<div>Footer</div>') }) 64
  • 66. TESTING SLOTS import { h } from 'vue' import Header from './Header.vue' test('advanced usage', () => { const wrapper = mount(MyComponent, { slots: { header: Header, main: h('div', 'Main Content'), sidebar: { template: '<div>Sidebar</div>' }, footer: '<div>Footer</div>' } }) }) 65
  • 67. TESTING SLOTS test('scoped slots', () => { const wrapper = mount(MyComponent, { slots: { footer: `<template #footer="scopeObj"> {{ scopeObj.msg }} </template>`, // or footer: `<template #footer="{ msg }"> {{ msg }} </template>`, // or footer: '{{ params.msg }}' } }) }) 66
  • 68. THANK YOU! Talk inspired by: "IOC, (inversion of control)" by Omar De Angelis @dennybiasiolli vuejs.org/guide/components/slots.html test-utils.vuejs.org/guide/advanced/slots.html github.com/dennybiasiolli/vue-slots-examples www.dennybiasiolli.com 67