この記事は、 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 に modules
と vuetify
を追加する。
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 が読み込めない。
(ただ読み込めた時もあって少し混乱。。)
(追記)
上記の回避方法が微妙だなと、対策を考えていたら、また微妙な方法を思いついた。
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">
©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
下記サイトを参考にさせていただいた。
###[メモ]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 Icons 、 Font 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 が出る。
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&hashtags=bulmaio&url=http://localhost:4000&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>© 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">“{{ val.title }}”</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>
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>
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
下記サイトを参考にさせていただいた。
- Nuxt.jsにBulmaを組み込んだら、Vuexストアが理解できた件
- Sticky Footer — Solved by Flexbox — Cleaner, hack-free CSS
- How to style a form using Bulma / Welcome to Signl
- Learn a CSS Framework in 6 Minutes with Bulma — SitePoint
下記は Bulma 関連の気になったサイトやページ。
-
Bulmaswatch
- Free themes for Bulma
-
Expo
- How people use Bulma to design beautiful websites
-
Bulma Customizer
- Create your own bespoke Bulma build
-
Free Bulma Templates
- Based on the Bulma CSS Framework
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
とりあえず、今後対応で。。
下記サイトを参考にさせていただいた。
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
雑感
- Vuetify は、アプリ感出すのに良いね。コンポーネントも多く用意されている。
- Bulma は、いじってておもしろい。
- Element UI は、Desktop と謳っているだけあって、コンポーネントはレスポンシブじゃないみたい。
他にも、気になる CSS Framework がいくつかあるので、また試す。