この記事は、 nuxt-community/express-template で新規作成したプロジェクトをベースに書いている。
この環境については、前回の記事で触れている。

今回、組み込んで見るのは

Vuetify 編

これ
https://www.npmjs.com/package/@nuxtjs/vuetify

まずは、インストール。

npm install --save @nuxtjs/vuetify
npm install --save @nuxtjs/font-awesome

1)nuxt.config.js に modulesvuetify を追加する。

  modules: [
    '@nuxtjs/vuetify',
    '@nuxtjs/font-awesome'
  ]

modules については ココ を参照。

  vuetify: {
    theme: {
      primary: '#3f51b5',
      secondary: '#b0bec5',
      accent: '#8c9eff',
      error: '#b71c1c'
    }
  }

theme の中身については ココ を参照。

2)node_modules/@nuxtjs/vuetify/index.js を少し変更する。

変更前

href: '//fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons'

変更後(https: を追加する。)

href: 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons'

これやらないと、 http://localhost:3000 での実行時に、Material Icons が読み込めない。
(ただ読み込めた時もあって少し混乱。。)

image.png

image.png

(追記)

上記の回避方法が微妙だなと、対策を考えていたら、また微妙な方法を思いついた。
1)で追加した nuxt.config.js の vuetify の中(theme と同じ階層)に下記を追加して、 Material Icons の読み込みを無効化する。
(node_modules/@nuxtjs/vuetify/index.js の修正は不要。)

    materialIcons: false

で、今度は、Material Icons を読み込む記述を追加する。
nuxt.config.js の head.link の配列に下記を追加する。

      {
        rel: 'stylesheet',
        type: 'text/css',
        href: 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons'
      }

インストールしたパッケージをいじるよりいいのかな。。

※ただこの問題、自分の環境でのみ発生するような気もしている。※

3)layouts/default.vue を、下記で上書きする。

https://codepen.io/johnjleider/pen/KQrPKJ を元にした。

<template>
  <div id="app">
    <v-app id="inspire">
      <v-navigation-drawer fixed v-model="drawerRight" right clipped app>
        <v-toolbar flat>
          <v-list>
            <v-list-tile>
              <v-list-tile avatar>
                <v-list-tile-avatar>
                  <v-icon medium>account_circle</v-icon>
                </v-list-tile-avatar>
                <v-list-tile-content>
                  <v-list-tile-title class="title">
                    User
                  </v-list-tile-title>
                </v-list-tile-content>
              </v-list-tile>
            </v-list-tile>
          </v-list>
        </v-toolbar>
        <v-list dense>
          <v-list-tile @click.stop="right = !right">
            <v-list-tile-action>
              <v-icon>exit_to_app</v-icon>
            </v-list-tile-action>
            <v-list-tile-content>
              <v-list-tile-title>Open Temporary Drawer</v-list-tile-title>
            </v-list-tile-content>
          </v-list-tile>
        </v-list>
        <v-list dense class="pt-0">
        <v-list-tile v-for="item in items" :key="item.title" :to="item.url">
          <v-list-tile-action>
            <v-icon>{{ item.icon }}</v-icon>
          </v-list-tile-action>
          <v-list-tile-content>
            <v-list-tile-title>{{ item.title }}</v-list-tile-title>
          </v-list-tile-content>
        </v-list-tile>
      </v-list>
      </v-navigation-drawer>
      <v-toolbar color="blue-grey darken-2" dark fixed app clipped-right>
        <v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
        <v-toolbar-title>Toolbar</v-toolbar-title>
        <v-spacer></v-spacer>
        <v-toolbar-items class="hidden-sm-and-down">
          <v-btn flat v-for="item in items" :key="item.title" :to="item.url">
            {{ item.title }}
          </v-btn>
        </v-toolbar-items>
        <v-toolbar-side-icon @click.stop="drawerRight = !drawerRight"></v-toolbar-side-icon>
      </v-toolbar>
      <v-navigation-drawer fixed v-model="drawer" app>
        <v-toolbar flat>
          <v-list>
            <v-list-tile>
              <v-list-tile avatar>
                <v-list-tile-avatar>
                  <v-icon medium>account_circle</v-icon>
                </v-list-tile-avatar>
                <v-list-tile-content>
                  <v-list-tile-title class="title">
                    User
                  </v-list-tile-title>
                </v-list-tile-content>
              </v-list-tile>
            </v-list-tile>
          </v-list>
        </v-toolbar>
        <v-list dense>
          <v-list-tile @click.stop="left = !left">
            <v-list-tile-action>
              <v-icon>exit_to_app</v-icon>
            </v-list-tile-action>
            <v-list-tile-content>
              <v-list-tile-title>Open Temporary Drawer</v-list-tile-title>
            </v-list-tile-content>
          </v-list-tile>
        </v-list>
        <v-list dense class="pt-0">
        <v-list-tile v-for="item in items" :key="item.title" :to="item.url">
          <v-list-tile-action>
            <v-icon>{{ item.icon }}</v-icon>
          </v-list-tile-action>
          <v-list-tile-content>
            <v-list-tile-title>{{ item.title }}</v-list-tile-title>
          </v-list-tile-content>
        </v-list-tile>
      </v-list>
      </v-navigation-drawer>
      <v-navigation-drawer temporary v-model="left" fixed>
        Left
      </v-navigation-drawer>
      <v-content>
        <v-container fluid fill-height>
          <v-layout justify-center align-center>
            <v-flex text-xs-center>
            <div>
              <nuxt/>
            </div>
          </v-flex>
          </v-layout>
        </v-container>
      </v-content>
      <v-navigation-drawer right temporary v-model="right" fixed>
        Right
      </v-navigation-drawer>
      <v-footer color="blue-grey darken-2" app class="white--text">
      &copy;2018 — <strong>Vuetify</strong>
      <v-spacer></v-spacer>
      <v-btn v-for="icon in icons" :key="icon" icon class="white--text">
        <v-icon small>{{ icon }}</v-icon>
      </v-btn>
    </v-footer>
    </v-app>
  </div>
</template>

<script>
import MyFooter from '~/components/Footer.vue'
import feature from '~/pages/feature.vue'
import contact from '~/pages/contact.vue'

export default {
  components: {
    MyFooter,
    feature,
    contact
  },
  data: () => ({
    drawer: null,
    items: [
      { title: 'Home', icon: 'home', url: '/' },
      { title: 'Feature', icon: 'code', url: '/feature' },
      { title: 'Contact', icon: 'question_answer', url: '/contact' }
    ],
    icons: ['fa-facebook', 'fa-twitter', 'fa-google-plus', 'fa-linkedin', 'fa-instagram'],
    // drawer: true,
    drawerRight: true,
    right: null,
    left: null
  }),
  props: {
    source: String
  }
}
</script>

4)pages/feature.vue を作成する。

<template>
  <div>
    Feature
  </div>
</template>

5)pages/contact.vue を作成する。

<template>
  <div>
    Contact
  </div>
</template>

6)pages/_id.vue の h1 と h2 タグのクラス( class="title" 、 class="info" )を削除する。

(必須ではない。)

7)起動

npm run dev

image.png

下記サイトを参考にさせていただいた。

[メモ]Font Awesome の他の導入方法

npm install --save font-awesome

nuxt.config.js へ下記を追加する。

  css: [
    'font-awesome/css/font-awesome.min.css'
  ],

使用方法は、下記のどちらでもいける。ただし、スタイルは異なる。

<i class="fa fa-camera"></i>
<v-icon>fa-camera</v-icon>

Vuetify は、 デフォルトで Material Icons に対応している。
導入は必要だが、 Material Design IconsFont Awesome をサポートしている。
Material Icons は接頭辞無し、Material Design Icons は接頭辞が mdi- 、Font Awesome は接頭辞が fa- とのこと。
https://vuetifyjs.com/en/components/icons

Bulma @nuxtjs

これ
https://github.com/nuxt-community/modules/tree/master/packages/bulma

npm install --save @nuxtjs/bulma @nuxtjs/font-awesome

1)nuxt.config.js の module.exports 内に modules を追加する。

  modules: [
    '@nuxtjs/bulma',
    '@nuxtjs/font-awesome'
  ]

2)nuxt.config.js の module.exports の build 内に postcss を追加する。

[参考] https://github.com/nuxt/nuxt.js/issues/1670

    postcss: {
      plugins: {
        'postcss-custom-properties': {
          warnings: false
        }
      }
    }

これがないと Warning が出る。

image.png

3)components/NavBar.vue を作成する。

<template>
  <nav class="navbar has-background-light">
    <div class="navbar-brand">
      <nuxt-link class="navbar-item" to="/">
        <img src="https://bulma.io/images/bulma-logo.png" alt="Bulma" width="112" height="28">
      </nuxt-link>
      <div class="navbar-burger burger burger-font-icon" @click="showNav = !showNav" :class="{'is-active': showNav}">
        <img src="@/assets/ic_menu_black_24px.svg" />
      </div>
    </div>
    <div id="navbarExampleTransparentExample" class="navbar-menu" :class="{'is-active':showNav}">
      <div class="navbar-start">
        <nuxt-link class="navbar-item" to="/">
          Home
        </nuxt-link>
        <div class="navbar-item has-dropdown is-hoverable">
          <a class="navbar-link" href="/documentation/overview/start/">
            Docs
          </a>
          <div class="navbar-dropdown is-boxed">
            <nuxt-link v-for="item in items" :key="item.title" :to="item.url" class="navbar-item">
              {{ item.title }}
            </nuxt-link>
            <hr class="navbar-divider">
            <a class="navbar-item" href="https://bulma.io/documentation/elements/box/">
              Elements
            </a>
            <a class="navbar-item is-active" href="https://bulma.io/documentation/components/breadcrumb/">
              Components
            </a>
          </div>
        </div>
      </div>
      <div class="navbar-end">
        <div class="navbar-item">
          <div class="field is-grouped">
            <p class="control">
              <a class="bd-tw-button button" data-social-network="Twitter" data-social-action="tweet" data-social-target="http://localhost:4000" target="_blank" href="https://twitter.com/intent/tweet?text=Bulma: a modern CSS framework based on Flexbox&amp;hashtags=bulmaio&amp;url=http://localhost:4000&amp;via=jgthms">
                <span class="icon">
                  <i class="fa fa-twitter"></i>
                </span>
                <span>
                  Tweet
                </span>
              </a>
            </p>
            <p class="control">
              <a class="button is-primary" href="https://github.com/jgthms/bulma/releases/download/0.7.0/bulma-0.7.0.zip">
                <span class="icon">
                  <i class="fa fa-download"></i>
                </span>
                <span>Download</span>
              </a>
            </p>
          </div>
        </div>
      </div>
    </div>
  </nav>
</template>

<script>
import feature from '~/pages/feature.vue'
import contact from '~/pages/contact.vue'

export default {
  components: {
    feature,
    contact
  },
  data: () => ({
    showNav: false,
    items: [
      { title: 'Home', icon: 'home', url: '/' },
      { title: 'Feature', icon: 'code', url: '/feature' },
      { title: 'Contact', icon: 'question_answer', url: '/contact' }
    ]
  })
}
</script>

<style>
.navbar {
  margin-bottom: 20px;
}
.burger-font-icon img {
  height: 30px;
  margin: 10px 0 0 12px;
}
</style>

4)assets/ic_menu_black_24px.svg を作成する。

Material Icons のメニューアイコン を SVG でダウンロードし、 assets に保存する。

5)components/FooterBar.vue を作成する。(ファイル名に違和感あってもスルー)

<template>
  <footer class="footer has-background-primary has-text-white">
    <div class="container">
    <div class="content has-text-centered is-info">
      <p>&copy; 2018 HOGE inc.</p>
    </div>
    </div>
  </footer>
</template>

<style scoped>
footer.footer {
  padding: 0.5em;
}
</style>

6)components/QuoteCard.vue を作成する。

<template>
  <div class="card">
    <div class="card-content">
      <h2 class="title">&ldquo;{{ val.title }}&rdquo;</h2> 
      <h3 class="subtitle">{{ val.subtitle }}</h3>
    </div>
    <div class="card-footer">
      <span class="card-footer-item">
        <a href="#" class="button is-primary">
          <i class="fa fa-thumbs-o-up"></i>
        </a>
      </span>
      <span class="card-footer-item">
        <a href="#" class="button is-danger">
          <i class="fa fa-thumbs-o-down"></i>
        </a>
      </span>
      <span class="card-footer-item">
        <a href="#" class="button is-info">
          <i class="fa fa-retweet"></i>
        </a>
      </span>
    </div>
  </div>
</template>

<script>
export default {
  props: ['val']
}
</script>

<style scoped>
.card {
  margin-bottom: 8px;
}
</style>

こんなコンポーネント。
image.png

7)components/SignIn.vue を作成する。

<template>
  <div class="card">
    <div class="card-content login">
      <p class="title">
        Already a member?
      </p>
      <p class="subtitle">
        Sign in to continue.
      </p>
      <div class="field">
        <label class="label">Email</label>
        <div class="control">
          <input class="input" type="text" placeholder="Email address">
        </div>
      </div>
      <div class="field">
        <label class="label">Password</label>
        <div class="control">
          <input class="input" type="email" placeholder="My password">
        </div>
      </div>
      <div class="subtitle is-6 has-text-centered">or</div>
      <div class="field is-grouped is-grouped-centered">
        <p class="control">
          <button class="button is-link">Facebook</button>
        </p>
        <p class="control">
          <button class="button is-info">Twitter</button>
        </p>
      </div>
    </div>
    <div class="card-footer has-text-primary has-background-white-bis">
      <p class="card-footer-item register">
        <span>
          Register
        </span>
      </p>
    </div>
  </div>
</template>

こんなコンポーネント。
image.png

8)layouts/default.vue を書きで上書きする。

<template>
  <div class="site">
    <nav-bar/>
    <div class="siteContent">
      <nuxt class="has-text-centered"/>
    </div>
    <footer-bar/>
  </div>
</template>

<script>
import FooterBar from '~/components/FooterBar.vue'
import NavBar from '~/components/NavBar.vue'

export default {
  components: {
    FooterBar,
    NavBar
  }
}
</script>

<style>
.site {
  display: flex;
  min-height: 100vh;
  flex-direction: column;
}
.siteContent {
  flex: 1;
}
</style>

9)pages/feature.vue を作成する。

<template>
  <div>
    <section class="section"> 
      <div class="container"> 
        <div class="columns is-centered ">
          <div class="column is-one-third ">
            <quote-card v-for="item in items" :key="item.title" :val="item"></quote-card>
          </div>
          <div class="column is-one-third">
            <quote-card v-for="item in items2" :key="item.title" :val="item"></quote-card>
          </div>
          <div class="column is-one-third">
            <quote-card v-for="item in items3" :key="item.title" :val="item"></quote-card>
          </div>
        </div>
      </div>
    </section>
  </div>
</template>

<script>
import QuoteCard from '~/components/QuoteCard.vue'

export default {
  components: {
    QuoteCard
  },
  data: () => ({
    items: [
      { title: 'Quote 1', subtitle: 'Programmer-01' },
      { title: 'Quote 2', subtitle: 'Programmer-02' },
      { title: 'Quote 3', subtitle: 'Programmer-03' }
    ],
    items2: [
      { title: 'Order 1', subtitle: 'Programmer-01' }
    ],
    items3: [
      { title: 'Deliver 1', subtitle: 'Programmer-01' },
      { title: 'Deliver 2', subtitle: 'Programmer-02' }
    ]
  })
}
</script>

10)pages/contact.vue を作成する。

<template>
  <div class="columns is-centered">
    <div class="column is-one-third is-mobile">
      <sign-in/>
    </div>
  </div>
</template>

<script>
import SignIn from '~/components/SignIn.vue'

export default {
  components: {
    SignIn
  }
}
</script>

11)起動

npm run dev

image.png

ウィンドウの幅が減ると。
image.png
image.png

各ページは。
image.png
image.png

下記サイトを参考にさせていただいた。

下記は Bulma 関連の気になったサイトやページ。

Bulma おもしろそうだな。

Bulma SCSS編

npm install --save bulma font-awesome
npm install --save-dev sass-loader node-sass

1)nuxt.config.js に下記部分に追加

変更前

  css: ['~/assets/css/main.css'],

変更後

  css: [
    { src: '~/assets/main.scss', lang: 'scss' },
    { src: 'font-awesome/scss/font-awesome.scss', lang: 'scss' }
  ],

2)nuxt.config.js の build 内に追加

    postcss: {
      plugins: {
        'postcss-custom-properties': {
          warnings: false
        }
      }
    }

3)assets/main.scss を作成する。

// 1. Import the initial variables
@import "~bulma/sass/utilities/initial-variables";
@import "~bulma/sass/utilities/functions";

// 2. Set your own initial variables
// Update blue
$blue: #72d0eb;
// Add pink and its invert
$pink: #ffb3b3;
$pink-invert: #fff;
// Add a serif family
$family-serif: "Merriweather", "Georgia", serif;

// 3. Set the derived variables
// Use the new pink as the primary color
$primary: $pink;
$primary-invert: $pink-invert;
// Use the existing orange as the danger color
$danger: $orange;
// Use the new serif family
$family-primary: $family-serif;

// 4. Setup your Custom Colors
$linkedin: #0077b5;
$linkedin-invert: findColorInvert($linkedin);
$twitter: #55acee;
$twitter-invert: findColorInvert($twitter);
$github: #333;
$github-invert: findColorInvert($github);

// 5. Add new color variables to the color map.
@import "~bulma/sass/utilities/derived-variables";
$addColors: (
  "twitter":($twitter, $twitter-invert),
  "linkedin": ($linkedin, $linkedin-invert),
  "github": ($github, $github-invert)
);
$colors: map-merge($colors, $addColors);

// 6. Import the rest of Bulma
@import "~bulma";

4)前章と同じ様に追加、編集を行う。

割愛。

5)起動

npm run dev

image.png

むむむ。
image.png

とりあえず、今後対応で。。

下記サイトを参考にさせていただいた。

Element UI 編

これ
https://element.eleme.io/#/en-US/component/quickstart#use-nuxt-js

基本的には、公式ガイドの通り。
https://element.eleme.io/#/en-US/component/quickstart#use-nuxt-js

npm install --save element-ui

1)plugins/element-ui.js を作成する。

import Vue from 'vue'
import Element from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'

export default () => {
  Vue.use(Element, { locale })
}

2)nuxt.config.js の module.exports の css を下記に書き換える。

  css: ['element-ui/lib/theme-chalk/index.css'],

3)nuxt.config.js の module.exports に下記を追加する。

  plugins: [
    '@/plugins/element-ui'
  ]

4)components/NavBar.vue を作成する。

<template>
  <div>
    <el-menu
      :default-active="activeIndex2"
      class="el-menu-demo"
      mode="horizontal"
      @select="handleSelect"
      background-color="#545c64"
      text-color="#fff"
      active-text-color="#ffd04b">
      <el-menu-item index="1">Processing Center</el-menu-item>
      <el-submenu index="2">
        <template slot="title">Workspace</template>
        <el-menu-item index="2-1">item one</el-menu-item>
        <el-menu-item index="2-2">item two</el-menu-item>
        <el-menu-item index="2-3">item three</el-menu-item>
        <el-submenu index="2-4">
          <template slot="title">item four</template>
          <el-menu-item index="2-4-1">item one</el-menu-item>
          <el-menu-item index="2-4-2">item two</el-menu-item>
          <el-menu-item index="2-4-3">item three</el-menu-item>
        </el-submenu>
      </el-submenu>
      <el-menu-item index="3" disabled>Info</el-menu-item>
      <el-menu-item index="4"><a href="https://www.ele.me" target="_blank">Orders</a></el-menu-item>
    </el-menu>
  </div>
</template>

<style>
</style>

<script>
export default {
  data () {
    return {
      activeIndex: '1',
      activeIndex2: '1'
    }
  },
  methods: {
    handleSelect (key, keyPath) {
      console.log(key, keyPath)
    }
  }
}
</script>

5)components/SideBar.vue を作成する。

<template>
  <el-menu :default-openeds="['1', '3']">
    <el-submenu index="1">
      <template slot="title"><i class="el-icon-message"></i>Navigator One</template>
      <el-menu-item-group>
        <template slot="title">Group 1</template>
        <el-menu-item index="1-1">Option 1</el-menu-item>
        <el-menu-item index="1-2">Option 2</el-menu-item>
      </el-menu-item-group>
      <el-menu-item-group title="Group 2">
        <el-menu-item index="1-3">Option 3</el-menu-item>
      </el-menu-item-group>
      <el-submenu index="1-4">
        <template slot="title">Option4</template>
        <el-menu-item index="1-4-1">Option 4-1</el-menu-item>
      </el-submenu>
    </el-submenu>
    <el-submenu index="2">
      <template slot="title"><i class="el-icon-menu"></i>Navigator Two</template>
      <el-menu-item-group>
        <template slot="title">Group 1</template>
        <el-menu-item index="2-1">Option 1</el-menu-item>
        <el-menu-item index="2-2">Option 2</el-menu-item>
      </el-menu-item-group>
      <el-menu-item-group title="Group 2">
        <el-menu-item index="2-3">Option 3</el-menu-item>
      </el-menu-item-group>
      <el-submenu index="2-4">
        <template slot="title">Option 4</template>
        <el-menu-item index="2-4-1">Option 4-1</el-menu-item>
      </el-submenu>
    </el-submenu>
    <el-submenu index="3">
      <template slot="title"><i class="el-icon-setting"></i>Navigator Three</template>
      <el-menu-item-group>
        <template slot="title">Group 1</template>
        <el-menu-item index="3-1">Option 1</el-menu-item>
        <el-menu-item index="3-2">Option 2</el-menu-item>
      </el-menu-item-group>
      <el-menu-item-group title="Group 2">
        <el-menu-item index="3-3">Option 3</el-menu-item>
      </el-menu-item-group>
      <el-submenu index="3-4">
        <template slot="title">Option 4</template>
        <el-menu-item index="3-4-1">Option 4-1</el-menu-item>
      </el-submenu>
    </el-submenu>
  </el-menu>
</template>

<style scoped>
.el-menu {
  border: none;
}
</style>

6)layouts/devault.vue を上書きする。

<template>  
  <div>
    <el-header>
      <nav-bar />
    </el-header>
    <el-container>
      <el-aside width="auto">
        <side-bar />
      </el-aside>
      <el-main>
        <nuxt class="centered-text"/>
      </el-main>      
    </el-container>
    <el-footer>
      <my-footer/>
    </el-footer>
  </div>
</template>

<script>
import MyFooter from '~/components/Footer.vue'
import NavBar from '~/components/NavBar.vue'
import SideBar from '~/components/SideBar.vue'

export default {
  components: {
    MyFooter,
    NavBar,
    SideBar
  }
}
</script>

<style>
html, body {
  padding: 0;
  margin: 0;
  height: 100%;
  width: 100%;
}
.el-header {
  background-color: #545c64;
  line-height: 60px;
}
.el-aside {
  border-right: 1px solid #E4E7ED;
}
.el-footer {
  border-top: 1px solid #E4E7ED;
}
.centered-text {
  text-align: center;
}
</style>

7)起動

npm run dev

image.png

雑感

  • Vuetify は、アプリ感出すのに良いね。コンポーネントも多く用意されている。
  • Bulma は、いじってておもしろい。
  • Element UI は、Desktop と謳っているだけあって、コンポーネントはレスポンシブじゃないみたい。

他にも、気になる CSS Framework がいくつかあるので、また試す。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.