20200806のvue.jsに関する記事は26件です。

【Vue.js】vue-headの導入について

フロント開発をする中、head要素をvueで管理する方法として、
vue-headというライブラリを導入する機会があったので、備忘録としてまとめておく。

前提

vue-routerを導入している事。
※この記事ではvue-routerについての解説は行いません。

手順

導入自体はとても簡単。
まずはnpmコマンドでパッケージをインストール。

npm install vue-head --save

今回はmain.jsで読み込みます。

main.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import VueHead from 'vue-head'

Vue.use(VueHead)
Vue.use(VueRouter)

あとは各ページのコンポーネント毎にタイトルとmetaタグ設定すればOK。

home.vue
export default {
  head: {
    title() {
      return {
        inner: 'App',
        separator: '|',
        complement: 'page',
      }
    },
    meta: [
      { name: 'description', content: 'My description', id: 'desc' }
    ]
  }
    ...
  }
}

router.jsで表示するページ毎のタイトルを定義しておいて、
複数ページで共有するコンポーネントがあれば、簡単にタイトルやmetaの切り替えが出来ます。

更に共通の内容があれば、Mixinする事でよりシンプルに書く事が出来ます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】Vue Routerとは?使い方

【Vue.js】Vue Routerとは?使い方

Vue.jsの公式ライブラリの一つである、Vue Routerについて。

公式ページ
https://router.vuejs.org/ja/guide/#html

Vue Routerとは?

WEBページのルーティングを制御するためのVue公式プラグイン。SPAを構築できる

SPAとは?

Single Page Applicationの略。
URLそのままでユーザーの操作に合わせてページの内容を変化させる。Ajaxでサーバーからデータを取得して動的に更新する。

画面切り替え時にWEBサーバーからページをDLする必要がないため、表示速度が早くなりUX改善に繋がる。

デメリットとしては、初回のロードで全てのコンテンツを読み込むため、初回ロードは重くなる。URLが単一なので、個々のページがインデックスされない(SEO上はおすすめできない)。

(参考)SPAの画面と挙動のイメージ動画
https://www.youtube.com/watch?v=wlVmmsMD28w&t=81s

ルーティングとは

URLと表示するページを紐づけること。
あるURLが入力された時は、このディレクトリのこのページを表示する。といったルール決めをする。

Vue Routerの読み込み

VueのライブラリとVue Routerのライブラリの2つをCDNで読み込む。

<Vur routerのライブラリCDN>
・最新版
https://unpkg.com/vue-router/dist/vue-router.js

・バージョン指定
https://unpkg.com/vue-router@3.0.7/dist/vue-router.js

以下をbodyタグ終端の上に記述。

.htmlバージョン指定
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="https://unpkg.com/vue-router@3.0.7/dist/vue-router.js"></script>
.html最新バージョン
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

ルーティングの設定

htmlの記述

リンクの設置はrouter-linkタグを使う。

<router-link to="/ページ">アンカーテキスト</router-link>

.html
        <!-- topページへのリンク -->
        <router-link to="/top">top</router-link>

        <!-- userページへのリンク -->
        <router-link to="/user">user</router-link>

jsの記述

new VueRouterでVue Routerのインスタンスを生成する。
routesオプションを設定する。値は配列で、プロパティはpathcomponentを設定する。

  • path: 'ページのパス'
  • component: テンプレート(テンプレを格納した変数)
.js
    <script>
        const router = new VueRouter({
            routes: [
                {
                    path: '/top',
                    component: Top
                },
                {
                    path: '/user',
                    component: User
                }
            ]
        })
    </script>


表示するテンプレートの設定

テンプレートはJSファイル内(scriptタグ内でも可)に作成し、reoute-viewタグ内で読み込む。

jsの記述

const 変数名 = { template: '内容'}

.js
        const Top = { template: '<div>Top</div>'}
        const User = { template: '<div>User</div>'} 

htmlの記述

各ページの内容はrouter-viewタグ内に記述する。

.html
<router-view></router-view>


routerのインスタンスをVueインスタンスに渡す

routerプロパティと$mount修飾子で、VueRouterインスタンスをVueインスタンスに渡す。

省略表記が使える。
router: router
  ↓
router

.js
        const app = new Vue({
            //router: router
            router
        }).$mount('#app')

routerプロパティにVueRouterインスタンスが入った変数(ここではrounter)を渡している。

静的ページ完成形

image.png

▼topクリック時のURL
~/vue-router/index.html#/top

▼userクリック時のURL
~/vuejs/vue-router/index.html#/user

※vue-routerはルートディレクトリ名

▼ソースコード
jsはscriptタグでインライン表記。

.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue Router</title>
</head>
<body>
    <div id="app">
        <!-- topページへのリンク -->
        <router-link to="/top">top</router-link>

        <!-- userページへのリンク -->
        <router-link to="/user">user</router-link>

      <!-- コンポーネントの表示領域 -->
        <router-view></router-view>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="https://unpkg.com/vue-router@3.0.7/dist/vue-router.js"></script>
    <!-- <script src="script.js"></script> -->
    <script>
        const Top = { template: '<div>Top</div>'}
        const User = { template: '<div>User</div>'} 

      const router = new VueRouter({
        routes: [
          {
            path: '/top',
            component: Top
          },
          {
            path: '/user',
            component: User
          }
        ]
      })

        const app = new Vue({
            router: router
        }).$mount('#app')
    </script>
</body>
</html>


URLパラメータの使用

URLの記載情報をURLパラメータで取得できるようにする。
ユーザー毎に固有の値を割り振り、その値を取得してコンテンツを出し分ける時に使用する。

作業手順

(1) リンク先のURLにパラメータを付与する。
<router-link to="/パス/xxx"></router-link>

(2) ルーティングのpathの形を合わせ、URLパラメータで取得したい値を 「:任意の名前」とする。
path: '/パス/:URLパラメータ名'

指定した名前が、paramsオブジェクトの中にプロパティ名として格納される。

値は、URLパターンとマッチする部分になる。
 ┗ 例: {params:[{URLパラメータ名:xxx}]}

(3) URLパラメータの表示
$route.params.URLパラメータ名で格納されたプロパティを取得できる。

URLパラメータを活用したプログラム

URLパラメータを定義、取得して画面上に表示する。

▼userクリック時のURL
~/vuejs/vue-router/index.html#/user/123
 ┗ /123:URLパラメータ

image.png
.html
<body>
    <div id="app">
        <!-- topページへのリンク -->
        <router-link to="/top">top</router-link>

        <!-- URLパラメータ --><!-- userページへのリンク -->
        <router-link to="/user/123">user</router-link>

      <!-- コンポーネントの表示領域 -->
        <router-view></router-view>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="https://unpkg.com/vue-router@3.0.7/dist/vue-router.js"></script>
    <!-- <script src="script.js"></script> -->
    <script>
        const Top = { template: '<div>Top</div>'}
        //URLパラメータ
        const User = { template: '<div>User <p>取得したルートパラメータ:{{$route.params.userId}}</p></div>'} 

      const router = new VueRouter({
        routes: [
          {
            path: '/top',
            component: Top
          },
          {
            //URLパラメータ
            path: '/user/:userId',
            component: User
          }
        ]
      })

        const app = new Vue({
            router: router
        }).$mount('#app')
    </script>
</body>


ルートに名前をつける

リンク先でパスを指定していたのに対し、設定した名前で指定することができる。

作業手順

(1) routesオプションの中にnameプロパティを設定する。
name: '任意の名前'

.js
      const router = new VueRouter({
        routes: [
          {
            //URLパラメータ
            path: '/user/:userId',
            name: 'user',
            component: User
          }
        ]
      })

(2) router-linkのto属性に設定したプロパティを渡す。
:to=" {name: '任意の名前', params: { URLパラメータ名: URLパラメータ} } "

.html
<router-link :to=" {name: 'user', params: { userId: 123} } ">user</router-link> 

<注意点>
・ルートの名前:文字列(シングルクオテーション必要)
・パラメータオブジェクトのプロパティ名:変数(シングルクオテーション不要)



▼コード全体

.html
<body>
    <div id="app">
        <!-- topページへのリンク -->
        <router-link to="/top">top</router-link>

        <!-- userページへのリンク --><!-- URLパラメータ -->
        <!-- <router-link to="/user/123">user</router-link> -->

        <!-- ルート名を使ったリンク作成 -->
        <router-link :to=" {name: 'user', params: { userId: 123} } ">user</router-link> 

      <!-- コンポーネントの表示領域 -->
        <router-view></router-view>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="https://unpkg.com/vue-router@3.0.7/dist/vue-router.js"></script>
    <!-- <script src="script.js"></script> -->
    <script>
        const Top = { template: '<div>Top</div>'}
        //URLパラメータ
        const User = { template: '<div>User <p>取得したルートパラメータ:{{$route.params.userId}}</p></div>'} 

      const router = new VueRouter({
        routes: [
          {
            path: '/top',
            component: Top
          },
          {
            //URLパラメータ
            path: '/user/:userId',
            name: 'user',
            component: User
          }
        ]
      })

        const app = new Vue({
            router: router
        }).$mount('#app')
    </script>
</body>
</html>


ネストされたルート

入れ子になった要素を切り替える。

例えば、userディレクトリの下にprofileとblogページがあり、
大枠はuserのテンプレートを使い、それぞれに合わせページの中身の一部を切り替える場合。

<例>
~/user/
~/user/profile
~/user/blog

ネストされたルートの作成方法

・親となるtemplateの中に、route-viewを設置する。
・routesプロパティにchildrenプロパティを追加する。

js改行の書き方

jsファイルはバッククオートで囲むことで改行することができる。

シングルクオテーションだとエラーになる。

.js
        const User = { template: `  //改行する場合はバッククオートに変える
            <div class="user">
                <h2>User 取得したルートパラメータ:{{$route.params.userId}}</h2>
                <router-view></router-view>
            </div>`
        } 

router-viewの入れ子

親となるテンプレートの中にroute-viewタグを記述する。

.js
        const User = { template: `  //改行する場合はバッククオートに変える
            <div class="user">
                <h2>User {{$route.params.userId}}</h2>
                <router-view></router-view>
            </div>`
        } 

子要素のテンプレートを作る

作り方は通常通り。

.js
            template: `
            <div class="profile">
                    <h2>Profile {{$route.params.userId}}</h2>
            </div>`
        }

        const Blog = {
            template: `
            <div class="blog">
                    <h2>Blog {{$route.params.userId}}</h2>
            </div>`
        }

ルーティングの設定

親要素にchildrenプロパティを追加し、配列形でpathとcomponentを記載する。

.js
      const router = new VueRouter({
        routes: [
          {
            path: '/user/:userId',
            component: User,
            children: [
                {
                    path: 'profile',
                    component: Profile
                },
                {
                    path: 'blog',
                    component: Blog
                }
            ]
          }
        ]
      })

挙動確認

▼ブラウザの表示

/user/123 /user/123/profile /user/123/blog
image.png
image.png
image.png
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】Vue Routerとは?使い方と実例

【Vue.js】Vue Routerとは?使い方

Vue.jsの公式ライブラリの一つである、Vue Routerについて。

公式ページ
https://router.vuejs.org/ja/guide/#html

目次

  1. Vue Routerとは?
    1. SPAとは?
    2. ルーティングとは?
  2. CDNによるVue Routerの読み込み
  3. ルーティングの設定
    1. jsの記述
    2. htmlの記述
    3. routerのインスタンスをvueインスタンスに渡す
  4. 静的ページ完成形
  5. URLパラメータの使用
    1. 作業手順
    2. URLパラメータを活用したプログラム
  6. ルートに名前をつける方法
  7. ネストされたテンプレートとルートの作成方法
    1. 作成方法
    2. jsファイルの改行の書き方
    3. router-viewの入れ子
    4. 子要素のテンプレート作成
    5. ルーティングの設定
    6. 確認用ソースコード
  8. リダイレクトの設定方法
  9. 名前つきルートのリダイレクトの方法
  10. URLそのままで違うページの内容を表示する方法(エイリアス)
  11. URLのハッシュ(#)を取り除く方法

Vue Routerとは?

WEBページのルーティングを制御するためのVue公式プラグイン。SPAを構築できる

SPAとは?

Single Page Applicationの略。
URLそのままでユーザーの操作に合わせてページの内容を変化させる。Ajaxでサーバーからデータを取得して動的に更新する。

画面切り替え時にWEBサーバーからページをDLする必要がないため、表示速度が早くなりUX改善に繋がる。

デメリットとしては、初回のロードで全てのコンテンツを読み込むため、初回ロードは重くなる。URLが単一なので、個々のページがインデックスされない(SEO上はおすすめできない)。

(参考)SPAの画面と挙動のイメージ動画
https://www.youtube.com/watch?v=wlVmmsMD28w&t=81s

ルーティングとは?

URLと表示するページを紐づけること。
あるURLが入力された時は、このディレクトリのこのページを表示する。といったルール決めをする。

CDNによるVue Routerの読み込み

VueのライブラリとVue Routerのライブラリの2つをCDNで読み込む。

<Vur routerのライブラリCDN>
・最新版
https://unpkg.com/vue-router/dist/vue-router.js

・バージョン指定
https://unpkg.com/vue-router@3.0.7/dist/vue-router.js

以下をbodyタグ終端の上に記述。

.htmlバージョン指定
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="https://unpkg.com/vue-router@3.0.7/dist/vue-router.js"></script>
.html最新バージョン
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

ルーティングの設定

htmlの記述

リンクの設置はrouter-linkタグを使う。

<router-link to="/ページ">アンカーテキスト</router-link>

.html
        <!-- topページへのリンク -->
        <router-link to="/top">top</router-link>

        <!-- userページへのリンク -->
        <router-link to="/user">user</router-link>

jsの記述

new VueRouterでVue Routerのインスタンスを生成する。
routesオプションを設定する。値は配列で、プロパティはpathcomponentを設定する。

  • path: 'ページのパス'
  • component: テンプレート(テンプレを格納した変数)
.js
    <script>
        const router = new VueRouter({
            routes: [
                {
                    path: '/top',
                    component: Top
                },
                {
                    path: '/user',
                    component: User
                }
            ]
        })
    </script>


表示するテンプレートの設定

テンプレートはJSファイル内(scriptタグ内でも可)に作成し、reoute-viewタグ内で読み込む。

jsの記述

const 変数名 = { template: '内容'}

.js
        const Top = { template: '<div>Top</div>'}
        const User = { template: '<div>User</div>'} 

htmlの記述

各ページの内容はrouter-viewタグ内に記述する。

.html
<router-view></router-view>


routerのインスタンスをVueインスタンスに渡す

routerプロパティと$mount修飾子で、VueRouterインスタンスをVueインスタンスに渡す。

省略表記が使える。
router: router
  ↓
router

.js
        const app = new Vue({
            //router: router
            router
        }).$mount('#app')

routerプロパティにVueRouterインスタンスが入った変数(ここではrounter)を渡している。

静的ページ完成形

image.png

▼topクリック時のURL
~/vue-router/index.html#/top

▼userクリック時のURL
~/vuejs/vue-router/index.html#/user

※vue-routerはルートディレクトリ名

▼ソースコード
jsはscriptタグでインライン表記。

.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue Router</title>
</head>
<body>
    <div id="app">
        <!-- topページへのリンク -->
        <router-link to="/top">top</router-link>

        <!-- userページへのリンク -->
        <router-link to="/user">user</router-link>

      <!-- コンポーネントの表示領域 -->
        <router-view></router-view>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="https://unpkg.com/vue-router@3.0.7/dist/vue-router.js"></script>
    <!-- <script src="script.js"></script> -->
    <script>
        const Top = { template: '<div>Top</div>'}
        const User = { template: '<div>User</div>'} 

      const router = new VueRouter({
        routes: [
          {
            path: '/top',
            component: Top
          },
          {
            path: '/user',
            component: User
          }
        ]
      })

        const app = new Vue({
            router: router
        }).$mount('#app')
    </script>
</body>
</html>


URLパラメータの使用

URLの記載情報をURLパラメータで取得できるようにする。
ユーザー毎に固有の値を割り振り、その値を取得してコンテンツを出し分ける時に使用する。

作業手順

(1) リンク先のURLにパラメータを付与する。
<router-link to="/パス/xxx"></router-link>

(2) ルーティングのpathの形を合わせ、URLパラメータで取得したい値を 「:任意の名前」とする。
path: '/パス/:URLパラメータ名'

指定した名前が、paramsオブジェクトの中にプロパティ名として格納される。

値は、URLパターンとマッチする部分になる。
 ┗ 例: {params:[{URLパラメータ名:xxx}]}

(3) URLパラメータの表示
$route.params.URLパラメータ名で格納されたプロパティを取得できる。

URLパラメータを活用したプログラム

URLパラメータを定義、取得して画面上に表示する。

▼userクリック時のURL
~/vuejs/vue-router/index.html#/user/123
 ┗ /123:URLパラメータ

image.png
.html
<body>
    <div id="app">
        <!-- topページへのリンク -->
        <router-link to="/top">top</router-link>

        <!-- URLパラメータ --><!-- userページへのリンク -->
        <router-link to="/user/123">user</router-link>

      <!-- コンポーネントの表示領域 -->
        <router-view></router-view>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="https://unpkg.com/vue-router@3.0.7/dist/vue-router.js"></script>
    <!-- <script src="script.js"></script> -->
    <script>
        const Top = { template: '<div>Top</div>'}
        //URLパラメータ
        const User = { template: '<div>User <p>取得したルートパラメータ:{{$route.params.userId}}</p></div>'} 

      const router = new VueRouter({
        routes: [
          {
            path: '/top',
            component: Top
          },
          {
            //URLパラメータ
            path: '/user/:userId',
            component: User
          }
        ]
      })

        const app = new Vue({
            router: router
        }).$mount('#app')
    </script>
</body>


ルートに名前をつける方法

リンク先でパスを指定していたのに対し、設定した名前で指定することができる。

作業手順

(1) routesオプションの中にnameプロパティを設定する。
name: '任意の名前'

.js
      const router = new VueRouter({
        routes: [
          {
            //URLパラメータ
            path: '/user/:userId',
            name: 'user',
            component: User
          }
        ]
      })

(2) router-linkのto属性に設定したプロパティを渡す。
:to=" {name: '任意の名前', params: { URLパラメータ名: URLパラメータ} } "

.html
<router-link :to=" {name: 'user', params: { userId: 123} } ">user</router-link> 

<注意点>
・ルートの名前:文字列(シングルクオテーション必要)
・パラメータオブジェクトのプロパティ名:変数(シングルクオテーション不要)



▼コード全体

.html
<body>
    <div id="app">
        <!-- topページへのリンク -->
        <router-link to="/top">top</router-link>

        <!-- userページへのリンク --><!-- URLパラメータ -->
        <!-- <router-link to="/user/123">user</router-link> -->

        <!-- ルート名を使ったリンク作成 -->
        <router-link :to=" {name: 'user', params: { userId: 123} } ">user</router-link> 

      <!-- コンポーネントの表示領域 -->
        <router-view></router-view>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="https://unpkg.com/vue-router@3.0.7/dist/vue-router.js"></script>
    <!-- <script src="script.js"></script> -->
    <script>
        const Top = { template: '<div>Top</div>'}
        //URLパラメータ
        const User = { template: '<div>User <p>取得したルートパラメータ:{{$route.params.userId}}</p></div>'} 

      const router = new VueRouter({
        routes: [
          {
            path: '/top',
            component: Top
          },
          {
            //URLパラメータ
            path: '/user/:userId',
            name: 'user',
            component: User
          }
        ]
      })

        const app = new Vue({
            router: router
        }).$mount('#app')
    </script>
</body>
</html>


ネストされたテンプレートとルートの作成方法

入れ子になった要素を切り替える。

例えば、userディレクトリの下にprofileとblogページがあり、
大枠はuserのテンプレートを使い、それぞれに合わせページの中身の一部を切り替える場合。

<例>
~/user/
~/user/profile
~/user/blog

作成方法

・親となるtemplateの中に、route-viewを設置する。
・routesプロパティにchildrenプロパティを追加する。

jsファイルの改行の書き方

jsファイルはバッククオートで囲むことで改行することができる。

シングルクオテーションだとエラーになる。

.js
        const User = { template: `  //改行する場合はバッククオートに変える
            <div class="user">
                <h2>User 取得したルートパラメータ:{{$route.params.userId}}</h2>
                <router-view></router-view>
            </div>`
        } 

router-viewの入れ子

親となるテンプレートの中にroute-viewタグを記述する。

.js
        const User = { template: `  //改行する場合はバッククオートに変える
            <div class="user">
                <h2>User {{$route.params.userId}}</h2>
                <router-view></router-view>
            </div>`
        } 

子要素のテンプレート作成

作り方は通常通り。

.js
            template: `
            <div class="profile">
                    <h2>Profile {{$route.params.userId}}</h2>
            </div>`
        }

        const Blog = {
            template: `
            <div class="blog">
                    <h2>Blog {{$route.params.userId}}</h2>
            </div>`
        }

ルーティングの設定2

親要素にchildrenプロパティを追加し、配列形でpathとcomponentを記載する。

<注意点>
子要素のパスに「冒頭の/」は不要。

.js
      const router = new VueRouter({
        routes: [
          {
            path: '/user/:userId',
            component: User,
            children: [
                {
                    path: 'profile',
                    component: Profile
                },
                {
                    path: 'blog',
                    component: Blog
                }
            ]
          }
        ]
      })

確認用ソースコード

▼ブラウザの表示

/user/123 /user/123/profile /user/123/blog
image.png image.png image.png

▼ソースコード

.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue Router</title>
</head>
<body>
    <div id="app">
        <!-- topページへのリンク -->
        <router-link to="/top">top</router-link>

        <!-- userページへのリンク --><!-- URLパラメータ -->
        <router-link to="/user/123">user</router-link>
        <router-link to="/user/123/profile">user profile</router-link>
        <router-link to="/user/123/blog">user blog</router-link>

        <!-- ルート名を使ったリンク作成 -->
        <!-- <router-link :to=" {name: 'user', params: { userId: 123} } ">user</router-link>  -->

      <!-- コンポーネントの表示領域 -->
        <router-view></router-view>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="https://unpkg.com/vue-router@3.0.7/dist/vue-router.js"></script>
    <!-- <script src="script.js"></script> -->
    <script>
        const Top = { template: '<div>Top</div>'}
        //URLパラメータ
        const User = { template: `  //改行する場合はバッククオートに変える
            <div class="user">
                <h2>User {{$route.params.userId}}</h2>
                <router-view></router-view>
            </div>`
        } 

        const Profile = {
            template: `
            <div class="profile">
                    <h2>Profile {{$route.params.userId}}</h2>
            </div>`
        }

        const Blog = {
            template: `
            <div class="blog">
                    <h2>Blog {{$route.params.userId}}</h2>
            </div>`
        }

      const router = new VueRouter({
        routes: [
          {
            path: '/top',
            component: Top
          },
          {
            //URLパラメータ
            path: '/user/:userId',
            name: 'user',
            component: User,
            children: [
                {
                    path: 'profile',
                    component: Profile
                },
                {
                    path: 'blog',
                    component: Blog
                }
            ]
          }
        ]
      })

        const app = new Vue({
            router: router
        }).$mount('#app')
    </script>
</body>
</html>


リダイレクトの設定方法

routesオプションでredirectプロパティを設定する。

redirect: 'パス'

例:/userにアクセスしたら、/topに転送する。

.js
 const router = new VueRouter({
        routes: [
          {
            //リダイレクトの設定
            path: '/user,
            redirect: '/top'
          }
        ]
      })


名前つきルートのリダイレクトの方法

ルートにnameプロパティで名前が与えられている場合のリダイレクト方法。

redirect: { name: 'ルートの名前'}

例:/userにアクセスしたら、/topに転送する。

.js
 const router = new VueRouter({
        routes: [
          {
            //リダイレクトの設定
            path: '/old-page',
            redirect: '{name: 'new-p'}'
          },
          {
            path: '/new-page',
            name: 'new-p'
            component: newPage
          }
        ]
      })


URLそのままで違うページの内容を表示する方法(エイリアス)

エイリアスを設定すると、URLそのままで、違うページの内容を表示することができる。

routesオプションにaliasプロパティを設定する。

alias: 'パス'

.js
 const router = new VueRouter({
        routes: [
          {
            //エイリアスの設定
            path: '/old-page',
            component: oldPage,
            alias: '/new-page'
          },
          {
            path: '/new-page',
            component: newPage
          }
        ]
      })

~/old-pageにアクセスすると、URLはそのままで、/new-pageの内容が表示される。


URLのハッシュ(#)を取り除く方法

HTML5 Historyモードを使う。
VueRouterインスタンス生成時に、modeプロパティを追加することで対応可能。サーバーの設定も必要になる。

作業手順

(1) modeプロパティの設定
mode: 'history'

.js
const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

(2) サーバーの設定
詳細は公式ページ参照

公式ページ
https://router.vuejs.org/ja/guide/essentials/history-mode.html



以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue CLI のインストールで躓いた場合

公式サイトのインストールコマンドを打ったのにインストールできない。

環境 : Mac OS Catalina 10.15.6
シェル : ZSH
nodenv : 1.3.2
node : v8.11.3

インストールコマンド

% npm install -g @vue/cli

エラーメッセージ

npm ERR! code E404
npm ERR! 404 Not Found: @vue/cli-ui@^4.4.6

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/whoami/.npm/_logs/2020-08-06T07_59_42_517Z-debug.log

解決方法

以前インストールした(インストール失敗した?)すべてのvue cliを削除します。

sudo npm uninstall --global vue-cli
sudo npm uninstall --global @vue/cli

最新バージョンをインストールします。

sudo npm install --global @vue/cli@latest

バージョンを確認

vue -V
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】フェードイン・フェードアウト(トランジション)の使い方

【Vue.js】フェードイン・フェードアウト(トランジション)の使い方

Vue.jsに用意されているtransitionコンポーネントを使うフェードインやフェードアウトなどのtransitionを設定することができる。

公式ページ
https://jp.vuejs.org/v2/guide/transitions.html

目次

  1. トランジションの方法
  2. クラスの適用フェーズ
  3. 適用されるクラスの種類
  4. クラスの命名ルール
  5. CSSの設定
  6. トランジションの実例


トランジションの方法

条件を満たすと、特定のclass属性が付与される。このクラス属性に対してcssスタイルを設定する。

  • 使えるディレクティブ: v-show, v-if
  • 要素をtransitionタグで囲む
    • 中のタグは一つのみ。
    • 複数ある場合は上の要素のみ表示される。
  • 要素の状態によって専用のクラスが付与される。


クラスの適用フェーズ

要素の表示・非表示、トランジションの段階によってクラスが付与される。

image.png


適用されるクラスの種類

適用されるクラスは全部で6種類。enterとleaveに2分される。

  • enter: true(非表示→表示)の時に適用されるクラス
  • leave: false(表示→非表示)の時に適用されるクラス
クラス名 概要
v-enter 開始状態。trueになった瞬間に適用される
v-enter-active 活性状態。trueになった瞬間から、完全に表示されるまで適用される
v-enter-to 終了状態。trueによる遷移が終わった瞬間に適用される
v-leave 開始状態。falseが適用された瞬間に適用される
v-leave-active 遷移状態。falseによる遷移の開始から終了するまで適用される
v-leave-to 終了状態。falseによる遷移が完全した瞬間に適用される


クラスの命名ルール

transitionタグには name属性 で名前をつけることができる。

name属性がないデフォルト状態ではクラス名の冒頭に「-v」がつく。

name属性を記述した場合は、「-v」がname属性の値に置き換わる。

①name属性がない場合
<transition>
  ↓
v-enter

②name属性がある場合
<transition name="trans">
  ↓
trans-enter


CSSの設定

効果の持続期間はv-enter-active, v-leave-activeに適用する。

透過度(opacity)はv-enterv-enter-leaveに適用する。

css設定の例
.v-enter-active, .v-leave-active {
    transition: opacity 1s
}

.v-enter, .v-leave-to{
    opacity: 0;
}

トランジションの実例

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        isShown: false
    }
})
.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Transition</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="app">

        <div>
            <button @click="isShown =! isShown">表示切り替え</button>
        </div>

        <transition name="vshow">
            <p v-show="isShown">
                v-show="isShown"
            </p>
        </transition>

        <transition name="vif">
            <p v-if="isShown">
                v-if="isShown"
            </p>
        </transition>

        <br><hr>
        <p>isShownプロパティの値:{{isShown}}</p>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>
</html>
.css
.vshow-enter-active, .vshow-leave-active{
    transition: opacity 1s
}

.vshow-enter, vshow-leave-to{
    opacity: 0;
}

.vif-enter-active, .vif-leave-active{
    transition: opacity 2s
}

.vif-enter, vif-leave-to{
    opacity: 0;
}



以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VeeValidate に電話番号のバリデーションルールを追加する

先週投稿した VeeValidate で非同期的なバリデーションを行う記事に続いて、今回も VeeValidate ネタです。

VeeValidate には電話番号のバリデーションルールはデフォルトで用意されていません。そのため google-libphonenumber を使ってカスタムルールを実装してみたので、そのメモです。

ちなみに google-libphonenumber は電話番号のパースやバリデーションのための国際対応ライブラリです。非常に便利なので是非使ってみてください!

TL;DR

  • google-libphonenumber を使えば国内・国外どちらでも(あるいは両方について)電話番号のバリデーションが実装できる。
  • 入力文字列のフィルタは watch() 関数を使えばリアクティブに実装できる。

環境

実装

以下では VeeValidate のモジュール import は省略しています。

カスタムルール

まずは VeeValidate のカスタムルールを extend() で追加します。

import { PhoneNumberUtil } from 'google-libphonenumber'

extend('phone', {
  message: 'The {_field_} field format is invalid',
  validate(value) {
    const util = PhoneNumberUtil.getInstance()
    try {
      const phoneNumber = util.parseAndKeepRawInput(value, 'JP')
      return util.isValidNumber(phoneNumber)
    } catch (err) {
      return false
    }
  }
})

パースやバリデーションの機能は基本的に PhoneNumberUtil から利用できます。
入力値が短すぎるなど、場合によっては parseAndKeepRawInput でうまくパースできずに例外がスローされるので、その場合は false となるように try-catch で囲んでいます。

ちなみに国コードを指定せずにバリデーションするメソッドは(探した限りでは)用意されていないようです。
そのため日本の電話番号フォーマットにヒットしなかった場合は国外のフォーマットもチェックしたいといったケースでは以下のように全ての国コードを取得してループ処理する必要がありそうです。

validate(value) {
  const util = PhoneNumberUtil.getInstance()
  const jpFirstRegions = ['JP'].concat(
    util.getSupportedRegions().filter(regionCode => regionCode !== 'JP')
  )
  const validRegionCode = jpFirstRegions.find((regionCode) => {
    try {
      const phoneNumber = util.parseAndKeepRawInput(value, regionCode)
      return util.isValidNumber(phoneNumber)
    } catch (err) {
      return false
    }
  })
  return validRegionCode !== undefined
}

コンポーネント

次にコンポーネントです。
これは単に ValidationProvider の rules に phone を指定するだけです。

<template>
  <ValidationProvider
    v-slot="{ errors }"
    ref="provider"
    name="Phone Number"
    rules="phone"
  >
    <input
      v-model="value"
      type="text"
    />
    <span>{{ errors[0] }}</span>
  </ValidationProvider>
</template>

<script lang="ts">
import { createComponent, ref } from '@vue/composition-api'

export default createComponent({
  setup() {
    const value = ref<string | null>(null)
    return {
      value
    }
  }
})
</script>

ただこれだと数字以外の文字も入力できてしまうため、よりユーザーフレンドリーになるように数字のみ許可する場合は以下のようになります。

<script lang="ts">
import { createComponent, ref, watch } from '@vue/composition-api'

export default createComponent({
  setup() {
    const value = ref<string | null>(null)
    watch(() => {
      value.value = value.value.replace(/[0-9]/g, (s) => {
        // 全角から半角への変換
        return String.fromCharCode(s.charCodeAt(0) - 0xFEE0)
      }).replace(/[^0-9]/g, '')
    })
    return {
      value
    }
  }
</script>

watch() メソッドを用いて value の更新があった際に数字以外の文字をフィルターアウトするようにしており、ついでに全角数字は半角数字に変換しています1

ちなみに google-libphonenumber 自体は +1 202-456-1414 のような記号付きの電話番号フォーマットにも対応しているので、 + や - などを除外対象から外すように上記のルールを書き換えれば記号付きのケースにも対応できます。

input タグの type で制御すれば良いのでは?

input タグの type に numbertel を指定するアプローチだと幾つか問題があります。

まず number ですが、こちらはユーザーがコピペで +1 202-456-1414 のような記号を含む番号を入力した場合に value が空で評価されてしまいます!またデフォルトではスピンボタンが表示されますが、電話番号の数値の増減は不要であるため消去するのが結構手間です。

次に tel ですが、こちらは pattern を指定しても入力値をフィルターする機能はないため、許可していない文字も入力できてしまいます。

このような事情もあり、最終的に Vue 側で入力値をコントロールするアプローチに落ち着きました。


  1. この変換方法は YoheiM.NET さんの記事から拝借しました。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】コンポーネントの使い方と注意点

【Vue.js】コンポーネントの使い方と注意点

コンポーネントとは一塊の要素のこと。名前(コンポーネント名)をつけ、呼び出すことで、簡単に何度でも使うことができる。

コンポーネントのコードを変更すれば全体に適用される。

PHPなどのクラスのようなイメージ。コンポーネントを元に作成した実態が(Vue)インスタンス。

目次

  1. コンポーネントの注意点
  2. コンポーネントの作り方(グローバル)
  3. htmlのみのコンポーネント
  4. dataオプションを使ったコンポーネント
  5. コンポーネントの作り方(ローカル)
  6. コンポーネント応用例(クリック回数カウンター)
  7. 確認用ソースコード


コンポーネントの注意点

  • コンポーネントはnew Veuの上に書く(ローカルもグローバルも)
  • コンポーネント名は必ず「-」を含む。
  • templateオプションにタグを記述する。
  • dataは関数でなければならない。
  • コンポーネント名をタグ名として呼び出す。
  • el要素は必須(グローバルでない場合は外側に必要)

「-」を含んだ命名をケバブケースと呼ぶ。(小文字と大文字の組み合わせはキャメルケース)

templateオプションの注意点

  • スペルミスがあると作動しない(templeteなど)
  • 記述するタグは単一であること。
  • タグを並列に複数記述すると、前方のタグしか反映されない
  • 複数のタグを記述する場合はdivタグなどで全体を囲む。
NG
<span>Please Click:</span><button v-on:click="count++">{{count}}</button>
OK
<div><span>Please Click:</span><button v-on:click="count++">{{count}}</button></div>

コンポーネントの作り方(グローバル)

・Vue.componentメソッドを使う。
・第1引数:コンポーネント名(-を含む)
・第2引数:コンポーネントの内容

▼jsファイルの記述
Vue.component('コンポーネント名',{内容})
 ┗ new Vueよりも上に記述する
 ┗ コンポーネント名は「-」を含む
 ┗ templateオプションでhtml要素を定義
 ┗ dataを使う場合はfunctionを使う

htmlのみのコンポーネント

htmlのみで構成する場合、templateオプション内にタグを記述する。

▼Hello Worldを出力するプログラム

image.png
.js
Vue.component('hello-component', {
    template: '<p>Hello World</p>',
})
.html
<body>
    <div id="app">
        <div>
            <p>■グローバルコンポーネント</p>
            <hello-component></hello-component>
            <hello-component></hello-component>
            <hello-component></hello-component>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>

dataオプションを使ったコンポーネント

dataオプションを使う時は、functionを使う。プロパティはreturnの中に記述する。

▼dataオプション内のプロパティをマスタッシュ展開で呼び出すコンポーネント

image.png
.js
Vue.component('data-function', {
    template: '<p>{{mes1}} {{mes2}}</p>',
    data: function(){
        return {
            mes1: "data",
            mes2: "function return",
        }
    }
})


var app = new Vue({
    el:'#app'
})
.html
<body>
    <div id="app">
        <div>
            <p>■data functionを使ったコンポーネント</p>
            <data-function></data-function>
            <data-function></data-function>
            <data-function></data-function>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


コンポーネントの作り方(ローカル)

基本的な作り方はグローバルと同じ。引数が1つ(コンポーネントの中身のみ)となる。

コンポーネント名はVueインスタンス内のcomponentsオプションで定義。

▼jsファイルの記述
var 変数名 = {内容}

<グローバルとの違い>
- Vue.componentsを使わない。
- 変数に格納する。
- Vueインスタンス内でcomponentsオプションを使う
- componentsオプションのプロパティでコンポーネント名と変数を紐づける。

components: {コンポーネント名: コンポーネントの変数}

.js
var localComponent =  {
    template: '<p>Locally Hello World</p>'
    }


var app = new Vue({
    el:'#app',
    components: {
        'local-component': localComponent
    }
})


コンポーネント応用例(クリック回数カウンター)

ボタンをクリックすると1づつ加算するコンポーネントを作成する。

image.png
  • コンポーネント名: button-counter
  • 変数countはdata内のfunction内で戻り値として記述
  • templeteはdivタグで囲む
.js
//■ボタンカウンター
Vue.component('button-counter', {
    data: function () {
        return {
          count: 0
        }
      },
    template: '<div><span>Please Click: <button v-on:click="count++">{{count}}</button></span></div>'
})


var app = new Vue({
    el:'#app'
    }
})
.html
<body>
    <div id="app">

        <div>
            <p>■ボタンカウンター</p>
            <button-counter></button-counter>
            <button-counter></button-counter>
            <button-counter></button-counter>
            <button-counter></button-counter>     
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


確認用ソースコード

▼ブラウザの表示

image.png
.js
//■グローバルコンポーネント
Vue.component('hello-component', {
    template: '<p>Hello World</p>',
})


//■data functionを使ったコンポーネント
Vue.component('data-function', {
    template: '<p>{{mes1}} {{mes2}}</p>',
    data: function(){
        return {
            mes1: "data",
            mes2: "function return",
        }
    }
})


//■ボタンカウンター
Vue.component('button-counter', {
    data: function () {
        return {
          count: 0
        }
      },
    template: '<div><span>Please Click: <button v-on:click="count++">{{count}}</button></span></div>'
})



//■ローカルコンポーネント
var localComponent =  {
    template: '<p>Locally Hello World</p>'
    }


var app = new Vue({
    el:'#app',
    components: {
        'local-component': localComponent
    }
})
.html
<body>
    <div id="app">
        <div>
            <p>■グローバルコンポーネント</p>
            <hello-component></hello-component>
            <hello-component></hello-component>
            <hello-component></hello-component>
        </div>

        <br><hr>

        <div>
            <p>■data functionを使ったコンポーネント</p>
            <data-function></data-function>
            <data-function></data-function>
            <data-function></data-function>
        </div>

        <br><hr>

        <div>
            <p>■ローカルコンポーネント</p>
            <local-component></local-component>
            <local-component></local-component>
            <local-component></local-component>
        </div>

        <br><hr>

        <div>
            <p>■ボタンカウンター</p>
            <button-counter></button-counter>
            <button-counter></button-counter>
            <button-counter></button-counter>
            <button-counter></button-counter>

        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>



以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TypescriptでComposition APIを型付きサクサクで使う

はじめに

Vue3で導入されたComposition API。使ってみて、Componentが簡潔になることを実感。あと、データごとに関心事を分けて書くことができ、スッキリかけて気持ちが良い。

一方、型付きにするにはコツがあるのでそれを書く。型推論が効いた状態って贅沢感があっていいです。

コード

reactiveを型付きにする

ジェネリックで型を教えると良い

const strRef = ref<string>('Hello');
const state = reactive<{ name: string, age: number }>({ name: 'taro', age: 10 });

reactiveだと冗長な感じがする。何より読みづらいから型部分は切り出すと良い感じ。

interface Person {
  name: string,
  age: number
}

とコンポーネントの頭当たりで定義して

const state = reactive<Person>({ name: 'taro', age: 10});

というような使い方をする。

定義部分が離れちゃうのは拡張する際にめんどくさいので、機能拡張が欲しい感じ。

型名を Personってしたけど、スコープがコンポーネント内に限られているので単純に State でも良い気もする。(迷ってる。)

propsを型付きにする

Propsの型定義は特にComposition APIだからって変わらないですが、自分用のメモとして書く。

props {
  person: Object as PropType<Person>,
  persons: [] as PropType<Person[]>
}

配列やオブジェクトの場合、PropTypeを経由しないと型情報とみなされないようなので注意が必要。

(ComputedのときはRefになるんだっけ、調べなきゃ)

モジュール

Composition APIの良いところであるモジュール化なんだけど、実際使うときには注意が必要。

何かって言うと、 setup()と同じように、生成にReactiveとComputedを定義する必要があるっていうこと。実行順を考えないとReactiveが動作しないという問題がある。

つまり、クラス定義を行う場合コンストラクタが肥大化するという問題がある。コンストラクタで行っても良いんだけど、インターフェイスに則った Factory methodを作ったほうが読みやすいように思える。

interface Person {
  name: reactive<string>,
  age: Ref<number>,
  greet: Computed<string>
}

getPerson(name: string, age: number) {
    const nameRef = ref<string>(name);
  const ageRef = ref<number>(age);
  const greet = Computed(() => `Hello ${nameRef.value}!`;
  return { name: nameRef, age: ageRef, greet };
}

このように意外とスッキリ書ける。

メソッド内で関数書くことに抵抗がない言語なので、意外と Factory methodがクラスの定義と違いが少ない気がする。インターフェイスは冗長な感じになるけど。。。

サンプル

とりあえず、CodePenに(サンプル)を作った。
スクリーンショット 2020-08-06 16.22.09.png

見どころとしては、personを集約する personsクラスを定義している点。Composition APIの良い点だと思うのだけど、reactiveを入れ子にすることができる。

interface Person {
  name: Ref<string>,
  age: Ref<number>,
  greet: Computed<string>,
};

interface Persons {
  persons: reactive<Person[]>,
  add: (person: Person) => void,
  remove: (person: Person) => void,
};

persons はおおもとのコンポーネントである my-componentで利用され、 personpersonコンポーネントで利用され、コンポーネントでなんの設定もせず、それぞれreactiveとして利用できる。

これのおかげで、コンポーネントは関数や変数のマッピングのみとなる。

app.component('person', {
  template: // 省略
  ,
  props: {
    person: Object as PropType<Person>
  },
  setup(props, { emit }) {
    const mode = ref<'view' | 'edit'>('view');
    const remove = () => emit('remove', props.person);
    const pushEdit = () => mode.value = 'edit';
    const pushUpdate = () => mode.value = 'view';
    return { remove, pushEdit, pushUpdate, mode };
  }
});

この利点は、再利用というよりコンポーネントからロジックをモデルとして切り出すことによって見通しがよくなる点と、テストが容易なる利点がある。

やっててちょっと嫌になるのは配列の扱い。

const remove = (person: Person) => {
    const index = persons.value.indexOf(person);
    persons.value.splice(index, 1);
  };

依存関係の更新を行うために、spliceで削除を行う必要がある。

ひと目で削除しているように見えないので、なにか機能拡張を用意したいなぁ。

終わりに

元々はVuexで型付でやろうとしていたのだけど、モジュール化がきれいにできないことが判ってきて、Coposition APIが依存関係がわかりやすいので試してみたら良かった。

また、モジュールの分割が容易なのは非常に助かった。

Typescriptとしては、奇妙な書き方になってしまうが、なれてしまえばなんの問題も無い。

結論としては、非常におすすめ!!

参考

ありがとうございます!
Vue Mastery: https://www.vuemastery.com/courses/vue-3-reactivity
先取りVue 3.x !! Composition API を試してみる
Vue.js の Composition API における親子コンポーネント間のデータ受け渡し
vue-composition-apiを使って機能単位のコード分割と合成を試してみた
Vue + TypeScriptでpropsのObjectやArrayに型をつける
Ref vs Reactive Vue3 Composition APIのリアクティブ関数の探究 / ref vs reactive Vue Composition API Deep in

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

入門: Vue.jsで認証機能をモジュール化する

はじめに

入門: Vue.jsで認証機能を作る」でトークン認証を、「Vue.jsとIdentity Platform(IDプラットフォーム)でAPIの認証機能を作る」を作成してきました。

この2つの記事の内容を組合わせればIdentity Platformを使った認証が出来るわけですが、前回は基本的にはモジュール化せずにべた書きしていたので、今回は別ファイルに分けてモジュール化してみました。これで大分管理がすっきりしまた。

という分けで今回も備忘録を兼ねた解説記事となります。

Vuexのモジュール分割

以前の記事ではVuexのモジュールを使わずに書いていたのでトップレベルの名前空間を使っていたのでprefixを付けていました。

const store = new Vuex.Store({
    state: {
        userId: "",
        userToken: ""
    },
    mutations: {...},
    actions: {...},
    modules: {
    },
})

Vuexのモジュール機能を使って以下のように書きます。

src/sotre/index.js
import Vue from "vue";
import Vuex from "vuex";

import user from "@/store/modules/user";

Vue.use(Vuex);

const store = new Vuex.Store({
  modules: {
    user,
  },
});

export default store;

モジュールにuserを読み込んで追加しています。user.jsは以下の通り。

src/store/modules/user.js
export default {
  namespaced: true,
  state: {
    id: "",
    name: "",
    token: "",
    pic: "",
    expiration_time: "",
  },
  mutations: {
    store(state, user) {
      state.id = user.id;
      state.token = user.token;
      state.name = user.name;
      state.pic = user.pic;
      state.expiration_time = user.expiration_time;
    },
    drop(state) {
      state.id = state.token = state.name = state.pic = state.expiration_time = "";
    },
  },
  actions: {
    store(context, user) {
      context.commit("store", user);
    },
    drop(context) {
      context.commit("drop");
    },
  },
};

これで{{$store.state.user.id}}のように取り扱えるので名前空間を活用出来て良いですね。単独のstateで管理すると破綻は見えてるので、この方法で分割するのが基本なのだと思います。

ビジネスロジックをモジュール化する

前回はIdentity PlatformとやりとりするFirabase SDKの処理をそのままVueファイルに記載していました。ただ、これはプレゼンテーションロジックとビジネスロジックが混在するという意味で基本的によろしくないです。
「ログイン処理」のような画面から独立したビジネスロジックは分離して別ファイルで管理するのが一般的だと思います。今一つVue.jsでそういったファイルを何処に配置するのがデファクトスタンダードなのか分からなかったのですが、いったんsrc直下にmodulesというディレクトリを作ってそこにauth.jsを格納しました。ソースコードは以下の通り。

src/modules/auth.js
import firebase from "firebase";
import axios from "axios";
import store from "@/store";

export default {
  init() {
    const config = {
      apiKey: process.env.VUE_APP_AUTH_API_KEY,
      authDomain: process.env.VUE_APP_AUTH_API_DOMAIN,
    };
    firebase.initializeApp(config);
  },
  loginWithTwitter() {
    this.login(new firebase.auth.TwitterAuthProvider());
  },
  loginWithGoogle() {
    this.login(new firebase.auth.GoogleAuthProvider());
  },
  login(provider) {
    const callApi = (token) => {
      const url = "http://localhost:8080/secured";
      const config = {
        headers: {
          Authorization: "Bearer " + token,
        },
      };
      axios.get(url, config).then((response) => {
        store.dispatch("user/store", {
          id: response.data.id,
          token: token,
          name: response.data.name,
          expiration_time: new Date(response.data.expiration_time * 1000),
          pic: response.data.picture,
        });
      });
    };

    firebase
      .auth()
      .signInWithPopup(provider)
      .then((res) => {
        res.user
          .getIdToken()
          .then(callApi)
          .catch((error) => {
            console.log(error);
            this.errorMessage = error.message;
            this.showError = true;
          });
      });
  },
};

基本的には前回のコードを単にファイルに切り出しただけですが、initメソッドを定義してその中でconfigの初期化コードを入れました。これによってmain.jsにfirebaseのインポートが不要になり、別の実装に切り替える事などが容易になります。
また、Vuexを使ってuser/storeにデータを格納しています。

Vueテンプレートやmain.jsの中で呼び出すときは下記のように普通にJavaScriptのモジュールとしてインポートして使います。

src/views/Signin.vue
<template>
  <div class="signin">
    <h1>サインイン</h1>
    <button @click="signInWithGoogle">Googleで認証</button>
    <button @click="signInWithTwitter">Twitterで認証</button>
    <div v-show="$store.state.user.id">
      <p>ID: {{$store.state.user.id}}</p>
      <p>
        名前:
        <img :src="$store.state.user.pic" width="24px" height="24px" />
        {{$store.state.user.name}}
      </p>
      <p>有効期限: {{$store.state.user.expiration_time}}</p>
    </div>
  </div>
</template>

<script>
import Auth from "@/modules/auth";
export default {
  name: "Signin",
  data() {
    return {};
  },
  methods: {
    signInWithGoogle: function () {
      Auth.loginWithGoogle();
    },
    signInWithTwitter: function () {
      Auth.loginWithTwitter();
    },
  },
};
</script>

main.jsもAuth.init()を呼ぶ形に書き換えます。

src/main.js
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import axios from "axios";
import VueAxios from "vue-axios";
import store from "@/store";
import Auth from "@/modules/auth";

Vue.config.productionTip = false;
Vue.use(VueAxios, axios);

Auth.init();

new Vue({
  router,
  render: (h) => h(App),
  store,
}).$mount("#app");

Vue Routerで認可を行う

Vue Routerは特に変更はありません。

src/router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import Index from "../views/Index.vue";
import Create from "../views/Create.vue";
import Signin from "../views/Signin.vue";

// store
import Store from "@/store";

Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    name: "Index",
    component: Index,
    meta: { requiresAuth: true },
  },
  {
    path: "/create",
    name: "Create",
    component: Create,
    meta: { requiresAuth: true },
  },
  {
    path: "/signin",
    name: "Signin",
    component: Signin,
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

router.beforeEach((to, from, next) => {
  if (
    to.matched.some((record) => record.meta.requiresAuth) &&
    !Store.state.user.token
  ) {
    next({ path: "/signin", query: { redirect: to.fullPath } });
  } else {
    next();
  }
});

export default router;

まとめ

とりあえずちゃんとした認証が出来たのでVue.jsである程度は作りたいものが作れるようになった気がします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】フォームでv-modelを使う方法と注意事項

【Vue.js】フォームでv-modelを使う方法と注意事項
inputタグやセレクトボックスでv-modelディレクティブを使う方法。便利な修飾子についても学ぶ。

▼公式ページ
https://jp.vuejs.org/v2/guide/forms.html

目次

v-modelとは?
v-modelの注意点
textareaとv-model
チェックボックスとv-model
複数のチェックボックス
ラジオボタンとv-model
セレクトボックスとv-model
複数選択可能なセレクトボックス
v-modelの修飾子
.lazy
.trim
.number
確認用ソースコード


v-modelとは?

Vue.jsのディレクティブの1種。
dataオブジェクトのプロパティの値とinputタブの入力値や選択値のデータを連動することができる。

簡単に言うと、画面上でボックスに入力した内容が、jsファイルのデータに反映できる便利な機能。

jsファイル側のデータを更新した場合も、画面上の入力値に連動させることができるため、双方向データバインディング(データ結合)と呼ぶ。

▼使い方
タグの属性に記述する。
v-model="プロパティ名"
 ┗ プロパティ名:dataオブジェクトの中の連動させてい値をもつプロパティ名を記述。


v-modelの注意点

  1. v-model利用時は、value, checked, selected属性の初期値は無視される。
  2. 複数のcheckbox及びradioの場合valueは必要
  3. 入力を確定するまで、プロパティには反映されない。

inputタグのvalue無視事例

テキストボックスでv-modelを使った場合の事例。

.js
var app = new Vue({
    el:'#app',
    data:{
        message: ""
    }
})
.html
        <div>
            ■value属性は無視される
            <p>プロパティの状態:{{ message }}</p>
            <input type="text" v-model="message" value="初期入力値value">
        </div>
image.png

value="初期入力値value"となっているが、画面の入力欄はv-modelのプロパティ message:"" が反映され空欄となっている。

※Tips
プロパティで誤って、1箇所でも「=」を使用すると、テンプレートにJSが反映されない。


textareaとv-model

textareaのマスタッシュ展開では単方向となるため、入力値をプロパティに反映させたい場合は、textareaではv-modelを使う

・マスタッシュ展開で初期値を表示することは可能。
・プロパティの値が変化すれば、マスタッシュ展開の内容も連動する。
・入力値とプロパティを連動させる場合はv-modelを使う。
・v-modelとマスタッシュ展開の併用は、v-modelのみと同じ動作。

<textarea v-model="プロパティ名"></textarea>

textareaのマスタッシュ構文とv-modelの違い

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        message: "Default message"
    }
})
.html
   <div id="app">
        <div>
            ■textareaの注意点
            <p>プロパティの状態:{{ message }}</p>

            ①マスタッシュ構文による記述<br>
            <textarea name="" >{{message}}</textarea>

            <br><br>

            ②v-modelによる記述<br>
            <textarea name="" v-model="message"></textarea>


            <br><br>

            ③マスタッシュ構文とv-modelの併用<br>
            <textarea name="" v-model="message">{{message}}</textarea>
        </div>
   </div>

改行した場合「¥n」がプロパティに入る

image.png


チェックボックスとv-model

チェックボックスでv-modelを使う場合は、checked属性の代替となる。

チェックボックスが複数ある場合、プロパティは配列になる

v-model="プロパティ名"
チェックマークを入れると、プロパティの値がtrueに、外すとfalseになる。

▼チェックマークを入れた時の、プロパティを表示するプログラム

・チェックボックス:inputタグでtype="checkbox"にする
・labelタグ:フォームの各要素と連動する。
 ┗ for属性にid名を記述して紐付ける。for=id名

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //checkboxの状態
        isChecked: false
    }
})
.html
   <div id="app">
        <div>
            ■checkboxとv-model
            <br><input type="checkbox" id="checkbox" v-model="isChecked">
            <label for="checkbox">{{isChecked}}</label>

        </div>
   </div>

(補足)labelタグのメリット

labelタグは設置しても画面の見た目に大きな変化はない。ただし、使用するメリットは大きい。

<labelタグのメリット>
・タグが見やすくなる。
・label要素をクリックしても要素がアクティブになる
・読み上げ機能のサポート(label部が読みあげられる)


複数のチェックボックス

複数のチェックボックスの場合、プロパティは配列を使い、値は真偽値ではなく、valueで設定した値を使う。

配列内にvalueの値を記述するとチェックマークがつく。配列が空欄の場合、すべてチェックマークなしの状態となる。

<input type="checkbox" v-model="プロパティ名" value="固有の値">

プロパティ名:[]



▼複数のチェックボックスの事例

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //複数のcheckbox
        multiChecked: ["blue"]
    }
})
.html
    <div id="app">
        <div>
            ■複数のcheckbox
            <br><input type="checkbox" id="red" v-model="multiChecked" value="red">
            <label for="red">Red</label>

            <input type="checkbox" id="blue" v-model="multiChecked" value="blue">
            <label for="blue">Blue</label>

            <input type="checkbox" id="green" v-model="multiChecked" value="green">
            <label for="green">Green</label>

            <p>プロパティの状態: {{multiChecked}}</p>

        </div>
   </div>


ラジオボタンとv-model

一つの要素のみチェックできるラジオボタンの場合、各要素にvalueを割当てるv-modelで指定したプロパティの値とvalueの値が連動する。

<input type="radio" v-model="プロパティ名" value="固有の値">

プロパティ名:'チェックしたい要素のvalue'



▼複数のチェックボックスの事例

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //ラジオボタン
        radio: 'bad'
    }
})
.html
    <div id="app">
        <div>
            ■ラジオボタンとv-model
            <br><input type="radio" id="good" v-model="radio" value="good">
            <label for="good">good</label>

            <input type="radio" id="normal" v-model="radio" value="normal">
            <label for="normal">normal</label>

            <input type="radio" id="bad" v-model="radio" value="bad">
            <label for="bad">bad</label>

            <p>プロパティの状態: {{radio}}</p>

        </div>
   </div>


セレクトボックスとv-model

selectタグにv-modelを適用することで、選択した内容をプロパティに反映させることができる。

<初期値の設定>
①選択肢の中から選ぶ場合
初期表示したい、oputionタグのテキストをプロパティに設定する。

②専用の初期値を設定する場合
・初期値は表示のみで選択できないようにするには、optionタグに下記属性を付与する。
disabled value="プロパティの値"

セレクトボックスとv-modelの実例

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //セレクトボックス
        selected: 'initial',
        selected2: '3'
    }
})
.html
    <div id="app">
        <div>
            ■セレクトボックスとv-model
            <br>
            <p>①選択肢の中から初期値を選ぶ</p>
            <select v-model="selected2">
                <option>1</option>
                <option>2</option>
                <option>3</option>
            </select>

            <br><br>

            <p>②専用の初期値を設定する</p>
            <select v-model="selected">
                <option disabled value="initial">Please Select</option>
                <option>1</option>
                <option>2</option>
                <option>3</option>
            </select>

            <p>プロパティの状態: {{selected}}</p>

        </div>
   </div>


複数選択可能なセレクトボックス

selectタグの属性にmultipleを付与すると複数選択可能になる。

この場合、プロパティの値は配列となる。
配列にoptionタグのテキストを入力しておくと、初期選択状態になる。

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //複数選択可能なセレクトボックス
        multiSelect: [2,3]
    }
})
.html
    <div id="app">
        <div>
            ■複数選択可能なセレクトボックス
            <br>
            <select v-model="multiSelect" multiple>
                <option disabled value="initial">Please Select</option>
                <option>1</option>
                <option>2</option>
                <option>3</option>
                <option>4</option>
                <option>5</option>
            </select>

            <p>プロパティの状態: {{multiSelect}}</p>

        </div>
   </div>

v-modelの修飾子

v-modelには修飾子が用意されている。

修飾子 概要
.lazy バインドのタイミング(プロパティへの反映)を遅らせる
.trim 入力値の空白を除外してプロパティに代入する
.number 入力値を数値型に変換してから代入する

公式ページ
https://jp.vuejs.org/v2/guide/forms.html#%E4%BF%AE%E9%A3%BE%E5%AD%90


.lazy

通常のリアルタイム反映(日本語の場合は確定後の反映)から、Enterで確定やTABキーで要素から移動した場合への反映となる。

v-model.lazy="プロパティ名"


.trim

入力値から、前後の空白(全角・半角)を削除して、プロパティに反映する。

中間の空白は2つ以上の場合に1つのみとなる。
例: 「   you    good   」→「you good」


.number

inputタグはtype="number"としても、プロパティに格納する値は文字列となる。

selectedも同じく数値を選択しても、プロパティに格納される値は文字列となる。

v-model.numberとすることで、数値として格納できる。この場合、type="text"でも入力値は数値として扱われる。

<補足>
type="text"とtype="number"の違い。

  • type="number"の場合、入力欄の右側に▲、▼マークが表示される。(クリックで増減、加減できる)
  • type="number"の場合、文字を入力すると自動クリアされる。
  • type="text"とv-model.numberを併用した場合、数値のみの場合は数値として、文字を含む場合は文字列として扱われる。

入力値に+10した場合の出力

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
       //.number修飾子確認用
        figure1: '',
        figure2: '',
        figure3: ''
})
.html
    <div id="app">
        <div>
            ■修飾子 .number
            <p>①デフォルト(type="number")</p>
            <p>プロパティの状態:{{ figure1 }}</p>
            入力:<input type="number" v-model="figure1">
            <p>「+10」した値:{{figure1 + 10}}</p>

            <br>

            <p>②.numberあり</p>
            <p>プロパティの状態:{{ figure2 }}</p>
            入力:<input type="number" v-model.number="figure2">
            <p>「+10」した値:{{figure2 + 10}}</p>

            <br>

            <p>③.numberあり、type="text"</p>
            <p>プロパティの状態:{{ figure3 }}</p>
            入力:<input type="text" v-model.number="figure3">
            <p>「+10」した値:{{figure3 + 10}}</p>

        </div>
   </div>


確認用ソースコード

▼ブラウザの表示

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        message: "Default message",

        //checkboxの状態
        isChecked: false,

        //複数のcheckbox
        multiChecked: ["blue"],

        //ラジオボタン
        radio: 'bad',

        //セレクトボックス
        selected: 'initial',
        selected2: '3',
        selected3: '',

        //複数選択可能なセレクトボックス
        multiSelect: [2,3],

        //.number修飾子確認用
        figure1: '',
        figure2: '',
        figure3: ''

    }
})
.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Formにおけるv-modelの活用</title>
</head>
<body>
    <div id="app">

        <div>
            ■value属性は無視される
            <p>プロパティの状態:{{ message }}</p>
            入力:<input type="text" v-model="message" value="初期入力値value">
        </div>

        <hr><br>

        <div>
            ■textareaの注意点
            <p>プロパティの状態:{{ message }}</p>

            ①マスタッシュ構文による記述<br>
            <textarea name="" >{{message}}</textarea>

            <br><br>

            ②v-modelによる記述<br>
            <textarea name="" v-model="message"></textarea>


            <br><br>

            ③マスタッシュ構文とv-modelの併用<br>
            <textarea name="" v-model="message">{{message}}</textarea>
        </div>

        <hr><br>

        <div>
            ■checkboxとv-model
            <br><input type="checkbox" id="checkbox" v-model="isChecked">
            <label for="checkbox">{{isChecked}}</label>

        </div>

        <hr><br>

        <div>
            ■複数のcheckbox
            <br><input type="checkbox" id="red" v-model="multiChecked" value="red">
            <label for="red">Red</label>

            <input type="checkbox" id="blue" v-model="multiChecked" value="blue">
            <label for="blue">Blue</label>

            <input type="checkbox" id="green" v-model="multiChecked" value="green">
            <label for="green">Green</label>

            <p>プロパティの状態: {{multiChecked}}</p>

        </div>

        <hr><br>

        <div>
            ■ラジオボタンとv-model
            <br><input type="radio" id="good" v-model="radio" value="good">
            <label for="good">good</label>

            <input type="radio" id="normal" v-model="radio" value="normal">
            <label for="normal">normal</label>

            <input type="radio" id="bad" v-model="radio" value="bad">
            <label for="bad">bad</label>

            <p>プロパティの状態: {{radio}}</p>

        </div>

        <hr><br>

        <div>
            ■セレクトボックスとv-model
            <br>
            <p>①選択肢の中から初期値を選ぶ</p>
            <select v-model="selected2">
                <option>1</option>
                <option>2</option>
                <option>3</option>
            </select>


            <p>プロパティの状態: {{selected2}}</p>

            <br><br>

            <p>②専用の初期値を設定する</p>
            <select v-model="selected">
                <option disabled value="initial">Please Select</option>
                <option>1</option>
                <option>2</option>
                <option>3</option>
            </select>

            <p>プロパティの状態: {{selected}}</p>

        </div>

        <hr><br>

        <div>
            ■複数選択可能なセレクトボックス
            <br>
            <select v-model="multiSelect" multiple>
                <option disabled value="initial">Please Select</option>
                <option>1</option>
                <option>2</option>
                <option>3</option>
                <option>4</option>
                <option>5</option>
            </select>

            <p>プロパティの状態: {{multiSelect}}</p>

        </div>

        <hr><br>


        <div>
            ■修飾子 .lazy
            <p>①.lazyなし</p>
            <p>プロパティの状態:{{ message }}</p>
            入力:<input type="text" v-model="message">

            <p>②.lazyあり</p>
            <p>プロパティの状態:{{ message }}</p>
            入力:<input type="text" v-model.lazy="message">
        </div>

        <hr><br>

        <div>
            ■修飾子 .trim
            <p>プロパティの状態:{{ message }}</p>
            入力:<input type="text" v-model.trim="message">

        </div>

        <hr><br>

        <div>
            ■修飾子 .number
            <p>①デフォルト(type="number")</p>
            <p>プロパティの状態:{{ figure1 }}</p>
            入力:<input type="number" v-model="figure1">
            <p>「+10」した値:{{figure1 + 10}}</p>

            <br>

            <p>②.numberあり</p>
            <p>プロパティの状態:{{ figure2 }}</p>
            入力:<input type="number" v-model.number="figure2">
            <p>「+10」した値:{{figure2 + 10}}</p>

            <br>

            <p>③.numberあり、type="text"</p>
            <p>プロパティの状態:{{ figure3 }}</p>
            入力:<input type="text" v-model.number="figure3">
            <p>「+10」した値:{{figure3 + 10}}</p>

        </div>

        <hr><br>


        <div>
            ■プロパティ確認用
            <pre> {{$data}} </pre>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>
</html>

以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】フォームの要素でv-modelを使い倒す方法と注意事項

【Vue.js】フォーム要素でv-modelを使い倒す方法と注意事項

inputタグやセレクトボックスでv-modelディレクティブを使う方法。便利な修飾子についても学ぶ。

▼公式ページ
https://jp.vuejs.org/v2/guide/forms.html

目次

  1. v-modelとは?
  2. v-modelの注意点
  3. textareaとv-model
  4. チェックボックスとv-model
  5. 複数のチェックボックス
  6. ラジオボタンとv-model
  7. セレクトボックスとv-model
  8. 複数選択可能なセレクトボックス
  9. v-modelの修飾子
    1. .lazy
    2. .trim
    3. .number
  10. 確認用ソースコード


v-modelとは?

Vue.jsのディレクティブの1種。
dataオブジェクトのプロパティの値とinputタブの入力値や選択値のデータを連動することができる。

簡単に言うと、画面上でボックスに入力した内容が、jsファイルのデータに反映できる便利な機能。

jsファイル側のデータを更新した場合も、画面上の入力値に連動させることができるため、双方向データバインディング(データ結合)と呼ぶ。

▼使い方
タグの属性に記述する。
v-model="プロパティ名"
 ┗ プロパティ名:dataオブジェクトの中の連動させてい値をもつプロパティ名を記述。


v-modelの注意点

  1. v-model利用時は、value, checked, selected属性の初期値は無視される。
  2. 複数のcheckbox及びradioの場合valueは必要
  3. 入力を確定するまで、プロパティには反映されない。

inputタグのvalue無視事例

テキストボックスでv-modelを使った場合の事例。

.js
var app = new Vue({
    el:'#app',
    data:{
        message: ""
    }
})
.html
        <div>
            ■value属性は無視される
            <p>プロパティの状態:{{ message }}</p>
            <input type="text" v-model="message" value="初期入力値value">
        </div>
image.png

value="初期入力値value"となっているが、画面の入力欄はv-modelのプロパティ message:"" が反映され空欄となっている。

※Tips
プロパティで誤って、1箇所でも「=」を使用すると、テンプレートにJSが反映されない。


textareaとv-model

textareaのマスタッシュ展開では単方向となるため、入力値をプロパティに反映させたい場合は、textareaではv-modelを使う

・マスタッシュ展開で初期値を表示することは可能。
・プロパティの値が変化すれば、マスタッシュ展開の内容も連動する。
・入力値とプロパティを連動させる場合はv-modelを使う。
・v-modelとマスタッシュ展開の併用は、v-modelのみと同じ動作。

<textarea v-model="プロパティ名"></textarea>

textareaのマスタッシュ構文とv-modelの違い

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        message: "Default message"
    }
})
.html
   <div id="app">
        <div>
            ■textareaの注意点
            <p>プロパティの状態:{{ message }}</p>

            ①マスタッシュ構文による記述<br>
            <textarea name="" >{{message}}</textarea>

            <br><br>

            ②v-modelによる記述<br>
            <textarea name="" v-model="message"></textarea>


            <br><br>

            ③マスタッシュ構文とv-modelの併用<br>
            <textarea name="" v-model="message">{{message}}</textarea>
        </div>
   </div>

改行した場合「¥n」がプロパティに入る

image.png


チェックボックスとv-model

チェックボックスでv-modelを使う場合は、checked属性の代替となる。

チェックボックスが複数ある場合、プロパティは配列になる

v-model="プロパティ名"
チェックマークを入れると、プロパティの値がtrueに、外すとfalseになる。

▼チェックマークを入れた時の、プロパティを表示するプログラム

・チェックボックス:inputタグでtype="checkbox"にする
・labelタグ:フォームの各要素と連動する。
 ┗ for属性にid名を記述して紐付ける。for=id名

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //checkboxの状態
        isChecked: false
    }
})
.html
   <div id="app">
        <div>
            ■checkboxとv-model
            <br><input type="checkbox" id="checkbox" v-model="isChecked">
            <label for="checkbox">{{isChecked}}</label>

        </div>
   </div>

(補足)labelタグのメリット

labelタグは設置しても画面の見た目に大きな変化はない。ただし、使用するメリットは大きい。

<labelタグのメリット>
・タグが見やすくなる。
・label要素をクリックしても要素がアクティブになる
・読み上げ機能のサポート(label部が読みあげられる)


複数のチェックボックス

複数のチェックボックスの場合、プロパティは配列を使い、値は真偽値ではなく、valueで設定した値を使う。

配列内にvalueの値を記述するとチェックマークがつく。配列が空欄の場合、すべてチェックマークなしの状態となる。

<input type="checkbox" v-model="プロパティ名" value="固有の値">

プロパティ名:[]



▼複数のチェックボックスの事例

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //複数のcheckbox
        multiChecked: ["blue"]
    }
})
.html
    <div id="app">
        <div>
            ■複数のcheckbox
            <br><input type="checkbox" id="red" v-model="multiChecked" value="red">
            <label for="red">Red</label>

            <input type="checkbox" id="blue" v-model="multiChecked" value="blue">
            <label for="blue">Blue</label>

            <input type="checkbox" id="green" v-model="multiChecked" value="green">
            <label for="green">Green</label>

            <p>プロパティの状態: {{multiChecked}}</p>

        </div>
   </div>


ラジオボタンとv-model

一つの要素のみチェックできるラジオボタンの場合、各要素にvalueを割当てるv-modelで指定したプロパティの値とvalueの値が連動する。

<input type="radio" v-model="プロパティ名" value="固有の値">

プロパティ名:'チェックしたい要素のvalue'



▼複数のチェックボックスの事例

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //ラジオボタン
        radio: 'bad'
    }
})
.html
    <div id="app">
        <div>
            ■ラジオボタンとv-model
            <br><input type="radio" id="good" v-model="radio" value="good">
            <label for="good">good</label>

            <input type="radio" id="normal" v-model="radio" value="normal">
            <label for="normal">normal</label>

            <input type="radio" id="bad" v-model="radio" value="bad">
            <label for="bad">bad</label>

            <p>プロパティの状態: {{radio}}</p>

        </div>
   </div>


セレクトボックスとv-model

selectタグにv-modelを適用することで、選択した内容をプロパティに反映させることができる。

<初期値の設定>

①選択肢の中から選ぶ場合
初期表示したい、oputionタグのテキストをプロパティに設定する。

②専用の初期値を設定する場合
・初期値は表示のみで選択できないようにするには、optionタグに下記属性を付与する。
disabled value="プロパティの値"

セレクトボックスとv-modelの実例

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //セレクトボックス
        selected: 'initial',
        selected2: '3'
    }
})
.html
    <div id="app">
        <div>
            ■セレクトボックスとv-model
            <br>
            <p>①選択肢の中から初期値を選ぶ</p>
            <select v-model="selected2">
                <option>1</option>
                <option>2</option>
                <option>3</option>
            </select>

            <br><br>

            <p>②専用の初期値を設定する</p>
            <select v-model="selected">
                <option disabled value="initial">Please Select</option>
                <option>1</option>
                <option>2</option>
                <option>3</option>
            </select>

            <p>プロパティの状態: {{selected}}</p>

        </div>
   </div>


複数選択可能なセレクトボックス

selectタグの属性にmultipleを付与すると複数選択可能になる。

この場合、プロパティの値は配列となる。
配列にoptionタグのテキストを入力しておくと、初期選択状態になる。

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //複数選択可能なセレクトボックス
        multiSelect: [2,3]
    }
})
.html
    <div id="app">
        <div>
            ■複数選択可能なセレクトボックス
            <br>
            <select v-model="multiSelect" multiple>
                <option disabled value="initial">Please Select</option>
                <option>1</option>
                <option>2</option>
                <option>3</option>
                <option>4</option>
                <option>5</option>
            </select>

            <p>プロパティの状態: {{multiSelect}}</p>

        </div>
   </div>

v-modelの修飾子

v-modelには修飾子が用意されている。

修飾子 概要
.lazy バインドのタイミング(プロパティへの反映)を遅らせる
.trim 入力値の空白を除外してプロパティに代入する
.number 入力値を数値型に変換してから代入する

公式ページ
https://jp.vuejs.org/v2/guide/forms.html#%E4%BF%AE%E9%A3%BE%E5%AD%90


.lazy

通常のリアルタイム反映(日本語の場合は確定後の反映)から、Enterで確定やTABキーで要素から移動した場合への反映となる。

v-model.lazy="プロパティ名"


.trim

入力値から、前後の空白(全角・半角)を削除して、プロパティに反映する。

中間の空白は2つ以上の場合に1つのみとなる。
例: 「   you    good   」→「you good」


.number

inputタグはtype="number"としても、プロパティに格納する値は文字列となる。

selectedも同じく数値を選択しても、プロパティに格納される値は文字列となる。

v-model.numberとすることで、数値として格納できる。この場合、type="text"でも入力値は数値として扱われる。

<補足>
type="text"とtype="number"の違い。

  • type="number"の場合、入力欄の右側に▲、▼マークが表示される。(クリックで増減、加減できる)
  • type="number"の場合、文字を入力すると自動クリアされる。
  • type="text"とv-model.numberを併用した場合、数値のみの場合は数値として、文字を含む場合は文字列として扱われる。

入力値に+10した場合の出力

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
       //.number修飾子確認用
        figure1: '',
        figure2: '',
        figure3: ''
})
.html
    <div id="app">
        <div>
            ■修飾子 .number
            <p>①デフォルト(type="number")</p>
            <p>プロパティの状態:{{ figure1 }}</p>
            入力:<input type="number" v-model="figure1">
            <p>「+10」した値:{{figure1 + 10}}</p>

            <br>

            <p>②.numberあり</p>
            <p>プロパティの状態:{{ figure2 }}</p>
            入力:<input type="number" v-model.number="figure2">
            <p>「+10」した値:{{figure2 + 10}}</p>

            <br>

            <p>③.numberあり、type="text"</p>
            <p>プロパティの状態:{{ figure3 }}</p>
            入力:<input type="text" v-model.number="figure3">
            <p>「+10」した値:{{figure3 + 10}}</p>

        </div>
   </div>


確認用ソースコード

▼ブラウザの表示

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        message: "Default message",

        //checkboxの状態
        isChecked: false,

        //複数のcheckbox
        multiChecked: ["blue"],

        //ラジオボタン
        radio: 'bad',

        //セレクトボックス
        selected: 'initial',
        selected2: '3',
        selected3: '',

        //複数選択可能なセレクトボックス
        multiSelect: [2,3],

        //.number修飾子確認用
        figure1: '',
        figure2: '',
        figure3: ''

    }
})
.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Formにおけるv-modelの活用</title>
</head>
<body>
    <div id="app">

        <div>
            ■value属性は無視される
            <p>プロパティの状態:{{ message }}</p>
            入力:<input type="text" v-model="message" value="初期入力値value">
        </div>

        <hr><br>

        <div>
            ■textareaの注意点
            <p>プロパティの状態:{{ message }}</p>

            ①マスタッシュ構文による記述<br>
            <textarea name="" >{{message}}</textarea>

            <br><br>

            ②v-modelによる記述<br>
            <textarea name="" v-model="message"></textarea>


            <br><br>

            ③マスタッシュ構文とv-modelの併用<br>
            <textarea name="" v-model="message">{{message}}</textarea>
        </div>

        <hr><br>

        <div>
            ■checkboxとv-model
            <br><input type="checkbox" id="checkbox" v-model="isChecked">
            <label for="checkbox">{{isChecked}}</label>

        </div>

        <hr><br>

        <div>
            ■複数のcheckbox
            <br><input type="checkbox" id="red" v-model="multiChecked" value="red">
            <label for="red">Red</label>

            <input type="checkbox" id="blue" v-model="multiChecked" value="blue">
            <label for="blue">Blue</label>

            <input type="checkbox" id="green" v-model="multiChecked" value="green">
            <label for="green">Green</label>

            <p>プロパティの状態: {{multiChecked}}</p>

        </div>

        <hr><br>

        <div>
            ■ラジオボタンとv-model
            <br><input type="radio" id="good" v-model="radio" value="good">
            <label for="good">good</label>

            <input type="radio" id="normal" v-model="radio" value="normal">
            <label for="normal">normal</label>

            <input type="radio" id="bad" v-model="radio" value="bad">
            <label for="bad">bad</label>

            <p>プロパティの状態: {{radio}}</p>

        </div>

        <hr><br>

        <div>
            ■セレクトボックスとv-model
            <br>
            <p>①選択肢の中から初期値を選ぶ</p>
            <select v-model="selected2">
                <option>1</option>
                <option>2</option>
                <option>3</option>
            </select>


            <p>プロパティの状態: {{selected2}}</p>

            <br><br>

            <p>②専用の初期値を設定する</p>
            <select v-model="selected">
                <option disabled value="initial">Please Select</option>
                <option>1</option>
                <option>2</option>
                <option>3</option>
            </select>

            <p>プロパティの状態: {{selected}}</p>

        </div>

        <hr><br>

        <div>
            ■複数選択可能なセレクトボックス
            <br>
            <select v-model="multiSelect" multiple>
                <option disabled value="initial">Please Select</option>
                <option>1</option>
                <option>2</option>
                <option>3</option>
                <option>4</option>
                <option>5</option>
            </select>

            <p>プロパティの状態: {{multiSelect}}</p>

        </div>

        <hr><br>


        <div>
            ■修飾子 .lazy
            <p>①.lazyなし</p>
            <p>プロパティの状態:{{ message }}</p>
            入力:<input type="text" v-model="message">

            <p>②.lazyあり</p>
            <p>プロパティの状態:{{ message }}</p>
            入力:<input type="text" v-model.lazy="message">
        </div>

        <hr><br>

        <div>
            ■修飾子 .trim
            <p>プロパティの状態:{{ message }}</p>
            入力:<input type="text" v-model.trim="message">

        </div>

        <hr><br>

        <div>
            ■修飾子 .number
            <p>①デフォルト(type="number")</p>
            <p>プロパティの状態:{{ figure1 }}</p>
            入力:<input type="number" v-model="figure1">
            <p>「+10」した値:{{figure1 + 10}}</p>

            <br>

            <p>②.numberあり</p>
            <p>プロパティの状態:{{ figure2 }}</p>
            入力:<input type="number" v-model.number="figure2">
            <p>「+10」した値:{{figure2 + 10}}</p>

            <br>

            <p>③.numberあり、type="text"</p>
            <p>プロパティの状態:{{ figure3 }}</p>
            入力:<input type="text" v-model.number="figure3">
            <p>「+10」した値:{{figure3 + 10}}</p>

        </div>

        <hr><br>


        <div>
            ■プロパティ確認用
            <pre> {{$data}} </pre>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>
</html>

以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

create-nuxt-app v3.2.0を使ってNuxt+Typescriptのプロジェクトを構築する

まえがき

create-nuxt-app コマンドを使用してTS+Nuxtプロジェクトを作成しようとしたところ、いつの間にか仕様が変わっていてちょっと感動したので書いてみることにしました。

なお、本記事内ではNuxtのmiddlewareModuleを使ってAPIサーバーを構築することを前提に進めるているため、SSRになっております。
SPAの場合でもほぼ変わりはないかと思いますが、予めご留意ください。

プロジェクトの開始

yarnを使っているとcliで対話式にプロジェクトが始められるようになっています。

npmでもバージョンが5.2以上ならnpxコマンドが使用できますので、そちらからでも上記同様対話式にプロジェクトを開始することが可能です。

【 yarn 】

$ yarn create nuxt-app {project-name}

【 npx 】

$ npx create-nuxt-app {project-name}

最近このNuxt界隈では、過去に Typescriptと相性が悪い と言われていたことを根に持っているかのように活発にTS向けのアップデートが行われており、
気づけばこのプロジェクトの開始でもフレームワークを JavascriptTypescript か選択できるようになったようです。

また、今回API機能を作りますので、Deployment targetをHosting Node.jsにしてください。

私が実行した際の対話の実行結果は以下です。
実際にやってみていただくとわかりますが、設問ないの選択可能項目も、そもそも設問自体も減ったような印象を受けました。

? Project name: {project name}
? Programming language: TypeScript
? Package manager: Yarn
? UI framework: Vuetify.js
? Nuxt.js modules: Axios
? Linting tools: ESLint, Prettier
? Testing framework: Jest
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Server (Node.js hosting)
? Development tools: Semantic Pull Requests

ファイルの追記・修正

少し前まで(おそらく4月段階)まではここからTypescriptを使用するための準備が必要でした。

しかしこれまで必要だった加筆修正がいつのまにか最初から組み込まれたようで、具体的には以下の設定が不要になりました。

- Library
  - @nuxt/typescript-buildがバンドルされたのでインストール不要
  - @nuxtjs/eslint-config-typescriptもバンドルされましたのでインストール不要
  - @nuxt/typescript-runtime もバンドルされましたのでインストール不要
- nuxt.config.json
  - buildModule内、 `'@nuxt/typescript-build'`の記述が不要(最初から書いてある)
- tsconfig.json
  - デフォルトで準備されてます
- .eslintrc.js
  - 以前はTS用に書き換える必要がありましたが、デフォルトで @nuxtjs/eslint-config-typescript が記述されており、設定が反映済みでしたので修正不要

ただし、package.json内のscript項目で使用されている nuxt-ts について、デフォルトではグローバルにインストールされていることが前提になってしまっています。

もし yarn devnuxt-ts がないというようなエラーが出た際には以下のように package.jsonないのscriptを書き換えてください。

package.json
"script":{
  "dev": "npx nuxt-ts",
  "build": "npx nuxt-ts build",
  "start": "npx nuxt-ts start",
  "generate": "npx nuxt-ts generate",
}

それぞれ接頭に npx コマンドを追記するだけです。

不足ライブラリの追加

開発環境において不足しているライブラリを追加しましょう。

$ yarn add -E -D ts-node

ソースフォルダを整理する

対話式でプロジェクト作成した場合、何がソースフォルダなのかもわからないですし、
APIサーバーを実装するにも後からわかりにくくなってしまうので、
一般的なフォルダ構成に修正したいと思います。

まず、プロジェクトルートに src ディレクトリを、さらにその中に api(API server), client(webサービス) フォルダを作成しましょう。

続いて作成した src/client ディレクトリ配下に以下のフォルダを移動します。

- assets
- components
- layouts
- middleware
- node_modules
- pages
- plugins
- static
- store

ワンライナーで移動させたい方は以下のコマンドを使ってください。

mv assets components layouts pages plugins static store middleware src/client

続いて、 nuxt.config.js に以下を追記します。

module.exports = {
  srcDir: 'src/client' // <-これを追記
}

起動

ここまでできたらいったん起動してみましょう。

yarn devするだけです、そしてブラウザで localhost:3000 にアクセスしてみましょう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsのライフサクルを丁寧に図解し直してみた

そもそもVue.jsのライフサイクルとは?

Vueインスタンスが生成されていから破棄されるまでの流れのこと。
基本的にはページが遷移するたびに破棄されデータなどが初期化され新たに生成される。

なぜいちいち破棄しなければならないのか?

ページごとに値が残っていては、Vueとして、サービスとして機能しないから。

Vue公式のライフサイクルの説明

Vueのライフサイクルは公式で以下のように図解してある。
Vue.js公式・ライフサイクルダイアグラム
FireShot Capture 003 - Vue インスタンス — Vue.js - jp.vuejs.org.png

だが英語だし、初見だと少し分かりにくかったので自分なりに補足などしてまとめてみた。

用語確認

初期化
最初の状態に戻すこと。もしくは最初の状態を整えること。
(https://wa3.i-3-i.info/word12961.html)

マウント
Vueの形式で書かれたコンポーネントなどの仮想表現を最終的なUI表現に出力するプロセス。

リアクティブデータ
リアクティブとは値が監視され、値の変更があった場合検知すること。
つまり、リアクティブデータとはVue.jsに値の変更などを逐一監視されているデータのこと。

自分なりに詳細に図解

Vue-10-2.jpg

Vue-11.jpg

Vue-12.jpg

Vue-13.jpg

Vue-14.jpg

Vue-15 2.jpg

参考

Vueのライフサイクル
Vue.js ライフサイクルフック概要

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vue.js 同じurlに移動する

同じurl。
/article/333/ から /article/777/ に移動する場合。

これが同じ article だとうまく画面が切り替わらない。

そんなときの対応

hoge.vue

<router-link :to="{ path: '/article/777/'}">
   次のページへ
</router-link>

//略


beforeRouteUpdate (to, from, next) {

    this.nextId = to.params.id;//333
    this.getArticle();
    next();//必須 これを読み出さないと、urlが変わらない

},


//略


getArticle(){

    let dataform = new FormData();

    //現在のアドレスバーから 記事 IDを取得
    var id = this.$route.params.id;

    //次のIDが空じゃなければ
    if(this.nextId != ''){
        id = this.nextId;
    }

    dataform.append('id',id);
    axios.post('/article/view/', dataform).then(e => {

    }).catch((error) => {

        console.log(error);

    });


},

これで url もデータも切り替わる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel 前ページ、次ページ

laravel で 前後のページ、及びレコードを取得したい場合がある。
その時の書き方。


$next = Article::query()//単数形 User
    ->where('id','>',$request->id)
    ->orderBy('id','ASC')
    //NGユーザーは読み出さない
    ->whereDoesntHave('social', function ($q){
        $q->where('ng',1);
    })
    ->select('id','name')
    ->first();//最初の

//次ページある
if (!empty($next->id)) {
    pd($next->id);
    pd($next->name);
} else {

    pd("次ページはありません");

}



$prev = Article::query()//単数形 User
    ->where('id','<',$request->id)
    ->orderBy('id','DESC')
    //NGユーザーは読み出さない
    ->whereDoesntHave('social', function ($q){
        $q->where('ng',1);
    })
    ->select('id','name')
    ->first();//最初の

//次ページある
if (!empty($prev->id)) {
    pd($prev->id);
    pd($prev->name);
} else {

    pd("前ページはありません");

}



こんな感じ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Flexboxでカルーセルスライダーをつくる

カルーセルスライダーとは、たいていのスライダーは1つの画像などを表示するのに対し、複数のものを表示し、左右の矢印を押下すると、ページャーのようにみえていなかった次の組を表示するもののことを指しています。

できあがったもの

イメージとしてはこんな感じのもの

0bf58c02-2815-4805-8b6a-60056d0b4dcf.png

コード

<div class="carousel">
  <div class="carousel_prev">&lt;</div>
  <div class="carousel_list_outer">
    <ul class="carousel_list">
      <li class="carousel_item">1</li>
      <li class="carousel_item">2</li>
      <li class="carousel_item">3</li>
      <li class="carousel_item">4</li>
      <li class="carousel_item">5</li>
      <li class="carousel_item">6</li>
      <li class="carousel_item">7</li>
      <li class="carousel_item">8</li>
    </ul>
  </div>
  <div class="carousel_next">&gt;</div>
</div>
.carousel{
  display: flex;
  align-items: center;
  width: 100%;
  .carousel_prev,
  .carousel_next{
    padding: 10px;
    cursor: pointer;
    &.hidden{
      visibility: hidden;
    }
  }
  .carousel_list_outer{
    flex: 1;
    overflow: hidden;
  }
  .carousel_list{
    display: flex;
    align-items: center;
    transition: 0.3s;
    .carousel_item{
      flex: 0 0 25%;
      display: flex;
      align-items: center;
      justify-content: center;
      width: 25%;
      height: 100px;
      background-color: #ccc;
      border: 1px solid #fff;
    }
  }
}

簡単に解説

まずは、左右の矢印とカルーセルの表示エリアをFlexboxで横並びにし、カルーセルはflex: 1;で幅いっぱいにする
はみ出た部分を表示したくないのでoverflow: hidden;をつける
もし、左右の矢印ではなく、横スクロールであれば、overflow-x: auto;とすればOK

カルーセル自体もFlexboxで横並びにする
今回は、決まった数を表示し、左右矢印でその数分移動させたかったので、flex: 0 0 25%;として、4つ表示するようにした

あとは、左右の矢印を押下したときに、何かしらの方法で、.carousel_listにクラスをつけるなどし、transform: 'translate(-100%, 0)';などとします
ここの数値のコントロールで、1つずつスクロールさせることもできます

また、Flexboxのorderでも制御することができると思います。

Vue.jsで、左右の矢印を制御する

CSS(Sass)は同じなので割愛します
(最後まできたら、最初に戻らず、矢印を非表示にするタイプです)

<template>
  <div class="carousel">
    <div @click="carouselPrev" class="carousel_prev" :class="{hidden:(list.length<=4) || (carouselIndex===0)}">&lt;</div>
    <div class="carousel_list_outer">
      <ul class="carousel_list" :style="{transform: 'translate(-'+carouselIndex+'00%, 0)'}">
        <template v-for="(item, index) in list">
         <li class="carousel_item">{{item}}</li>
        </template>
      </ul>
    </div>
    <div @click="carouselNext" class="carousel_next" :class="{hidden:(list.length<=4) || (carouselIndex===carouselIndexMax)}">&gt;</div>
  </div>
</template>

<script>
export default {
  layout: "white",
  data(){
    return{
      list: [1, 2, 3, 4, 5, 6, 7, 8],
      carouselIndex: 0,
    }
  },
  computed: {
    carouselIndexMax() {
      return parseInt(this.list.length/4)-1;
    }
  },
  methods: {
    carouselPrev(){
      this.carouselIndex--;
    },
    carouselNext(){
      this.carouselIndex++;
    }
  }
}
</script>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】v-on完全マスター。イベントハンドラの使い方と実例

【Vue.js】v-on完全マスター。イベントハンドラの使い方と実例

v-onディレクティブを使ったイベントオブジェクトの様々な記述方法について。

目次

  1. インラインメソッドハンドラ
  2. メソッドイベントハンドラ
  3. イベントハンドラの引数受け渡し
  4. イベントオブジェクト
  5. イベントオブジェクトとは?
    1. コンソールに出力する方法
    2. html上に出力する方法
  6. イベントオブジェクト(引数ありの場合)
  7. イベント修飾子
    1. 主なイベント修飾子
    2. .once
    3. .prevent
  8. キー修飾子
    1. キー修飾子の一覧
    2. キー修飾子の実例
  9. システム修飾子
    1. システム修飾子の一覧
    2. システム修飾子の実例
  10. マウスボタンの修飾子
  11. v-on:の省略記法
  12. 確認用ソースコード

インラインメソッドハンドラ

v-onを記述するときに、インライン上にJavaScript式で記述することができる。

簡単な式の場合のみ利用可能。複雑な場合は後述のmethodsオプションを使ったメソッドイベントハンドラを使う。

v-on:イベント"javascript式"

実例

ボタンをクリックする毎に表示数値に1を加算する。
++を使用

v-on:click="counter++"

.js
var app = new Vue({
    el:'#app',
    data:{
        counter:0
    }
})
.html
<body>
    <div id="app">
        <div>
            ■インラインイベントハンドラ

            <p> 数値:{{ counter }} </p>
            <button v-on:click="counter++">+1</button>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


メソッドイベントハンドラ

methodsオプションを使ってイベントを記述する。(.js側の記述)

methods:{イベントハンドラ名: function(){処理}}

.js
var app = new Vue({
    el:'#app',
    data:{
        counter:0
    },    
    //メソッドイベントハンドラ
    methods:{
        clickHandler: function(){
            this.counter++
        }
    }
})
.html
<body>
    <div id="app">
        <div>
            ■メソッドイベントハンドラ

            <p> 数値:{{ counter }} </p>
            <button v-on:click="clickHandler">+1</button>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


イベントハンドラの引数受け渡し

引数に値を入れることで、その値を引き渡すことができる。

v-on:click="イベントハンドラ名(引数)"

引数で渡した文字列を画面上に表示する

onクリックイベントで、
・引数で「受け渡しに成功!」という文字列を渡す。
・プロパティに代入し、マスタッシュ展開で画面上に表示する。

.js
var app = new Vue({
    el:'#app',
    data:{
        //引数の受け渡し
        message: ''
    },
    methods:{
        //引数の受け渡し
        argument: function(arg1){
            this.message = arg1
        }
    }
})
.html
<body>
    <div id="app">
        <div>
            ■イベントハンドラの引数受け渡し

            <p>引数:{{ message }}</p>
            <button v-on:click="argument('受け渡しに成功!')">クリック</button>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


イベントオブジェクト

イベントオブジェクトとは?

イベントオブジェクトとは、イベントが発生した時の要素やイベントの種類、発生時間などの情報が入ったオブジェクト。

イベントで設定した関数の第1引数がイベントオブジェクトになる。(任意の文字列)

event, ev, eなどで表示されることが多い。

<注意点>
イベントハンドラで引数を渡す場合は、第一引数に$eventを追加。(実例は後述)

イベントオブジェクトの参照

取得したいプロパティ名を付与することで取得できる。
イベントオブジェクト.プロパティ.プロパティ...

コンソールに出力する方法

console.log(イベントオブジェクト)とすることで、console上に表示可能。

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //インラインイベントハンドラ(javascript式)
        counter:0,

        //イベントオブジェクト
        eventObject: ''

    },
    //メソッドイベントハンドラ
    methods:{
        clickHandler: function(event){
            this.counter++


            //イベントオブジェクト          
            this.eventObject = event
            console.log(event)
            console.log(event.target)
            console.log(event.target.tagName)
            console.log(event.target.innerHTML)
            console.log(event.target.type)
            console.log(event.screenX)
            console.log(event.screenY)
        }
    }
})

html上に出力する方法

マスタッシュ展開で表示可能。
{{ イベントオブジェクト.プロパティ }}

.html
<body>
    <div id="app">

        <div>
            ■イベントオブジェクト
            <p>{{eventObject}}</p>
            <p>タグ名:{{eventObject.target}}</p>
            <p>x座標:{{eventObject.screenX}}</p>
            <p>y座標:{{eventObject.screenY}}</p>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>
.js
var app = new Vue({
    el:'#app',
    data:{
        //インラインイベントハンドラ(javascript式)
        counter:0,

        //イベントオブジェクトを格納するプロパティ
        eventObject: ''

    },
    //メソッドイベントハンドラ
    methods:{
        clickHandler: function(event){
            this.counter++

            //イベントオブジェクトの代入          
            this.eventObject = event
        }
    }
})


イベントオブジェクト(引数ありの場合)

引数がある場合は、第1引数に「$event」を記載することで、イベントオブジェクトの受け渡しができる。

▼HTMLファイル
v-on:click="eveArg($event, 受け渡す引数)"

▼jsファイル
methods:{イベントハンドラ名: function($event, 変数){処理}}

.html
<body>
    <div id="app">

        <div>
            ■イベントハンドラの引数とイベントオブジェクトの受け渡し
            <p>引数:{{ message }}</p>
            <p>イベントオブジェクト: {{eventObject}}</p>
            <button v-on:click="eveArg($event, '受け渡しに成功!')">クリック</button>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>
.js
var app = new Vue({
    el:'#app',
    data:{
        //インラインイベントハンドラ(javascript式)
        counter:0,

        //イベントオブジェクトを格納するプロパティ
        eventObject: ''

    },
    //メソッドイベントハンドラ
    methods:{
        //イベントオブジェクトと引数の受け渡し
        eveArg: function($event, arg1){
            this.message = arg1
            this.eventObject = $event
        }
        }
    }
})


イベント修飾子

v-onイベントを修飾するもので、DOMイベントの振る舞いを変更することができる。

v-on:click.イベント修飾子 = "イベントハンドラ名(引数)"

<メリット>
・methodsオプション側ではなく、htmlで処理を変更できる。
・設定したり、外したりが簡単。

下記記事がわかりやすい。
https://qiita.com/Yorinton/items/f7eb54f05609750da7f5

主なイベント修飾子

イベント修飾子 概要
.stop 設置したハンドラは実施するが、親要素のハンドラは実行しない
.prevent ハンドラを実施するが、次の動作をしない(リンク先に飛ぶなど)
.capture キャプチャモードで実行。最上位の親要素から順にハンドラを適用していく
.self イベント発生元が要素実親の場合にだけ実行
.once イベントハンドラを1回だけ実行
.left マウスの左クリック時のみハンドラを呼び出す
.passive passiveモードを有効化

.once

イベントハンドラを1回のみ実行する。

v-on:イベント名.once="イベントハンドラ名(引数)"

ボタンクリックで現在時刻を表示するプログラム

現在時刻は new Date()で作成できる。
.toLocaleString()で修飾することで、秒以下の情報をカット。

.js
var app = new Vue({
    el:'#app',
    data:{
        //現在時刻の格納
        nowTime: ''
    },
    methods:{
        //イベント修飾子 .once
        currentTime: function(){
            this.nowTime = new Date().toLocaleString()
        }
        }
    }
})
.html
<body>
    <div id="app">
            ■イベント修飾子<br>
            .once
            <p>現在時刻:{{ nowTime }}</p>

            <button v-on:click="currentTime">通常</button>
            <button v-on:click.once="currentTime">.once</button>

        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>

.prevent

イベントハンドラのみ実行し、要素のアクションを実行しない。

v-on:イベント名.prevent="イベントハンドラ名(引数)"

現在時刻を表示するが、リンクは非活性にするプログラム

現在時刻は new Date()で作成できる。
.toLocaleString()で修飾することで、秒以下の情報をカット。

.js
var app = new Vue({
    el:'#app',
    data:{
        //現在時刻の格納
        nowTime: ''
    },
    methods:{
        //イベント修飾子 .once
        currentTime: function(){
            this.nowTime = new Date().toLocaleString()
        }
        }
    }
})
.html
<body>
    <div id="app">
            ■イベント修飾子<br> 
            .prevent

            <p>現在時刻:{{ nowTime }}</p>
            <a href="https://jp.vuejs.org/index.html" v-on:click="currentTime">現在時刻更新しvue公式ページトップにリンク</a><br>
            <a href="https://jp.vuejs.org/index.html" v-on:click.prevent="currentTime">prevent</a>

        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


キー修飾子

特定のキーコードが押された場合に、イベントハンドラを呼び出す。

keyupイベントと合わせて使用されることが多い。もちろんclickイベントでも使える。

・keyup:キーから指が離れたタイミングでイベントを実施

v-on:keyup.キー修飾子
v-on:keyup.キー修飾子1.キー修飾子2.キー修飾子3...
 ┗ キー修飾子はキー番号で指定することも可能
 ┗ つなげることで複数設定可能
  例: .27 = .esc

キー修飾子の一覧

  1. enter
  2. tab
  3. delete (“Backspace” もキャプチャ)
  4. esc
  5. space
  6. up
  7. down
  8. left
  9. right

キー番号を指定することでアルファベットを指定することも可能。
例えば、a:「.65」, c:「.67」

キーコード一覧

公式ページ

キー修飾子の実例

escape, space, deleteキーのいずれかをクリックすると、入力したテキストを削除するプログラム。

・inputタグにv-onを設定し、イベントハンドラを設定。
・v-modelで入力値とdataオブジェクトのプロパティを連動させる。

v-on:keyup.esc.space.delete="clearHandler('clicked escape kye!')"

.js
var app = new Vue({
    el:'#app',
    data:{
        //引数の受け渡し
        message: '',
        message1: '',
    },
    methods:{
        //キー修飾子
        clearHandler: function(text){
            this.message = ""
            this.message1 = text
        }
    }
})
.html
<body>
    <div id="app">
        <div>
            ■キー修飾子<br>
            esc, space, deleteキーをクリックすると、入力したテキストを削除します。

            <input type="text" v-on:keyup.esc.space.delete="clearHandler('clicked escape kye!')" v-model="message">
            <p>{{message1}}</p>

        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


システム修飾子

ctrlキーなどシステム系と合わせてイベントハンドラを呼び出す。

公式ページ

システム修飾子の一覧

  1. .ctrl
  2. .alt ※windowsのみ
  3. .shift
  4. .meta

.meta修飾子とは?
OSにより異なる。
・Mac: コマンドキー(⌘)
・Windows: ウィンドウキー(⊞)

システム修飾子の実例

shiftキーを押しながらクリックするとアラートを表示するプログラム

image.png
.js
var app = new Vue({
    el:'#app',
    methods:{
        showAlert: function(){
            alert('shiftキーを押しながらクリックしました')
        }
    }
})
.html
<body>
    <div id="app">
        <div>
            ■システム修飾子<br>
                        <p v-on:click.shift="showAlert">
            ▶︎shift押しながらこのテキストをクリック
            </p>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>

マウスボタンの修飾子

マウスボタンのクリックによってもイベントハンドラを操作できる。

  1. .left
  2. .right
  3. .middle

.leftと.rightはキー修飾子と共通。キーボードでもマウスでもどちらでも反応数する。

公式ページ


v-on:の省略記法

v-on:は使用頻度が高いため省略記法「@」が用意されている。
5文字を1文字で記述できる。

以下2つは同じ処理になる。
@click="イベントハンドラ名"
v-on:click="イベントハンドラ名"

省略記法の実例

@click.イベント修飾子="イベントハンドラ"

省略記法の実例

「a」を押しながらクリックした場合に、アラートを表示する。

.js
var app = new Vue({
    el:'#app',
    methods:{
        //省略記法
        showAlert2: function(){
            alert('aを押しながらクリックしました')
        }
    }
})
.html
<body>
    <div id="app">
        <div>
            ■省略記法<br>

            <p @click.65="showAlert2">
                ▶︎aを押しながらこのテキストをクリック
            </p>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


確認用ソースコード

▼ブラウザの表示

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //インラインイベントハンドラ(javascript式)
        counter:0,

        //イベントオブジェクト
        eventObject: '',

        //引数の受け渡し
        message: '',
        message1: '',
        //現在時刻の格納
        nowTime: ''
    },
    //メソッドイベントハンドラ
    methods:{
        clickHandler: function(event){
            this.counter++

            //イベントオブジェクト
            this.eventObject = event
            console.log(event)
            console.log(event.target)
            console.log(event.target.tagName)
            console.log(event.target.innerHTML)
            console.log(event.target.type)
            console.log(event.screenX)
            console.log(event.screenY)
        },

        //引数の受け渡し
        argument: function(arg1){
            this.message = arg1
        },

        //イベントオブジェクトと引数の受け渡し
        eveArg: function($event, arg1){
            this.message = arg1
            this.eventObject = $event
        },

        //イベント修飾子
        currentTime: function(){
            this.nowTime = new Date().toLocaleString()
        },

        //キー修飾子
        clearHandler: function(text){
            this.message = ""
            this.message1 = text
        },
        //システム修飾子
        showAlert: function(){
            alert('shiftキーを押しながらクリックしました')
        },

        //省略記法
        showAlert2: function(){
            alert('aを押しながらクリックしました')
        }
    }
})
.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>handler</title>
</head>
<body>
    <div id="app">
        <div>
            ■インラインイベントハンドラ
            <p> 数値:{{ counter }} </p>
            <button v-on:click="counter++">+1</button>
        </div>

        <hr>

        <div>
            ■メソッドイベントハンドラ
            <p> 数値:{{ counter }} </p>
            <button v-on:click="clickHandler">+1</button>
        </div>

        <hr>

        <div>
            ■イベントオブジェクト
            <p>{{eventObject}}</p>
            <p>タグ名:{{eventObject.target}}</p>
            <p>x座標:{{eventObject.screenX}}</p>
            <p>y座標:{{eventObject.screenY}}</p>
        </div>

        <hr>

        <div>
            ■イベントハンドラの引数受け渡し
            <p>引数:{{ message }}</p>
            <button v-on:click="argument('受け渡しに成功!')">クリック</button>
        </div>

        <hr>

        <div>
            ■イベントハンドラの引数とイベントオブジェクトの受け渡し
            <p>引数:{{ message }}</p>
            <p>イベントオブジェクト: {{eventObject}}</p>
            <button v-on:click="eveArg($event, '受け渡しに成功!')">クリック</button>
        </div>

        <hr>

        <div>
            ■イベント修飾子<br>
            .once
            <p>現在時刻:{{ nowTime }}</p>
            <button v-on:click="currentTime">通常</button>
            <button v-on:click.once="currentTime">.once</button>

            <br><br>
            .prevent
            <p>現在時刻:{{ nowTime }}</p>
            <a href="https://jp.vuejs.org/index.html" v-on:click="currentTime">現在時刻更新しvue公式ページトップにリンク</a><br>
            <a href="https://jp.vuejs.org/index.html" v-on:click.prevent="currentTime">prevent</a>

        </div>

        <hr>

        <div>
            ■キー修飾子<br>
            esc, space, deleteキーをクリックすると、入力したテキストを削除します。
            <input type="text" v-on:keyup.esc.space.delete="clearHandler('cliked clear key!')" v-model="message">
            <p>{{message1}}</p>

            <br>


            ■システム修飾子<br>
            <p v-on:click.shift="showAlert">
                ▶︎shift押しながらこのテキストをクリック
            </p>

        </div>

        <hr>

        <div>
            ■省略記法<br>
            <p @click.65="showAlert2">
                ▶︎aを押しながらこのテキストをクリック
            </p>

        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>
</html>



以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】v-onを完全マスター。イベントハンドラの使い方と実例

【Vue.js】イベントハンドラ v-onの使い方と実例

v-onディレクティブを使ったイベントオブジェクトの様々な記述方法について。

目次

  1. インラインメソッドハンドラ
  2. メソッドイベントハンドラ
  3. イベントハンドラの引数受け渡し
  4. イベントオブジェクト
  5. イベントオブジェクトとは?
    1. コンソールに出力する方法
    2. html上に出力する方法
  6. イベントオブジェクト(引数ありの場合)
  7. イベント修飾子
    1. 主なイベント修飾子
    2. .once
    3. .prevent
  8. キー修飾子
    1. キー修飾子の一覧
    2. キー修飾子の実例
  9. システム修飾子
    1. システム修飾子の一覧
    2. システム修飾子の実例
  10. マウスボタンの修飾子
  11. v-on:の省略記法
  12. 確認用ソースコード

インラインメソッドハンドラ

v-onを記述するときに、インライン上にJavaScript式で記述することができる。

簡単な式の場合のみ利用可能。複雑な場合は後述のmethodsオプションを使ったメソッドイベントハンドラを使う。

v-on:イベント"javascript式"

実例

ボタンをクリックする毎に表示数値に1を加算する。
++を使用

v-on:click="counter++"

.js
var app = new Vue({
    el:'#app',
    data:{
        counter:0
    }
})
.html
<body>
    <div id="app">
        <div>
            ■インラインイベントハンドラ

            <p> 数値:{{ counter }} </p>
            <button v-on:click="counter++">+1</button>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


メソッドイベントハンドラ

methodsオプションを使ってイベントを記述する。(.js側の記述)

methods:{イベントハンドラ名: function(){処理}}

.js
var app = new Vue({
    el:'#app',
    data:{
        counter:0
    },    
    //メソッドイベントハンドラ
    methods:{
        clickHandler: function(){
            this.counter++
        }
    }
})
.html
<body>
    <div id="app">
        <div>
            ■メソッドイベントハンドラ

            <p> 数値:{{ counter }} </p>
            <button v-on:click="clickHandler">+1</button>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


イベントハンドラの引数受け渡し

引数に値を入れることで、その値を引き渡すことができる。

v-on:click="イベントハンドラ名(引数)"

引数で渡した文字列を画面上に表示する

onクリックイベントで、
・引数で「受け渡しに成功!」という文字列を渡す。
・プロパティに代入し、マスタッシュ展開で画面上に表示する。

.js
var app = new Vue({
    el:'#app',
    data:{
        //引数の受け渡し
        message: ''
    },
    methods:{
        //引数の受け渡し
        argument: function(arg1){
            this.message = arg1
        }
    }
})
.html
<body>
    <div id="app">
        <div>
            ■イベントハンドラの引数受け渡し

            <p>引数:{{ message }}</p>
            <button v-on:click="argument('受け渡しに成功!')">クリック</button>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


イベントオブジェクト

イベントオブジェクトとは?

イベントオブジェクトとは、イベントが発生した時の要素やイベントの種類、発生時間などの情報が入ったオブジェクト。

イベントで設定した関数の第1引数がイベントオブジェクトになる。(任意の文字列)

event, ev, eなどで表示されることが多い。

<注意点>
イベントハンドラで引数を渡す場合は、第一引数に$eventを追加。(実例は後述)

イベントオブジェクトの参照

取得したいプロパティ名を付与することで取得できる。
イベントオブジェクト.プロパティ.プロパティ...

コンソールに出力する方法

console.log(イベントオブジェクト)とすることで、console上に表示可能。

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //インラインイベントハンドラ(javascript式)
        counter:0,

        //イベントオブジェクト
        eventObject: ''

    },
    //メソッドイベントハンドラ
    methods:{
        clickHandler: function(event){
            this.counter++


            //イベントオブジェクト          
            this.eventObject = event
            console.log(event)
            console.log(event.target)
            console.log(event.target.tagName)
            console.log(event.target.innerHTML)
            console.log(event.target.type)
            console.log(event.screenX)
            console.log(event.screenY)
        }
    }
})

html上に出力する方法

マスタッシュ展開で表示可能。
{{ イベントオブジェクト.プロパティ }}

.html
<body>
    <div id="app">

        <div>
            ■イベントオブジェクト
            <p>{{eventObject}}</p>
            <p>タグ名:{{eventObject.target}}</p>
            <p>x座標:{{eventObject.screenX}}</p>
            <p>y座標:{{eventObject.screenY}}</p>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>
.js
var app = new Vue({
    el:'#app',
    data:{
        //インラインイベントハンドラ(javascript式)
        counter:0,

        //イベントオブジェクトを格納するプロパティ
        eventObject: ''

    },
    //メソッドイベントハンドラ
    methods:{
        clickHandler: function(event){
            this.counter++

            //イベントオブジェクトの代入          
            this.eventObject = event
        }
    }
})


イベントオブジェクト(引数ありの場合)

引数がある場合は、第1引数に「$event」を記載することで、イベントオブジェクトの受け渡しができる。

▼HTMLファイル
v-on:click="eveArg($event, 受け渡す引数)"

▼jsファイル
methods:{イベントハンドラ名: function($event, 変数){処理}}

.html
<body>
    <div id="app">

        <div>
            ■イベントハンドラの引数とイベントオブジェクトの受け渡し
            <p>引数:{{ message }}</p>
            <p>イベントオブジェクト: {{eventObject}}</p>
            <button v-on:click="eveArg($event, '受け渡しに成功!')">クリック</button>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>
.js
var app = new Vue({
    el:'#app',
    data:{
        //インラインイベントハンドラ(javascript式)
        counter:0,

        //イベントオブジェクトを格納するプロパティ
        eventObject: ''

    },
    //メソッドイベントハンドラ
    methods:{
        //イベントオブジェクトと引数の受け渡し
        eveArg: function($event, arg1){
            this.message = arg1
            this.eventObject = $event
        }
        }
    }
})


イベント修飾子

v-onイベントを修飾するもので、DOMイベントの振る舞いを変更することができる。

v-on:click.イベント修飾子 = "イベントハンドラ名(引数)"

<メリット>
・methodsオプション側ではなく、htmlで処理を変更できる。
・設定したり、外したりが簡単。

下記記事がわかりやすい。
https://qiita.com/Yorinton/items/f7eb54f05609750da7f5

主なイベント修飾子

イベント修飾子 概要
.stop 設置したハンドラは実施するが、親要素のハンドラは実行しない
.prevent ハンドラを実施するが、次の動作をしない(リンク先に飛ぶなど)
.capture キャプチャモードで実行。最上位の親要素から順にハンドラを適用していく
.self イベント発生元が要素実親の場合にだけ実行
.once イベントハンドラを1回だけ実行
.left マウスの左クリック時のみハンドラを呼び出す
.passive passiveモードを有効化

.once

イベントハンドラを1回のみ実行する。

v-on:イベント名.once="イベントハンドラ名(引数)"

ボタンクリックで現在時刻を表示するプログラム

現在時刻は new Date()で作成できる。
.toLocaleString()で修飾することで、秒以下の情報をカット。

.js
var app = new Vue({
    el:'#app',
    data:{
        //現在時刻の格納
        nowTime: ''
    },
    methods:{
        //イベント修飾子 .once
        currentTime: function(){
            this.nowTime = new Date().toLocaleString()
        }
        }
    }
})
.html
<body>
    <div id="app">
            ■イベント修飾子<br>
            .once
            <p>現在時刻:{{ nowTime }}</p>

            <button v-on:click="currentTime">通常</button>
            <button v-on:click.once="currentTime">.once</button>

        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>

.prevent

イベントハンドラのみ実行し、要素のアクションを実行しない。

v-on:イベント名.prevent="イベントハンドラ名(引数)"

現在時刻を表示するが、リンクは非活性にするプログラム

現在時刻は new Date()で作成できる。
.toLocaleString()で修飾することで、秒以下の情報をカット。

.js
var app = new Vue({
    el:'#app',
    data:{
        //現在時刻の格納
        nowTime: ''
    },
    methods:{
        //イベント修飾子 .once
        currentTime: function(){
            this.nowTime = new Date().toLocaleString()
        }
        }
    }
})
.html
<body>
    <div id="app">
            ■イベント修飾子<br> 
            .prevent

            <p>現在時刻:{{ nowTime }}</p>
            <a href="https://jp.vuejs.org/index.html" v-on:click="currentTime">現在時刻更新しvue公式ページトップにリンク</a><br>
            <a href="https://jp.vuejs.org/index.html" v-on:click.prevent="currentTime">prevent</a>

        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


キー修飾子

特定のキーコードが押された場合に、イベントハンドラを呼び出す。

keyupイベントと合わせて使用されることが多い。もちろんclickイベントでも使える。

・keyup:キーから指が離れたタイミングでイベントを実施

v-on:keyup.キー修飾子
v-on:keyup.キー修飾子1.キー修飾子2.キー修飾子3...
 ┗ キー修飾子はキー番号で指定することも可能
 ┗ つなげることで複数設定可能
  例: .27 = .esc

キー修飾子の一覧

  1. enter
  2. tab
  3. delete (“Backspace” もキャプチャ)
  4. esc
  5. space
  6. up
  7. down
  8. left
  9. right

キー番号を指定することでアルファベットを指定することも可能。
例えば、a:「.65」, c:「.67」

キーコード一覧

公式ページ

キー修飾子の実例

escape, space, deleteキーのいずれかをクリックすると、入力したテキストを削除するプログラム。

・inputタグにv-onを設定し、イベントハンドラを設定。
・v-modelで入力値とdataオブジェクトのプロパティを連動させる。

v-on:keyup.esc.space.delete="clearHandler('clicked escape kye!')"

.js
var app = new Vue({
    el:'#app',
    data:{
        //引数の受け渡し
        message: '',
        message1: '',
    },
    methods:{
        //キー修飾子
        clearHandler: function(text){
            this.message = ""
            this.message1 = text
        }
    }
})
.html
<body>
    <div id="app">
        <div>
            ■キー修飾子<br>
            esc, space, deleteキーをクリックすると、入力したテキストを削除します。

            <input type="text" v-on:keyup.esc.space.delete="clearHandler('clicked escape kye!')" v-model="message">
            <p>{{message1}}</p>

        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


システム修飾子

ctrlキーなどシステム系と合わせてイベントハンドラを呼び出す。

公式ページ

システム修飾子の一覧

  1. .ctrl
  2. .alt ※windowsのみ
  3. .shift
  4. .meta

.meta修飾子とは?
OSにより異なる。
・Mac: コマンドキー(⌘)
・Windows: ウィンドウキー(⊞)

システム修飾子の実例

shiftキーを押しながらクリックするとアラートを表示するプログラム

image.png
.js
var app = new Vue({
    el:'#app',
    methods:{
        showAlert: function(){
            alert('shiftキーを押しながらクリックしました')
        }
    }
})
.html
<body>
    <div id="app">
        <div>
            ■システム修飾子<br>
                        <p v-on:click.shift="showAlert">
            ▶︎shift押しながらこのテキストをクリック
            </p>
        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>

マウスボタンの修飾子

マウスボタンのクリックによってもイベントハンドラを操作できる。

  1. .left
  2. .right
  3. .middle

.leftと.rightはキー修飾子と共通。キーボードでもマウスでもどちらでも反応数する。

公式ページ


v-on:の省略記法

v-on:は使用頻度が高いため省略記法「@」が用意されている。
5文字を1文字で記述できる。

以下2つは同じ処理になる。
@click="イベントハンドラ名"
v-on:click="イベントハンドラ名"

省略記法の実例

@click.イベント修飾子="イベントハンドラ"

省略記法の実例

「a」を押しながらクリックした場合に、アラートを表示する。

.js
var app = new Vue({
    el:'#app',
    methods:{
        //省略記法
        showAlert2: function(){
            alert('aを押しながらクリックしました')
        }
    }
})
.html
<body>
    <div id="app">
        <div>
            ■省略記法<br>

            <p @click.65="showAlert2">
                ▶︎aを押しながらこのテキストをクリック
            </p>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>


確認用ソースコード

▼ブラウザの表示

image.png
.js
var app = new Vue({
    el:'#app',
    data:{
        //インラインイベントハンドラ(javascript式)
        counter:0,

        //イベントオブジェクト
        eventObject: '',

        //引数の受け渡し
        message: '',
        message1: '',
        //現在時刻の格納
        nowTime: ''
    },
    //メソッドイベントハンドラ
    methods:{
        clickHandler: function(event){
            this.counter++

            //イベントオブジェクト
            this.eventObject = event
            console.log(event)
            console.log(event.target)
            console.log(event.target.tagName)
            console.log(event.target.innerHTML)
            console.log(event.target.type)
            console.log(event.screenX)
            console.log(event.screenY)
        },

        //引数の受け渡し
        argument: function(arg1){
            this.message = arg1
        },

        //イベントオブジェクトと引数の受け渡し
        eveArg: function($event, arg1){
            this.message = arg1
            this.eventObject = $event
        },

        //イベント修飾子
        currentTime: function(){
            this.nowTime = new Date().toLocaleString()
        },

        //キー修飾子
        clearHandler: function(text){
            this.message = ""
            this.message1 = text
        },
        //システム修飾子
        showAlert: function(){
            alert('shiftキーを押しながらクリックしました')
        },

        //省略記法
        showAlert2: function(){
            alert('aを押しながらクリックしました')
        }
    }
})
.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>handler</title>
</head>
<body>
    <div id="app">
        <div>
            ■インラインイベントハンドラ
            <p> 数値:{{ counter }} </p>
            <button v-on:click="counter++">+1</button>
        </div>

        <hr>

        <div>
            ■メソッドイベントハンドラ
            <p> 数値:{{ counter }} </p>
            <button v-on:click="clickHandler">+1</button>
        </div>

        <hr>

        <div>
            ■イベントオブジェクト
            <p>{{eventObject}}</p>
            <p>タグ名:{{eventObject.target}}</p>
            <p>x座標:{{eventObject.screenX}}</p>
            <p>y座標:{{eventObject.screenY}}</p>
        </div>

        <hr>

        <div>
            ■イベントハンドラの引数受け渡し
            <p>引数:{{ message }}</p>
            <button v-on:click="argument('受け渡しに成功!')">クリック</button>
        </div>

        <hr>

        <div>
            ■イベントハンドラの引数とイベントオブジェクトの受け渡し
            <p>引数:{{ message }}</p>
            <p>イベントオブジェクト: {{eventObject}}</p>
            <button v-on:click="eveArg($event, '受け渡しに成功!')">クリック</button>
        </div>

        <hr>

        <div>
            ■イベント修飾子<br>
            .once
            <p>現在時刻:{{ nowTime }}</p>
            <button v-on:click="currentTime">通常</button>
            <button v-on:click.once="currentTime">.once</button>

            <br><br>
            .prevent
            <p>現在時刻:{{ nowTime }}</p>
            <a href="https://jp.vuejs.org/index.html" v-on:click="currentTime">現在時刻更新しvue公式ページトップにリンク</a><br>
            <a href="https://jp.vuejs.org/index.html" v-on:click.prevent="currentTime">prevent</a>

        </div>

        <hr>

        <div>
            ■キー修飾子<br>
            esc, space, deleteキーをクリックすると、入力したテキストを削除します。
            <input type="text" v-on:keyup.esc.space.delete="clearHandler('cliked clear key!')" v-model="message">
            <p>{{message1}}</p>

            <br>


            ■システム修飾子<br>
            <p v-on:click.shift="showAlert">
                ▶︎shift押しながらこのテキストをクリック
            </p>

        </div>

        <hr>

        <div>
            ■省略記法<br>
            <p @click.65="showAlert2">
                ▶︎aを押しながらこのテキストをクリック
            </p>

        </div>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="script.js"></script>
</body>
</html>



以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsを1から学んでみた〜ミックスイン〜

Vue.js を1から学んでみた。にて書いてきましたが、
長くなり編集しにくくなってきたので、分割しました(こんなやりかたしないのかな?知りたい。)

10-1. 概要

export default{に定義されている、data、componentsなどは総じてオプションと呼ばれる。

sample.vue
<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  // dataはオプションの1つ
  data: function() {
    return {
      name: "次郎"
    }
  },
  // componentsはオプションの1つ
  components: {
    HelloWorld
  }
}
</script>

これらのオプションをJavaScriptファイルにまとめて、複数のvueファイルで使い回す仕組みをミックスインという。

10-2. 基本的な使い方

新しいJavaScriptファイルを作成し、共有したいオプションを実装する。

(特に何もしない)main.js
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
capitalizeMixIn.js
// 実際のミックスインの実装
export const capitalizeMixIn = {
  props: {
    message: {
      type: String
    },
  },
  data: function() {
    return {
      msg: this.message
    }
  },
  filters: {
    capitalize: function (value) {
      if (!value) return ''
      value = value.toString()
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
  }
}
(特に何もしない)App.vue
<template>
  <div>
    <Job message="system engineer"></Job>
    <Job message="monotas"></Job>
  </div>
</template>

<script>
import Job from "./components/Job.vue";

export default {
  components: {
    Job: Job
  }
}
</script>
Job.vue
<template>
  <div>
    {{ msg | capitalize }}
  </div>
</template>

<script>
// mixinの取り込み
// '@'はsrcをルートとして定義できる便利なもの
import { capitalizeMixIn } from  "@/capitalizeMixIn"

export default {
  // ミックスインの設定
  mixins: [capitalizeMixIn]
}
</script>

結果
image.png

オプションが被った場合

ミックスインのオプションと、ミックインを指定しているコンポーネントで、オプションが被った場合は、コンポーネントが優先される
ただし、ライフサイクルメソッドについては、ミックスインもコンポーネントも両方とも実行される。ミックスイン→コンポーネントの順番で実行される。

Job.vue
<template>
  <div>
    {{ msg | capitalize }}
  </div>
</template>

<script>
import { capitalizeMixIn } from "@/capitalizeMixIn"

export default {
  mixins: [capitalizeMixIn],
  // ミックスインと同じキーのdataオプションを用意
  data: function() {
    return {
      msg: "component message"
    }
  },
}
</script>

結果:コンポーネントが優先される

image.png

10-3. グローバル登録について

コンポーネントやカスタムディレクティブのように、グローバル登録はあるっちゃあ、ある笑
ただ、、、仮にライフサイクルメソッドを実装してしまうと全てのコンポーネントが展開された時に実行されてしまい危険w
なので、載せないでおく。
実現したい内容が他の方法ではどうしてもできない場合に調べようと思うので割愛。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsを1から学んでみた〜フィルター〜

Vue.js を1から学んでみた。にて書いてきましたが、
長くなり編集しにくくなってきたので、分割しました(こんなやりかたしないのかな?知りたい。)

9-1. 概要

Utilityクラスの様なもの。
例えば、引数の値を全て大文字にしたいような機能が欲しい場合、定義して使うことができる。

9-2. 基本

利用できるのは、mustache展開({{}} の展開)と v-bindの2つ。

単一指定

対象のVueインスタンスプロパティに対して| (パイプ)を設定する。

sample.html
<!-- mustaches -->
{{ message | capitalize }}

<!-- v-bind -->
<div v-bind:id="rawId | formatId"></div>

複数指定

複数指定する場合は、以下の様に|でつなげる。

sample.html
<!-- mustaches -->
{{ message | capitalize | subString }}

ローカル登録

filtersで登録する。

App.vue
<template>
  <div>
    <Job message="system engineer"></Job>
    <Job message="hogehoge"></Job>
  </div>
</template>

<script>
import Job from "./components/Job.vue";

export default {
  components: {
    Job: Job
  }
}
</script>
Job.vue
<template>
  <div>
    {{ msg | capitalize }}
  </div>
</template>

<script>
export default {
  props: {
    message: {
      type: String
    },
  },
  data: function() {
    return {
      msg: this.message
    }
  },
  // ローカル登録
  filters: {
    capitalize: function (value) {
      if (!value) return ''
      value = value.toString()
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
  }
}
</script>

結果:先頭の文字列だけが大文字
image.png

グルーバル登録

main.jsにて登録する。

main.js
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

// グローバル登録
Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

new Vue({
  render: h => h(App),
}).$mount('#app')
App.vue
<template>
  <div>
    <Job message="system engineer"></Job>
    <Job message="hogehoge"></Job>
  </div>
</template>

<script>
import Job from "./components/Job.vue";

export default {
  components: {
    Job: Job
  }
}
</script>
Job.vue
<template>
  <div>
    {{ msg | capitalize }}
  </div>
</template>

<script>
export default {
  props: {
    message: {
      type: String
    },
  },
  data: function() {
    return {
      msg: this.message
    }
  },
}
</script>

結果:先頭の文字列だけが大文字
image.png

9-3. 注意事項

  • this.は使えない

computedとの違い

  • computedは、キャッシュが残るため仮想DOMが変更した場合のみ実行される。パフォーマンスの面で優れている。
  • フィルターは、都度実行されるためパフォーマンスの面では劣る。ただ、作りやすく利用もしやすい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker Vue Go

Docker

Dockerマウントできないよ〜

ERROR: for nginx  Cannot start service nginx: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"rootfs_linux.go:58: mounting \\\"/Users/ishidashogo/practice/goPractice/etc/nginx/nginx.conf\\\" to rootfs 
\\\"/var/lib/docker/overlay2/ac829670cc63c6bd9749802860c0b6dd9619d56f1883525650acc81db4dc4ee1/merged\\\" at \\\"/var/lib/docker/overlay2/ac829670cc63c6bd9749802860c0b6dd9619d56f1883525650acc81db4dc4ee1/merged/etc/nginx/nginx.conf\\\" caused \\\"not a directory\\\"\"": unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type

マウントのディレクトリが違うみたいでした。
docker-compose.ymlファイル内で指定しているvolumeの場所に指定してある
欲しいファイルがないことによるエラーみたいでした。

https://qiita.com/hanakok/items/6bfcfbb8b7b4df877178

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

オンライン研修でYoutube動画を再生するためのWEBアプリをつくった

はじめに

コロナの影響で、オンラインで研修やセミナーを行うことが多くなりました。

その際、Youtubeにある動画の一部分をスマートに流したい。
プロとして再生に手間取るのはかっこわるい。
事前の準備で、再生の頭出しと終わりの事前設定をしておきたい。

そんな人のためのWEBアプリを作りました。

つくりたいイメージ

オンライン研修で3本くらいYoutube動画の頭出しと終了の設定を事前に終えられて、かつ、誰でもその設定が簡単に変えられるものを作ろうと思いました。

実際につくったもの

1つの動画の頭出しと終了の設定を、
コードの方の数字を変えるだけでできるようになりました。

詳細はこちらをご覧ください。
https://optimistic-ritchie-c5d29d.netlify.app/youtube05

ソースコードはこちら
https://gist.github.com/kaiser355/0a9e3a3a39407ee8b935b9cf93401a0b

ただし、動画の下にあるフォームを入力しても、
自動で計算はされるものの、それが動画の頭出しの設定には
変更できません。

ここはできるように改良していきます。

設定の変え方

コード内のこの部分の数字を変更してください。
単位は秒で。

playerVars: {
            start: 2, // 動画再生の開始位置
            end: 8 // 動画再生の終了位置

つかったフレームワーク・ライブラリなど
・Youtube Player API
・Vue.js
・Bootstrap

終わりに

つくりたいものをつくるために様々格闘しましたが、
・Youtube動画を複数設置すると動画が表示されなくなる
・フォームで計算したものを、再生開始時間のところに変数を代入してみるものの、
 うまく設定が変えられない
の課題がクリアできず、ひとまず、現状で公開します。

今後改善していきます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vueカルーセルコンポーネント「Hooper」を使う

ドキュメント

https://baianat.github.io/hooper/getting-started.html

インストール

Macターミナル
npm install hooper

vueコンポーネント

HooperSample.vue
<template>
  <hooper>
    <slide>
      slide 1
    </slide>
    <slide>
      slide 2
    </slide>
    <slide>
      slide 3
    </slide>
    <slide>
      slide 4
    </slide>
    <hooper-progress slot="hooper-addons"></hooper-progress>
    <hooper-pagination slot="hooper-addons"></hooper-pagination>
  </hooper>
</template>

<script>
import 
    Hooper,
    Slide,
    Progress as HooperProgress,
    Pagination as HooperPagination,
} from 'hooper';
import 'hooper/dist/hooper.css';

export default {
    name: 'App',
    components: {
      Hooper,
      Slide,
      HooperProgress,
      HooperPagination,
    }
  };
</script>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Mac】Vueカルーセルコンポーネント「Hooper」を使う

ドキュメント

https://baianat.github.io/hooper/getting-started.html

インストール

Macターミナル
npm install hooper

vueコンポーネント

HooperSample.vue
<template>
  <hooper>
    <slide>
      slide 1
    </slide>
    <slide>
      slide 2
    </slide>
    <slide>
      slide 3
    </slide>
    <slide>
      slide 4
    </slide>
    <hooper-progress slot="hooper-addons"></hooper-progress>
    <hooper-pagination slot="hooper-addons"></hooper-pagination>
  </hooper>
</template>

<script>
import 
    Hooper,
    Slide,
    Progress as HooperProgress,
    Pagination as HooperPagination,
} from 'hooper';
import 'hooper/dist/hooper.css';

export default {
    name: 'App',
    components: {
      Hooper,
      Slide,
      HooperProgress,
      HooperPagination,
    }
  };
</script>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue 省略記法

:v-bind

<a v-bind:href="url"> ... </a>
<a :href="url"> ... </a>

:v-on

<a v-on:click="func"> ... </a>
<a @click="func"> ... </a>

:v-slot

<template v-slot:title></>
<template #title></>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Mac】Vue cli

 vue cli インストール

Macターミナル
npm install -g @vue/cli

vue cli バージョン確認

Macターミナル
vue --version

vueプロジェクトを作成

Macターミナル
vue create new-project

開発用サーバ起動

Macターミナル
cd new-project
npm run serve  
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む