Vue

by kabanoki

HTML

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/portal-vue.umd.min.js"></script>
<div id="app">
  <div class="container">
    <card class="item left">
      <portal-target name="head"></portal-target>      
    </card>

    <card class="item right">
      <span><a href="#" @click.preven="show = 'A'">コンポーネントAを表示</a></span> | 
      <span><a href="#" @click.preven="show = 'B'">コンポーネントBを表示</a></span>
      <span><a href="#" @click.preven="show = 'C'">コンポーネントCを表示</a></span>
      <component-a v-if="show === 'A'"></component-a>
      <component-b v-if="show === 'B'"></component-b>
      <component-c v-if="show === 'C'"></component-c>
    </card>

    <card class="item left">
      <portal-target name="footer"></portal-target>      
    </card>
  </div>
</div>
  
<template id="A">
  <div>
    <p>
      コンポーネントA のサイドバーパーツ
    </p>
    <portal to="head">
      <h2>コンポーネントA</h2>
    </portal>
    <portal to="footer">
      <h2>コンポーネントAのフッター</h2>
    </portal>
  </div>
</template>

<template id ="B">
  <div>
    <p>
      コンポーネントB のサイドバーパーツ
    </p>
    <portal to="head">
      <h2>コンポーネントB</h2>
    </portal>
    <portal to="footer">
      <h2>コンポーネントBのフッター</h2>
    </portal>
  </div>
</template>

<template id ="C">
  <div>
    <p>
      コンポーネントC のサイドバーパーツ
    </p>
    <portal to="head">
      <h2>コンポーネントC</h2>
    </portal>
    <portal to="footer">
      <h2>コンポーネントCのフッター</h2>
    </portal>
  </div>
</template>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/portal-vue.umd.min.js"></script>

CSS

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

p{
  margin-top: 15px;
  margin-bottom: 15px;
}

Vue

const PortalVue = window['PortalVue'].default;
Vue.use(PortalVue);

Vue.component('card', {
  template: `
  <div class="item left">
    <slot />
  </div>
  `,
})

Vue.component('component-a', {
  template: '#A',
});

Vue.component('component-b', {
  template: '#B',
});

Vue.component('component-c', {
  template: '#C',
});

new Vue({
  el: '#app',
  data: {
    show: 'A',
  }
});