Content Distribution

https://goo.gl/ttW89y

#vuelondon / Blake Newman / @blakenewman

What is content distribution?

Interweave the parent “content” and the component’s own template

Default List Component

Custom list componet

List component

<template>
    <ul>
        <li v-for="item in data">{{ item }}</li>
    </ul>
</template>

<script>
    export default {
        props: {
            data: Array,
        },
    };
</script>

<style>
    // Custom Styles
</style>

Implementation

<template>
    <list :data="[...]" />
</template>

<script>
    import List from '@component/list';

    export default {
        components: {
            List,
        },
    };
</script>

Output

List component with image

<template>
    <ul>
        <li v-for="item in data">
            {{ item }}
            <img v-if="item === 'A User'"
                 :src="require('@asset/logo.png')" 
                 alt="A User Image"
                 width="10px"
                 height="10px" />
        </li>
    </ul>
</template>

<script>
    export default {
        props: {
            data: Array,
        },
    };
</script>

Implementation

<template>
    <list :data="[...]" />
</template>

<script>
    import List from '@component/list';

    export default {
        components: {
            List,
        },
    };
</script>

Output

Meh :/

Slots

<!-- AppLayout.vue -->
<template>
    <div class="container">
        <header>
            <slot name="header" />
        </header>
        <main>
            <slot />
        </main>
        <footer>
            <slot name="footer" />
        </footer>
    </div>
</template>

<!-- Parent implementing AppLayout.vue -->
<app-layout>
    <h1 slot="header">Here might be a page title</h1>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
    <p slot="footer">Here's some contact info</p>
</app-layout>

Slots - output

<div class="container">
    <header>
        <h1>Here might be a page title</h1>
    </header>
    <main>
        <p>A paragraph for the main content.</p>
        <p>And another one.</p>
    </main>
    <footer>
        <p>Here's some contact info</p>
    </footer>
</div>

List component with slot

<template>
    <ul>
        <li v-for="item in data">
            {{ item }}
            <slot />
        </li>
    </ul>
</template>

<script>
    export default {
        props: {
            data: Array,
        },
    };
</script>

Implementation

<template>
    <list :data="[...]">
        <img v-if="item === 'A User'"
             :src="require('@asset/logo.png')" 
             alt="A User Image"
             width="10px"
             height="10px" />
    </list>
</template>

<script>
    import List from '@component/list';

    export default {
        components: {
            List,
        },
    };
</script>

Output

Meh :/

List component with scoped slot

(Version 2.1+)

<template>
    <ul>
        <slot name="item"
              v-for="item in data"
              :text="item">
              {{ item }} <!-- Fallback Content -->
        </slot>
    </ul>
</template>

<script>
    export default {
        props: {
            data: Array,
        },
    };
</script>

Implementation

<template>
    <list :data="[...]">
        <template scope="child" v-if="child.text === 'A User'">
            {{ child.text }}
            <img :src="require('@asset/logo.png')" 
                 alt="A User Image"
                 width="10px"
                 height="10px" />
        </template>
    </list>
</template>

<script>
    import List from '@component/list';

    export default {
        components: {
            List,
        },
    };
</script>

Output

Yay :)

VueConf 2017

conf.vuejs.org

Wrocław, Poland - 2017

The official Vue.js Conference

Content Distribution (Vue.js)

By Blake Newman

Content Distribution (Vue.js)

Best practices for content distribution with slots within Vue.js Applications. London Vue.js Meetup #4 (Lightning Talk)

  • 2,168