5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

VueAdvent Calendar 2022

Day 7

Vue3 + MDBootstrap / Bootstrap5 のプロジェクトの作成

Last updated at Posted at 2022-09-05

基本、上に書いてある通りです。ただし、vue のプロジェクト作成方法が少し変わったりして、そのままでは動かなかったので、罠回避のためにメモしておきます。

MDB でない、バニラ(?)Bootstrap5 については末尾に記載。

いろいろバージョン

$ npm -v
9.0.3
$ node -v
v16.16.0
$ yarn -v
1.22.19

プロジェクト作成

以下のサンプルでは project の名前は sample-bootstrap-project としています。

$ yarn create vue
success Installed "create-vue@3.4.1" with binaries:
      - create-vue

Vue.js - The Progressive JavaScript Framework

✔ Project name: … your-project-name
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit Testing? … No / Yes
✔ Add an End-to-End Testing Solution? › No
✔ Add ESLint for code quality? … No / Yes

Done. Now run:

  cd your-project-name
  npm install
  npm run dev

$ cd your-project-name
$ yarn add mdb-vue-ui-kit
$ yarn

この段階では MDBootstrap はまだ使えませんが、yarn dev としてページが表示できることを確認しておきます。

$ yarn dev

http://localhost:5173/ をブラウザで開くと、下記のようなページが表示されるはずです。

image.png

コードの変更

main.js

src/main.js を下記のように書き換えます。

src/main.js
import { createApp } from 'vue'
// import './style.css' // これをコメントアウトする!!
import App from './App.vue'
import 'mdb-vue-ui-kit/css/mdb.min.css'; // 追加

createApp(App).mount('#app')

stype.css をコメントアウトしないと、画面がダークかつ中央寄りになります。

index.html

下記の二行を <head> 以下に追加します。

index.html
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet" />
    <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900&display=swap" rel="stylesheet" />

App.vue

style にフォントを追加します。

src/App.vue
<style>
#app {
  font-family: Roboto, Helvetica, Arial, sans-serif;
}
</style>

これで、あとはコンポーネントを個別に import すればOKです。

具体的な例

src/App.vue
<template>
  <header>
    <MDBNavbar expand="lg" dark bg="dark" container>
      <MDBNavbarBrand href="#">Brand</MDBNavbarBrand>
      
      <MDBNavbarToggler
        @click="collapse1 = !collapse1"
        target="#navbarSupportedContent"
      ></MDBNavbarToggler>
    </MDBNavbar>
  </header>
  <main class="flex-shrink-0 pt-5">
    <div class="container">
      <h1>{{ msg }}</h1>

      <p>
        <a href="https://vitejs.dev/guide/features.html" target="_blank">
          Vite Documentation
        </a>
        |
        <a href="https://v3.vuejs.org/" target="_blank">Vue 3 Documentation</a>
      </p>

      <MDBBtn color="primary" class="mb-3" @click="state.count++">
        count is: {{ state.count }}
      </MDBBtn>

      <p>
        Edit components/HelloWorld.vue to test hot module replacement.
      </p>
    </div>
  </main>
</template>
<script>
import {
  MDBBtn,
  MDBNavbar,
  MDBNavbarToggler,
  MDBNavbarBrand,
} from 'mdb-vue-ui-kit';

export default {
  // 使用するコンポーネントはすべてここに記述する必要がある。
  components: {
    MDBBtn,
    MDBNavbar,
    MDBNavbarToggler,
    MDBNavbarBrand,
  },
  data: () => (
    {
      msg: "Welcome to MDBootstrap",
      state: {
        count: 0
      },
      collapse1: false
    }
  )
}
</script>
<style scoped>
#app {
  font-family: Roboto, Helvetica, Arial, sans-serif;
}
</style>

テスト

$ yarn dev

これで、http://localhost:5173/ をブラウザで開くと、下記のような画面になるはずです。

image.png

ボタンを押すと、カウントが進みます。

Vuetify のように、モジュールのオートロードがないので、自分で全部 import する必要があります(多分)。

Bootstrap5 + Vue3 + Vite

基本、公式にある通りです。

$ yarn create vue
success Installed "create-vue@3.4.1" with binaries:
      - create-vue

Vue.js - The Progressive JavaScript Framework

✔ Project name: … your-project-name
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit Testing? … No / Yes
✔ Add an End-to-End Testing Solution? › No
✔ Add ESLint for code quality? … No / Yes

Done. Now run:

  cd your-project-name
  npm install
  npm run dev

$ cd your-project-name
$ yarn add bootstrap @popperjs/core bootstrap-icons

bootstrap-icons は必須ではないです(使わないってことはないと思いますが・・・)

main.js

src/main.js
import { createApp } from 'vue'
import App from './App.vue'

//import './assets/main.css'
import 'bootstrap'
import "bootstrap/dist/css/bootstrap.min.css";

const app = createApp(App)

app.mount('#app')

main.css を必ずコメントアウトします。これであとは、普通に Bootstrap が使えます。

App.vue

下記はSticky footer with fixed navbarのコードをほぼそのまま App.vue にコピペしただけです。

src/App.vue
<template>
  <div class="d-flex flex-column h-100">
    <header>
      <nav class="navbar navbar-expand-md navbar-dark bg-dark">
        <div class="container-fluid">
          <a class="navbar-brand" href="#">Navbar</a>
          <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav me-auto mb-2 mb-lg-0">
              <li class="nav-item">
                <a class="nav-link active" aria-current="page" href="#">Home</a>
              </li>
              <li class="nav-item">
                <a class="nav-link" href="#">Link</a>
              </li>
              <li class="nav-item dropdown">
                <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                  Dropdown
                </a>
                <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
                  <li><a class="dropdown-item" href="#">Action</a></li>
                  <li><a class="dropdown-item" href="#">Another action</a></li>
                  <li><hr class="dropdown-divider"></li>
                  <li><a class="dropdown-item" href="#">Something else here</a></li>
                </ul>
              </li>
              <li class="nav-item">
                <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
              </li>
            </ul>
            <form class="d-flex">
              <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
              <button class="btn btn-outline-success" type="submit">Search</button>
            </form>
          </div>
        </div>
      </nav>
    </header>

    <main class="flex-shrink-0">
      <div class="container">
        <h1 class="mt-1">Sticky footer with fixed navbar</h1>
        <p class="lead">Pin a footer to the bottom of the viewport in desktop browsers with this custom HTML and CSS. A fixed navbar has been added with <code class="small">padding-top: 60px;</code> on the <code class="small">main &gt; .container</code>.</p>
        <p>Back to <a href="/docs/5.0/examples/sticky-footer/">the default sticky footer</a> minus the navbar.</p>
      </div>
    </main>
    
    <footer class="footer mt-auto py-3 bg-light">
      <div class="container">
        <span class="text-muted">Place sticky footer content here.</span>
      </div>
    </footer>
    
  </div>
  </template>
  
  <script setup>
  
  </script>
  
  <style scoped>
  main > .container {
    padding: 60px 15px 0;
  }
  </style>

結果:

image.png

vue-router (おまけ)

$ yarn add vue-router

src/main.js を以下のように変更する。

src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

//import './assets/main.css'
import 'bootstrap'
import "bootstrap/dist/css/bootstrap.min.css";

const app = createApp(App)

app.use(router)

app.mount('#app')

/src/router を作成して /src/router/index/js を次のようにします。

src/router/index.js
import { createRouter, createWebHashHistory } from 'vue-router';
// 上の import は必須
import HelloWorld from '../components/HelloWorld.vue';
import HomeView from '../components/HomeView.vue';

// ここは読み込ませるページの内容に依存
// 何もページが無い場合は空の配列を与えておけばとりあえずエラーにはならない。
const routes = [
    {
        path: '/',
        name: 'mainpage',
        component: HomeView
    },
    {
        path: '/hello',
        name: 'hellopage',
        component: HelloWorld
    },
]

// これ以下は必須
const router = createRouter({
    history: createWebHashHistory(),
    routes
})
  
export default router

src/App.vuemain 要素の中に <router-view></router-view> を追加する(一例)。

src/App.vue
<template>
<div class="d-flex flex-column h-100">
<header>
  <nav class="navbar navbar-expand-md navbar-dark bg-dark">
    <div class="container-fluid">
      <span class="navbar-brand">Navbar
      </span>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
          <li class="nav-item">
            <a class="nav-link active" aria-current="page" href="#">Home</a>
          </li>
          <li class="nav-item">
            <router-link class="nav-link active" aria-current="page" to="/hello">Hello</router-link>
          </li>
          <li class="nav-item">
            <button class="btn btn-outline-light" @click="$router.push('/hello')">Hello</button>
          </li>
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
              Dropdown
            </a>
            <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
              <li><a class="dropdown-item" href="#">Action</a></li>
              <li><a class="dropdown-item" href="#">Another action</a></li>
              <li><hr class="dropdown-divider"></li>
              <li><a class="dropdown-item" href="#">Something else here</a></li>
            </ul>
          </li>
          <li class="nav-item">
            <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
          </li>
        </ul>
        <form class="d-flex">
          <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
          <button class="btn btn-outline-success" type="submit">Search</button>
        </form>
      </div>
    </div>
  </nav>
</header>
<main class="flex-shrink-0">
  <router-view></router-view>
</main>

<footer class="footer mt-auto py-3 bg-light">
  <div class="container">
    <span class="text-muted">Place sticky footer content here.</span>
  </div>
</footer>
</div>
</template>

<script setup>

</script>

<style scoped>
main > .container {
  padding: 60px 15px 0;
}
</style>

vue-router で遷移する場合は、<router-link to="/hoge">HOGE</router-link> とします。<button class="btn" @click="$router.push('/hello')">Hello</button> みたいな方法もありです。

components/HomeView.vue の例。

components/HomeView.vue
<template>
  <div class="container">
    <h1 class="mt-1">Sticky footer with fixed navbar</h1>
    <p class="lead">Pin a footer to the bottom of the viewport in desktop browsers with this custom HTML and CSS. A fixed navbar has been added with <code class="small">padding-top: 60px;</code> on the <code class="small">main &gt; .container</code>.</p>
    <p>Back to <a href="/docs/5.0/examples/sticky-footer/">the default sticky footer</a> minus the navbar.</p>
  </div>
</template>

これで、画面遷移が可能になります。

さらなるおまけ

vue-router で historical mode を使っているときに、リロードしたときに 404 になるのを防ぐ方法について。

/public_redirects というファイルを作り、中身を下記にします。

/*    /index.html   200

もひとつおまけ:Vite の HMR 設定

vite.config.js を下記のようにしておけば、コードを更新すると自動的にページの読み込みがなされます。ただし、アイコンや画像などを外部URLから取ってくるようなコードを追加したときは、リロードが必要のようです(多分)

vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  server: {
    watch: {
      usePolling: true
    }
  },
  plugins: [vue()]
})
5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?