Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Vue.js × Atomic Design - コンポーネント分割の指針 / Vue.js ...

nrs
July 10, 2019

Vue.js × Atomic Design - コンポーネント分割の指針 / Vue.js and Atomic Design - Guideline for components division

Vue.js 講演用資料です。

# 概要
コンポーネントをどのような粒度で分割し、どのように実装するべきかというのは難しいテーマです。
一概に正解があるとも言い切れないテーマですが、この指針を疎かにすることはチームを混乱に陥れることと同義です。
それが SPA 未経験のチームであればなおさらです。
直近のプロジェクトはまさにそんなプロジェクトでした。
本セッションではアトミックデザインのエッセンスを用いてコンポーネント分割の指針を示し、
またコンポーネント実装時に注意すべき事柄についてお話します

# URL
HomePage: https://nrslib.com
Twitter: https://twitter.com/nrslib

nrs

July 10, 2019
Tweet

More Decks by nrs

Other Decks in Programming

Transcript

  1. <template> <dl> <dt>Name</dt><dd>{{name}}</dd> <dt>Job</dt><dd>{{job}}</dd> <dt>Company</dt><dd>{{company}}</dd> <dt>Twitter</dt><dd>{{twitter}}</dd> </dl> </template> <script lang="ts">

    import { Component, Vue } from 'vue-property-decorator'; @Component export default class MyProfile extends Vue { public name: string = 'Masanobu Naruse'; public jobs: string[]= ['Programmer', 'Developer Evangelist']; public company: string = 'GMO Internet, Inc.'; public twitter: string = '@nrslib'; public get job(): string { return this.jobs.join(', '); } } </script>
  2. © 2019 narusemi All rights reserved. INFORMATION TOP ABOUT ME

    https://nrslib.com HP @nrslib Twitter Masanobu Naruse Name TOP > ABOUT ME BLOG Search Search Nrs Seminar https://nrslib.com HP @nrslib Twitter UX UI / DevRel. Team GMO Internet, Inc. Company Programmer / Developer Evangelist Job Masanobu Naruse Name
  3. Nrs Seminar https://nrslib.com HP @nrslib Twitter UX UI / DevRel.

    Team GMO Internet, Inc. Company Programmer / Developer Evangelist Job Masanobu Naruse Name Search Search © 2019 narusemi All rights reserved. INFORMATION TOP ABOUT ME https://nrslib.com HP @nrslib Twitter Masanobu Naruse Name TOP > ABOUT ME BLOG Logo
  4. https://nrslib.com HP @nrslib Twitter UX UI / DevRel. Team GMO

    Internet, Inc. Company Programmer / Developer Evangelist Job Masanobu Naruse Name Search Search © 2019 narusemi All rights reserved. INFORMATION TOP ABOUT ME https://nrslib.com HP @nrslib Twitter Masanobu Naruse Name TOP > ABOUT ME BLOG HeaderTitle Nrs Seminar
  5. Nrs Seminar https://nrslib.com HP @nrslib Twitter UX UI / DevRel.

    Team GMO Internet, Inc. Company Programmer / Developer Evangelist Job Masanobu Naruse Name TOP Search © 2019 narusemi All rights reserved. INFORMATION ABOUT ME https://nrslib.com HP @nrslib Twitter Masanobu Naruse Name TOP > ABOUT ME BLOG TextBox Search
  6. Nrs Seminar https://nrslib.com HP @nrslib Twitter UX UI / DevRel.

    Team GMO Internet, Inc. Company Programmer / Developer Evangelist Job Masanobu Naruse Name Search TOP © 2019 narusemi All rights reserved. INFORMATION ABOUT ME https://nrslib.com HP @nrslib Twitter Masanobu Naruse Name TOP > ABOUT ME BLOG PrimaryButton Search
  7. Nrs Seminar https://nrslib.com HP @nrslib Twitter UX UI / DevRel.

    Team GMO Internet, Inc. Company Programmer / Developer Evangelist Job Masanobu Naruse Name Search Search © 2019 narusemi All rights reserved. INFORMATION ABOUT ME https://nrslib.com HP @nrslib Twitter Masanobu Naruse Name TOP > ABOUT ME BLOG SideMenuButton TOP
  8. Nrs Seminar https://nrslib.com HP @nrslib Twitter UX UI / DevRel.

    Team GMO Internet, Inc. Company Programmer / Developer Evangelist Job Masanobu Naruse Name Search Search TOP © 2019 narusemi All rights reserved. INFORMATION ABOUT ME https://nrslib.com HP @nrslib Twitter Masanobu Naruse Name BLOG TOP > ABOUT ME BreadCrumb
  9. Nrs Seminar https://nrslib.com HP @nrslib Twitter UX UI / DevRel.

    Team GMO Internet, Inc. Company Programmer / Developer Evangelist Job Masanobu Naruse Name Search Search TOP © 2019 narusemi All rights reserved. INFORMATION ABOUT ME https://nrslib.com HP @nrslib Twitter Masanobu Naruse TOP > ABOUT ME BLOG TableCell Name
  10. HomePageTitle Placeholder Button SideMenuButton BreadCrumb > TableCell HomePageTitle Button Placeholder

    HomePageTitle Search Search TOP INFORMATION ABOUT ME BLOG TableCell TableCell
  11. HomePageTitle Placeholder Button SideMenuButton BreadCrumb > TableCell HomePageTitle Button Placeholder

    HomePageTitle Search Search TOP INFORMATION ABOUT ME BLOG TableCell TableCell
  12. HomePageTitle Placeholder Button SideMenuButton BreadCrumb > TableCell HomePageTitle Button Placeholder

    HomePageTitle Search Search BreadCrumb > BreadCrumb TOP INFORMATION ABOUT ME BLOG TableCell TableCell
  13. HomePageTitle Placeholder Button SideMenuButton BreadCrumb > TableCell HomePageTitle Button Placeholder

    TableCell TableCell HomePageTitle Search Search BreadCrumb > BreadCrumb TOP INFORMATION ABOUT ME BLOG
  14. HomePageTitle Placeholder Button SideMenuButton BreadCrumb > TableCell HomePageTitle Button Placeholder

    TableCell TableCell HomePageTitle Search Search TableCell TableCell TableCell TableCell TableCell TableCell BreadCrumb > BreadCrumb TOP INFORMATION ABOUT ME BLOG
  15. <template> <div> <header-menu></header-menu> <div class="contents"> <side-menu></side-menu> <main class="main" role="main"> <global-message

    /> <slot name="main-content"></slot> </main> </div> <footer-menu></footer-menu> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; ... @Component({ components: { GlobalMessage, FooterMenu, NotifyMessage, SideMenu, HeaderMenu }, }) export default class NormalTemplate extends Vue {} </script>
  16. <template> <div> <header-menu></header-menu> <div class="contents"> <side-menu></side-menu> <main class="main" role="main"> <global-message

    /> <slot name="main-content"></slot> </main> </div> <footer-menu></footer-menu> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; ... @Component({ components: { GlobalMessage, FooterMenu, NotifyMessage, SideMenu, HeaderMenu }, }) export default class NormalTemplate extends Vue {} </script>
  17. <template> <normal-template> <router-view slot="main-content"></router-view> </normal-template> </template> <script lang="ts"> import {

    Component, Vue } from 'vue-property-decorator'; import NormalTemplate from 'front/atomic/Templates/Layer/NormalTemplate.vue'; @Component({ components: { NormalTemplate }, }) export default class TopRootPage extends Vue {} </script>
  18. <template> <contents-with-breadcrumb> <template slot="breadcrumbs"> <crumb :to="{name: 'top'}">{{$t("breadcrumb-home")}}</crumb> <crumb isActive="true">{{$t("title")}}</crumb> </template>

    <indexed-list v-loading="isLoading"> <indexed-list-row heading="Name"> <indexed-list-label>Masanobu Naruse</indexed-list-label> </indexed-list-row> <indexed-list-row heading="Job"> <indexed-list-label>Programmer / Developer Evangelist</indexed-list-label> </indexed-list-row> <indexed-list-row heading="Company"> <indexed-list-label>GMO Internet, Inc.</indexed-list-label> </indexed-list-row> <indexed-list-row heading="Team"> <indexed-list-label>UX UI / DevRel.</indexed-list-label> </indexed-list-row> <indexed-list-row heading="Twitter"> <normal-link href="https://twitter.com/nrslib">@nrslib</normal-link> </indexed-list-row> <indexed-list-row heading="HP"> <normal-link href="https://nrslib.com">https://nrslib.com</normal-link> </indexed-list-row> </indexed-list> </contents-with-breadcrumb> </template>
  19. <template> <contents-with-breadcrumb> <template slot="breadcrumbs"> <crumb :to="{name: 'top'}">{{$t("breadcrumb-home")}}</crumb> <crumb isActive="true">{{$t("title")}}</crumb> </template>

    <indexed-list v-loading="isLoading"> <indexed-list-row heading="Name"> <indexed-list-label>Masanobu Naruse</indexed-list-label> </indexed-list-row> <indexed-list-row heading="Job"> <indexed-list-label>Programmer / Developer Evangelist</indexed-list-label> </indexed-list-row> <indexed-list-row heading="Company"> <indexed-list-label>GMO Internet, Inc.</indexed-list-label> </indexed-list-row> <indexed-list-row heading="Team"> <indexed-list-label>UX UI / DevRel.</indexed-list-label> </indexed-list-row> <indexed-list-row heading="Twitter"> <normal-link href="https://twitter.com/nrslib">@nrslib</normal-link> </indexed-list-row> <indexed-list-row heading="HP"> <normal-link href="https://nrslib.com">https://nrslib.com</normal-link> </indexed-list-row> </indexed-list> </contents-with-breadcrumb> </template>
  20. <template> <a v-if="href" :href='href' target="_blank" rel="noopener noreferrer" > <slot></slot> </a>

    <router-link v-else :to="to"> <slot></slot> </router-link> </template> <script lang="ts"> import { Vue, Component, Prop } from 'vue-property-decorator'; @Component({ name: 'NormalLink' }) export default class NormalLink extends Vue { @Prop() public to: any; @Prop() public href: string; } </script>
  21. atomic Atoms Molecules Organisms Templates Link Button NormalLink PrimaryButton SecondaryButton

    LinkButton AddButton Table TableColumn TableColumnHeader Table TableRow Table TableComponent TableSearchTable TableHeader Contents Layer : : : NormalTemplate NoAuthorityTemplate Contents ContentsWithBreadcrumb 構成サンプル
  22. pages Top TopRootPage TopIndexPage Index Info Index Detail InfoRootPage InfoIndexPage

    InfoDetailPage TopRoute InfoRoute InfoData 構成サンプル (ページ) :
  23. 案ずることはない すべては Atom だ <h1> タグとか どうします? <template> <h1> <slot></slot>

    </h1> </template> <script lang="ts"> import { Component, Prop, Vue } from 'vue-property-decorator'; @Component export default class Heading1 extends Vue { } </script>
  24. どれが Atom で どれが Molecules で どこからが Organism? Atom を利用したら

    Molecules Molecules を利用してたら Organism 意味ある塊なら Organism
  25. Parent Component Child Component { ‘data’ : ‘b’} { ‘data’

    : ‘b’} Notify コンポーネント作りの 経験がないとやりがち
  26. { ‘data’ : ‘b’} Parent Component Child Component Change Child

    Component Notify event Notify event 親子が増えても一緒
  27. <template> <normal-template> <template slot="main-content"> <h2 style="color: green">Play Ground</h2> <link-button :to="{name:

    'module-playground-dropdown'}">Dropdown</link-button> <link-button :to="{name: 'module-playground-table'}">Table</link-button> <link-button :to="{name: 'module-playground-modal'}">Modal</link-button> <link-button :to="{name: 'module-playground-tab'}">Tab</link-button> <link-button :to="{name: 'modulePlaygroundPassword'}">Password</link-button> <link-button :to="{name: 'modulePlaygroundButton'}">Button</link-button> <link-button :to="{name: 'modulePlaygroundText'}">Text</link-button> <link-button :to="{name: 'modulePlaygroundFormElement'}">FormElement & Validator</link-button> <link-button :to="{name: 'modulePlaygroundDatepicker'}">datepicker</link-button> <link-button :to="{name: 'modulePlaygroundLoading'}">L@@ding</link-button> <link-button :to="{name: 'modulePlaygroundProgressTracker'}">ProgressTracker</link-button> <link-button :to="{name: 'modulePlayGroundProgress'}">Progress</link-button> <link-button :to="{name: 'modulePlayGroundCheckbox'}">Checkbox</link-button> <link-button :to="{name: 'modulePlayGroundPanel'}">Panel</link-button> <link-button :to="{name: 'modulePlaygroundVariableInput'}">VariableInput</link-button> <link-button :to="{name: 'modulePlaygroundRadioGroupButton'}">RadioGroup</link-button> <link-button :to="{name: 'modulePlayGroundClipboard'}">Clipboard</link-button> <link-button :to="{name: 'modulePlaygroundInnerWizard'}">InnerWizard</link-button> <link-button :to="{name: 'modulePlayGroundTooltip'}">Tooltip</link-button> <link-button :to="{name: 'modulePlayGroundConfigurationTipsPage'}">ConfigurationTips</link-button> <link-button :to="{name: 'modulePlayGroundPager'}">Pager</link-button> <link-button :to="{name: 'modulePlayGroundAnchor'}">Anchor</link-button> <link-button :to="{name: 'modulePlayGroundCapacityDisplay'}">Capacity</link-button> <link-button :to="{name: 'modulePlayGroundEmptyPanel'}">EmptyPanel</link-button> <link-button :to="{name: 'modulePlayGroundCarouselPage'}">Carousel</link-button> <link-button :to="{name: 'modulePlayGroundGraphPage'}">Graph</link-button> <router-view></router-view> </template> </normal-template> </template> <script lang="ts"> import { Component } from 'vue-property-decorator'; import { BasePage } from '@lib/vue/BasePage'; import NormalTemplate from 'front/atomic/Templates/Layer/NormalTemplate.vue'; import LinkButton from 'front/atomic/Atoms/Button/LinkButton.vue'; @Component({ components: { LinkButton, NormalTemplate }, }) export default class ModulePlayGroundRootPage extends Vue {} </script>
  28. <template> <normal-template> <template slot="main-content"> <h2 style="color: green">Play Ground</h2> <link-button :to="{name:

    'module-playground-dropdown'}">Dropdown</link-button> <link-button :to="{name: 'module-playground-table'}">Table</link-button> <link-button :to="{name: 'module-playground-modal'}">Modal</link-button> <link-button :to="{name: 'module-playground-tab'}">Tab</link-button> <link-button :to="{name: 'modulePlaygroundPassword'}">Password</link-button> <link-button :to="{name: 'modulePlaygroundButton'}">Button</link-button> <link-button :to="{name: 'modulePlaygroundText'}">Text</link-button> <link-button :to="{name: 'modulePlaygroundFormElement'}">FormElement & Validator</link-button> <link-button :to="{name: 'modulePlaygroundDatepicker'}">datepicker</link-button> <link-button :to="{name: 'modulePlaygroundLoading'}">L@@ding</link-button> <link-button :to="{name: 'modulePlaygroundProgressTracker'}">ProgressTracker</link-button> <link-button :to="{name: 'modulePlayGroundProgress'}">Progress</link-button> <link-button :to="{name: 'modulePlayGroundCheckbox'}">Checkbox</link-button> <link-button :to="{name: 'modulePlayGroundPanel'}">Panel</link-button> <link-button :to="{name: 'modulePlaygroundVariableInput'}">VariableInput</link-button> <link-button :to="{name: 'modulePlaygroundRadioGroupButton'}">RadioGroup</link-button> <link-button :to="{name: 'modulePlayGroundClipboard'}">Clipboard</link-button> <link-button :to="{name: 'modulePlaygroundInnerWizard'}">InnerWizard</link-button> <link-button :to="{name: 'modulePlayGroundTooltip'}">Tooltip</link-button> <link-button :to="{name: 'modulePlayGroundConfigurationTipsPage'}">ConfigurationTips</link-button> <link-button :to="{name: 'modulePlayGroundPager'}">Pager</link-button> <link-button :to="{name: 'modulePlayGroundAnchor'}">Anchor</link-button> <link-button :to="{name: 'modulePlayGroundCapacityDisplay'}">Capacity</link-button> <link-button :to="{name: 'modulePlayGroundEmptyPanel'}">EmptyPanel</link-button> <link-button :to="{name: 'modulePlayGroundCarouselPage'}">Carousel</link-button> <link-button :to="{name: 'modulePlayGroundGraphPage'}">Graph</link-button> <router-view></router-view> </template> </normal-template> </template> <script lang="ts"> import { Component } from 'vue-property-decorator'; import { BasePage } from '@lib/vue/BasePage'; import NormalTemplate from 'front/atomic/Templates/Layer/NormalTemplate.vue'; import LinkButton from 'front/atomic/Atoms/Button/LinkButton.vue'; @Component({ components: { LinkButton, NormalTemplate }, }) export default class ModulePlayGroundRootPage extends Vue {} </script> 実践的なコンポーネントを 作ってもらって経験してもらう
  29. <template> <div> <secondary-button @clicked="buttonClicked">Add row</secondary-button> <secondary-button @clicked="onClearButtonClicked">Clear</secondary-button> <secondary-button @clicked="changeLoadingButtonClicked">SwitchLoading</secondary-button> <normal-heading>ページング</normal-heading>

    <module-play-ground-table-paging-table :data="data" :isLoading="isLoading" :orderServerId <normal-heading>件数指定</normal-heading> <module-play-ground-table-dropdown-paging-table :data="data" :isLoading="isLoading" :orde <normal-heading>検索</normal-heading> <module-play-ground-table-search-table :data="data" :isLoading="isLoading" :orderServerId <normal-heading>通常テーブル(全データ)</normal-heading> <module-play-ground-table-normal-table :data="data" :isLoading="isLoading" :orderServerId </div> </template> PlayGround があれば コンポーネントの使い方もわかる
  30. No