20200317のvue.jsに関する記事は20件です。

Laravel7.XでVue.jsを実装してみる

npmを起動してみる

npm run watchを叩くと以下のエラーメッセージが出力

terminal
'cross-env' is not recognized as an internal or external command,
operable program or batch file.

こちらのリンクを参考にして解決
https://stackoverflow.com/questions/45034581/laravel-5-4-cross-env-is-not-recognized-as-an-internal-or-external-command

Bootstrap-Vueの実装

こちらのドキュメントを参考に実施(https://bootstrap-vue.js.org/docs)

1) npmでbootstrap-vueをインストール

terminal
# With npm
npm install vue bootstrap-vue bootstrap

2) bootstrap-vueをインポート

resources\js\bootstrap.js
import Vue from 'vue'
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

3) BladeとVueファイルをVueに合わせて構成
(作成中…)
Laravel5.xではVue環境が構築されていた気がするが(Example-component等)
7.xはない…

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

コロナウイルスから学ぶdocker-compose

はじめに

最早今更感ありますが、新型コロナウイルス対策サイトが話題ですね
オープンソースコミュニティへの貢献の方法については既に非常に丁寧な記事が出ているので割愛しますが、
docker-composeの紹介をしている人が少ないので書いてみます

勿論ボランティアで何か貢献できれば何よりですが、
このプロジェクトはコミットしないとしてもdocker-composeやvue.jsに触れてみるのにかなりお勧めです
正直お国が主導のプロジェクトがどんな地獄なのか見学するつもりで覗いてみたのでびっくりした

docker-compose使ってみよう

新型コロナウイルス対策サイトのgitリポジトリ
ソースコードをクローンしたら、出来上がったディレクトリ上で

docker-compose up

と打つだけで環境構築からサーバーの起動まで終わり、
スクリーンショット (126).png

ブラウザでlocalhost:3000にアクセスすると動くようになります、すごーい
スクリーンショット (127).png

以上、みんなも試しにやってみてね

解説

当然docker及びdocker-composeはインストールする必要がありますが...
コマンドいくつか叩けばインストールできるので割愛

docker-composeで動くことを確認するためにどこを見るのか

プロジェクトのルートディレクトリにDockerfile

FROM node:10.19-alpine

WORKDIR /app

COPY package.json yarn.lock ./

RUN yarn install

COPY . .

EXPOSE 3000
ENV HOST 0.0.0.0

CMD ["yarn", "dev"]

そしてdocker-compose.ymlがあります

version: "3"
services:
  app:
    container_name: covid19
    build:
      context: .
      dockerfile: Dockerfile
    tty: true
    ports:
        - 3000:3000
    volumes:
        - .:/app
        - node_modules:/app/node_modules
volumes:
  node_modules: {}

docker-compose.ymlがあるからには環境構築がdocker-composeで行えるはずです。
内容によってはこれらの中身を見ればどのようなフレームワークなのかもおおよそ推測できるでしょう
全てを解説すると長くなるし、そもそも完璧に説明できるほど熟知しているかというと微妙ですが

このファイルを見ればdocker-compose.ymlの記述に従って、
covid19という命名のappコンテナが立ち上がり、
localhostの3000番ポートでアクセスできるようになる、
という動きをまずは雰囲気で感じることができれば良いと思います

終わりに

遊んでみたくなるdocker-composeコマンドを紹介

docker-compose up 通常の起動、終了する時はctrl + c
docker-compose up -d => dオプションでデーモン化、バックグラウンド起動できる
docker-compose exec app bash => 起動中のコンテナの中に入ることができる
docker-compose down => docker-composeで管理しているコンテナを全部終了する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

オンラインSwiftコード生成ツールをつくった

概要

ブラウザで利用できるSwiftコード生成ツールを作成しました。
https://shtnkgm.github.io/SwiftCodeGenerator/

↓こんなの

SwiftでTDDを進めるにあたり、Mockとなるインスタンスの生成コードを書くのが大変だっため、Webツールを作成しました。
SourceryやPure Swiftでやる方法も検討しましたが、Vue.jsでコードも書きたかったため、Web技術で作成しました。

できること

以下のような型定義を入力フォームにコピペすると、

struct Book {
    let price: Int
    let title: String
}

以下のようなコードを出力します。

メンバーワイズイニシャライザ

extension Book {
    init(
        price: Int,
        title: String
    ) {
        self.price = price
        self.title = title
    }
}

ファクトリメソッド(適当な値でインスタンスを生成するmakeメソッド)

extension Book {
    static func make(
        price: Int = 0,
        title: String = ""
    ) -> Book {
        return Book(
            price: price,
            title: title
        )
    }
}

Codableに準拠するための実装

extension Book: Codable {
    enum CodingKeys: String, CodingKey {
        case price
        case title
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        price = try container.decode(Int.self, forKey: .price)
        title = try container.decode(String.self, forKey: .title)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(price, forKey: .price)
        try container.encode(title, forKey: .title)
    }
}

Equatableに準拠するための実装

extension Book: Equatable {
    static func == (lhs: Book, rhs: Book) -> Bool {
        return
            lhs.price == rhs.price &&
            lhs.title == rhs.title
    }
}

構成

コード生成処理はクライアントサイドで行うため、かなりライトな構成です。

試してみてください

β版で不具合や足りない点もあるかと思いますが、活用いただけたら幸いです。

Swift Code Generator
https://shtnkgm.github.io/SwiftCodeGenerator/

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

地図を自由自在に描画できたらワクワクした話 ~ 新型コロナウィルスの感染情報を可視化したサイトを Firebase Hosting で公開

新型コロナウィルスの感染情報を可視化したサイトを作ったのですが、その際に地図を自由自在に描画できてワクワクした気持ちを共有できればと思います。

新型コロナウィルスの感染情報を可視化したサイト
https://hazard.westa.io/

もしよかったらご覧ください。

1. 地図の描画に D3.js を使う

地図を自由に描画できたら、色々可能性の幅が広がりそうでワクワクしませんか?
今回は『D3.js を使用すると地図を自由に描画できるよ!』って紹介記事です。

1.1 地図データの準備

(1) Natural Earth から世界地図のデータを取得

  • 取得した地形データのファイル拡張子は .shp
  • なお、この地図データには日本の都道府県情報も入っている (後述する geojson 形式に変換したのちにブラウザ上で動的に都道府県ごとに色を変えたりといった事も可能です)

(2) QGIS ソフトで地図を加工・ファイル形式変換

  • フリーソフト。地形のデータとなる点を移動したり、不要な地形を削除したり加工ができる
  • .shp から geojson 形式に変換できる

(3) mapshaper でデータを軽量化

  • 地形のデータとなる点情報をイイ感じに削減してデータを軽量化できる

1.2 地図データの描画

  • 上記で用意した地図データを D3.js を使用して SVG として描画

2020-03-17_15h26_29.png
↑ D3.js を使い日本地図を描画して、感染情報を元に色を付けた。QGIS を使い沖縄県の位置を上部に移動できたが、沖縄と本土を区切る線を入れたかったが方法がわからずこのまま

2020-03-17_15h26_41.png
↑ D3.js を使い世界地図を描画して、感染情報を元に色を付けた。地図データを軽量化しすぎてロシア上部、カナダ上部、グリーンランドなどが異様なほどチープな形状に... 言わなきゃ気付かんか、あははー(*'▽')

実際のコードは以下の記事が参考になりました。

noguchi さんの記事
d3で地図を描画する

2. D3 以外の地図描画方法

D3.js を使用しないでもっとお手軽に地図を表示して JavaScript から制御する方法はありますが今回採用は見送りました。

2.1 Japan Map - jQuery plugin

D3.js で実現する方法と比べて、とってもお手軽で導入コストが低そうです。
ですが、このライブラリは jQuery が必要であり、私は Nuxt.js を使いたい都合上、共存が面倒そうで利用しませんでした。

2.2 Google Charts / GeoChart

当初はこれで実装していましたが、GCP の Google Maps API を経由(mapsApiKeyが必要)するため課金対象となるようでした(間違っていたらごめんなさい)。

3. その他 利用技術

ついでに今回作成したサイトの技術情報を紹介させてください!
これまで色々なライブラリで遊んできましたが、ここ最近は私の中でTypeScript, Nuxt.js (Vue.js), Vuetify, firebase に落ち着いた感があります。

(1) Nuxt.js @2.11 (Vue.js のフレームワーク)

  • お手軽に SPA/SSR サイトを立ち上げるのに Vue.js のフレームワークである Nuxt.js を選定
  • なお、今回は SSR(サーバー・サイド・レンダリング) 不要のため SPA(シングル・ページ・アプリケーション) とした
  • PWA 対応もお手軽

(2) Vuetify @2.2 (デザイン・コンポーネントフレームワーク)

  • お手軽で信頼性のある UI ライブラリとして Vuetify を選定
  • スクロールなどにより、とある要素が表示されるタイミングで遅延実行が行える v-intersect 機能など、素晴らしい機能が盛りだくさん
  • スマホのネイティブアプリっぽい雰囲気にできる

Screenshot_20200317-155552.png
↑ 最近のスマホアプリは画面下にタブが固定表示されるものが多くなってきたが、Vuetify を使うとお手軽に実現できる

(3) vue/composition-api @0.4 (Vue.js v2 系で v3 系の機能を使えるライブラリ)

現状の vue の最新安定版は v2 系ですが、v3 系がアルファ段階で公開されています。
v3 のアルファ版はまだまだ挑戦する勇気が持てなかったので、代わりに v2 系で v3 系の composition-api が試せるライブラリを使ってみました。TypeScript とも相性が良く結構イイ感じです。

使い方は以下の記事が参考になりました。

@ryo2132 さんの記事
先取りVue 3.x !! Composition API を試してみる

(4) Chart.js @2.9

  • 可視化するうえでチャート (棒グラフや折れ線グラフ、円グラフなど) をお手軽に描画するためのライブラリ
  • とってもお手軽にきれいなチャートを描画できる

2020-03-17_16h03_29.png

チャートライブラリの選定には以下の記事が役に立ちました。

@awakia さんの記事
チャート、グラフを書くのに良さそうなJavascriptライブラリ6選

(5) PWA

  • Web サイトを直接ホームに追加することでアプリケーション化できます。(以下の『感染情報』アプリがそれです)

Screenshot_20200317-154657.png

  • PWA にはアプリ化するにあたって色々な機能がありますが、以下の記事がとっても詳しいです。

@umamichi さんの記事
PWA 入門 〜iOS SafariでPWAを体験するまで〜 2019年7月更新

(6) TypeScript @3.8

  • TypeScript Love!

4. 現状の運用費用

  • Google/Firebase-Hosting
    • 今のところ無料枠内
  • ドメイン代
    • もともと持っていたドメインからサブドメインを作成したため追加費用なし

参考までに記載しておきます。


勢いで書いてしまったので変な部分も多分にありそうですが、皆さんも D3.js + 地図描画いかがでしょうか。
記事の内容が『役に立った』『面白かった』と思ったら、ぜひ LGTM(いいね) を頂けると嬉しい限りでございます!

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

シニアエンジニアに聞いたvue関連ライブラリの選定方法

同僚の @kubotak さんに聞いたライブラリ選定基準をまとめます。今回は特にフロントエンド領域でvueに絞って書きます。

1. 公式がまとめているライブラリリストをみる

まずはともあれ、vuejsが公式でまとめているライブラリリストを参照する。

https://github.com/vuejs/awesome-vue

ここにやりたいことにマッチしそうなライブラリを全部一通り見てみる。

2. star数を確認する

あまりにも使っている人が少ないと、コミュニティがないことが想定される

3. 新規 issue を確認して、それがPRに反映されているか

issue が無いのはユーザが少ないか、すでに枯れている(安定してバグなども少ない)ライブラリ。

issue が多いのにPRが作られていない、またはマージされていないライブラリはメンテナが居なくなっているので避けるのが吉。

4. 最終リリースタグとnpmのページを確認する

githubでreleasesをみると最後にいつリリースされているかわかる。ただしnpmの場合にはrelease tagが切られていなくてもnpm packageとしてリリースされていることがあるのでそちらも確認する。
あまりに古いのだと新しいvueバージョンに追従できない可能性などを考慮した方が良い。

5. readme がきちんと書かれているか

有用な情報が書かれていないと導入は辛くなります。

6. 動作例が書かれているか

あれば何ができるかよりイメージがつきやすくなります。無い場合には自分で動かさないといけないのでややハードルは上がる。

7. ファイルサイズは大きすぎないか

あまりに便利すぎるライブラリは全部入りでファイルサイズが大きくなりがちです。
nuxtなどフレームワークで適切に配信されるものが分割される場合にはそこまでシビアにならなくても良い。

8. 2個くらいまで絞り込めたら実際に使ってみる

何個かまで絞れて迷うところまできたら、導入しやすそうか使いやすそうかを実際に使ってみて確かめる。

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

Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part4

前回のパート

前回は、全ページで使用するヘッダーの作成と会員登録の処理の実装を行いました
前回のパートはこちら→Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part3
今回は、前回実装し登録をした内容を利用してログイン機能の実装をしていこうと思います

ログインフォームの実装(Vue側)

まずはログインフォームのview側の実装をしていきます
client/componentsLogin.vueを作成して下記を追加してください

Login.vue
<template>
    <div>
        <Header />
        <div class="main-container">
            <v-form v-model="valid">
                <v-text-field v-model="form.email" :rules="emailRules" label="E-mail" required></v-text-field>
                <v-text-field v-model="form.password" :rules="passwordRules" label="Password" required type="password"></v-text-field>
                <v-btn small>submit</v-btn>
            </v-form>
        </div>
    </div>
</template>

<script>
    import Header from './Header';

    export default {
        components: {
            Header
        },
        metaInfo: {
            title: 'ログイン',
            htmlAttrs: {
                lang: 'ja'
            }
        },
        created () {
            const user = this.$store.getters['auth/user'];
            if (user !== null) {
                this.$router.push('/todo');
            }
        },
        data () {
            return {
                form: {
                    email: '',
                    password: '',
                },
                emailRules: [
                    v => !!v || 'E-mailを入力してください',
                    v => /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(v) || 'E-mailを正しく入力してください'
                ],
                passwordRules: [
                    v => !!v || 'パスワードを入力してください'
                ]
            }
        }
    }
</script>

<style>
    .main-container {
        width: 500px;
        margin: auto;
    }
</style>

前回のRegister.vueと内容はほとんど同じなので
特に説明は必要ないかと思いますので、割愛します
説明が必要な方は、前回のパートに戻って確認してみてください

ではここにmethodを追加していきます

Register.vue
<template>
    <div>
        <Header />
        <div class="main-container">
            <v-form v-model="valid">
                <v-text-field v-model="form.email" :rules="emailRules" label="E-mail" required></v-text-field>
                <v-text-field v-model="form.password" :rules="passwordRules" label="Password" required type="password"></v-text-field>
                <v-btn small @click="login">submit</v-btn>    //追加
            </v-form>
        </div>
    </div>
</template>

<script>
    import Header from './Header';

    export default {
        components: {
            Header
        },
        metaInfo: {
            title: 'ログイン',
            htmlAttrs: {
                lang: 'ja'
            }
        },
        created () {
            const user = this.$store.getters['auth/user'];
            if (user !== null) {
                this.$router.push('/todo');
            }
        },
        data () {
            return {
                form: {
                    email: '',
                    password: '',
                },
                emailRules: [
                    v => !!v || 'E-mailを入力してください',
                    v => /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(v) || 'E-mailを正しく入力してください'
                ],
                passwordRules: [
                    v => !!v || 'パスワードを入力してください'
                ]
            }
        },
        methods: {    //追加
            async login() {
                await this.$store.dispatch('auth/login', this.form);
                this.$router.push('/todo');
            }
        }
    }
</script>

<style>
    .main-container {
        width: 500px;
        margin: auto;
    }
</style>

ログイン時のmethodを追加しました
内容は、auth.jsloginアクションにフォームに入力された内容を渡しdipatchしています
その処理が終われば、/todoのTodoページに遷移する様に設定してます

では次に、auth.jsloginアクションを定義していきます
'auth.js`に下記を追加してください

auth.js
import axios from 'axios';

const state = {
    user: null
}

const getters = {
    user: state => state.user
}

const mutations = {
    setUser (state, user) {
        state.user = user;
    }
}

const actions = {
    async register({ commit }, data) {
        const response = await axios.post('/api/register', data)
        commit('setUser', response.data);
    },

    async searchUser({ commit }) {
        const response = await axios.get('/api/user');
        const user = response.data ? response.data : null;
        commit('setUser', user);
    },

    async login({ commit }, data) {    //追加
        const response = await axios.post('/api/login', data);
        commit('setUser', response.data);
    }
}

export default {
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}

今回追加したアクションはLaravelで定義した、/loginのルートに対して入力されたデータをPOSTし
その、情報を変数responseに格納しています
そして、その値をsetUsermutationに対してcommitしstateのuserの値をセットしています
registerの時と同じ流れになります

次に、Laravel側の実装をしていきます

Laravel側の実装

Vue側でのauth.jsでPOSTしていた/loginをルートに定義していきます
api.phpに下記を追加してください

api.php
Route::post('/register', 'Auth\RegisterController@register')->name('register');
Route::post('/login', 'Auth\LoginController@login')->name('login');    //追加
Route::get('/user', function(){
    return Auth::user();
});

これでauth.jsloginアクションからaxiosでリクエストを投げられる様になりました

そして、part3で下記の記述をLoginController.phpに追加してますのでこれでLaravel側での実装は完了です

LoginController.php
    protected function authenticated(Request $request, $user)    //追加
    {
        return $user;
    }

上記までの記述で一通りログイン機能の実装が終わりました
ただ遷移する画面の/todoをまだ用意していないので正常に画面が遷移することができないので
ここで、Todo.vueコンポーネントを追加しておきましょう
client/componentsTodo.vueファイルを新規で作成してください
中身はこの様にしておいてください

Todo.vue
<template></template>

<script></script>

<style></style>

次にrouter.jsにコンポーネントを登録しておきます
router.jsに下記を追加してください

router.js
import Vue from 'vue';
import Router from 'vue-router';
import Login from '../components/Login';
import Register from '../components/Register';
import Todo from '../components/Todo';    //追加

Vue.use(Router);

export default new Router({
    mode: 'history',
    routes: [
        {
            path: '/login',
            component: Login
        },
        {
            path: '/signup',
            component: Register
        },
        {
            path: '/todo',    //追加
            component: Todo
        }
    ]
})

ここまでできたらログインを試してみてください
正常であれば、ログイン後/todoに遷移し真っ白な画面が表示されるかと思います

終わりに

今回はログイン機能の実装を行いました
それに加えて、/todoページの用意も行いました

次回は、ログアウト機能を実装したいと思います
次回のログアウト機能が終われば認証周りの実装は終わりですので、Todoを作っていく実装に入っていきます

次回のパートはこちら→Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part5

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

Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part3

前回のパート

前回は、Authの導入とマイグレーションファイルを作成し
今回のTodoアプリで使用するテーブルの作成まで行いました
前回のパートはこちら→Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part2
今回は、全てのページで使うヘッダーの作成と認証周りの実装をやっていきます

ヘッダーコンポーネントの作成

全てのページで共通で使うヘッダーを作成していきます
Vuetifyで実装しますので、Vuetifyを使用しない方は自作での実装をしてください
まず、client/componentsHeader.vueを作成し下記を追加してください

Header.vue
<template>
    <v-card color="grey lighten-4" flat height="200px" tile>
        <v-toolbar dense>
            <v-app-bar-nav-icon></v-app-bar-nav-icon>

            <v-toolbar-title>Todo-List</v-toolbar-title>

            <v-spacer></v-spacer>

            <router-link to="/signup">
                <v-btn icon>
                    <v-icon>mdi-account</v-icon>
                </v-btn>
            </router-link>

            <router-link to="/todo">
                <v-btn icon>
                    <v-icon>mdi-align-horizontal-left</v-icon>
                </v-btn>
            </router-link>

            <router-link to="/login">
                <v-btn icon>
                    <v-icon>mdi-login</v-icon>
                </v-btn>
            </router-link>

            <v-btn icon>
                <v-icon>mdi-logout</v-icon>
            </v-btn>
        </v-toolbar>
    </v-card>
</template>

templateのみのシンプルな物です
<v-btn><router-link>で囲み、会員登録やログインやログアウト、Todoページのリンクを設定しています
全てVuetifyになります
詳しく知りたい方はこちらを参照ください→こちら
これでヘッダーの用意は終わりです

会員登録の実装

まずはVue側でフォームの実装をしていきます
client/componentsRegister.vueを作成してください
Register.vueにを下記の様に下記を追加してください

Register.vue
<template>
    <div>
        <Header />
        <div class="main-container">
            <v-form v-model="valid">    //・・・①
                <v-text-field v-model="form.name" :rules="nameRules" label="Name" required></v-text-field>    //・・・②
                <v-text-field v-model="form.email" :rules="emailRules" label="E-mail" required></v-text-field>
                <v-text-field v-model="form.password" :rules="passwordRules" label="Password" required type="password"></v-text-field>
                <v-text-field v-model="form.password_confirmation" :rules="repasswordRules" label="Confirm Password" required type="password"></v-text-field>
                <v-btn small>submit</v-btn>
            </v-form>
        </div>
    </div>
</template>

<script>
    import Header from './Header';

    export default {
        components: {
            Header
        },
        metaInfo: {    //・・・③
            title: '会員登録',
            htmlAttrs: {
                lang: 'ja'
            }
        },
        data () {
            return {
                form : {
                    name: '',
                    email: '',
                    password: '',
                    password_confirmation: '',
                },
                nameRules: [
                    v => !!v || '名前を入力してください',    //・・・④
                ],
                emailRules: [
                    v => !!v || 'E-mailを入力してください',
                    v => /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(v) || 'E-mailを正しく入力してください'    //・・・⑤
                ],
                passwordRules: [
                    v => !!v || 'パスワードを入力してください',
                    v => v.length >= 8 || 'パスワードは8文字以上で入力してください'    //・・・⑥
                ],
                repasswordRules: [
                    v => !!v || 'パスワードの再入力を行ってください',
                    v => v == this.form.password || 'パスワードが一致しません'    //・・・⑦
                ]
            }
        }
    }
</script>

<style>
    .main-container {
        width: 500px;
        margin: auto;
    }
</style>

①ここは全てVuetifyになります
ここでは簡単な説明はしますが、もっと詳しく知りたい方は、こちらをご覧ください→こちら

②Vuetifyのフォームになります
:rulesこの部分で下の④⑤⑥⑦のルールとバインディングしており、フロント側でのバリデーションを行っています
requireは入力必須を意味します
labelでフォームのラベル名に設定できます
②で設定しているものはどれも同じ要領です
次に設定しているバリデーションのルールについて軽く触れておきます
④入力の値が存在しているかどうか(未入力でないか)をチェックしています
⑤正規表現でEmailの形式かどうかをチェックしています
⑥パスワードが8文字以上で入力されているかをチェックしています
⑦passwordの入力値を一致しているかをチェックしています

③part1でインストールしたVue Metaです
ここでは、titleを【会員登録】としてlangをjaに設定しています
Vue Metaをこの様な設定を行うために使用します

これで、Vuetifyを使って簡単にフォームを用意できバリデーションまで行えました
次に会員登録機能の実装を行っていきます

会員登録機能の実装(Laravel側)

まずは、routes/api.phpを開きルートを定義していきます
/registerは会員登録用のルート
/userはログインをしているのかを常時チェックするために用意したルートになります(この後のVue側の実装で再度説明します)

api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::post('/register', 'Auth\RegisterController@register')->name('register');    //追加
Route::get('/user', function(){    //追加
    return Auth::user();
});

次にapp/Http/Controllers/Auth/RegisterCOntroller.phpを開いて下記を追加します

RegisterController.php
    protected function registered(Request $request, $user)    //追加
    {
        return $user;
    }

registerd()メソッドをオーバーライドすることで
登録処理をした際にUser情報を返却できる様に設定できます
この値を使って今後認証を行うので、上記を追加しました

このついでに
ログイン時にとログアウト時にも必要になる処理を先にやっておきます
app/Http/Controllers/Auth/LoginController.phpを開いて下記を追加してください

LoginController.php
    protected function authenticated(Request $request, $user)    //追加
    {
        return $user;
    }

こちらの追加の内容も、registerd()メソッドのオーバーライドをした際と同じ理由になり
ログイン時にUserの情報を返却する様に設定しています

次にLoginController.phpでさらにloggedOut()メソッドを追加してください

LoginController.php
    protected function loggedOut(Request $request)
    {
        $request->session()->regenerate();
        return response('', 200);
    }

こちらは、ログアウト時に呼ばれるメソッドになり
ログアウト時にセッションを再生成を行い、レスポンスを返す様にしてあります

上記3つの追加点については、本記事作成でも参考にさせて頂いたこちらの記事を参照してください→こちら

以上で会員登録に必要なLaravel側の処理の実装は終わりです(ログイン時とログアウト時の設定も行いました)

会員登録処理(Vue側)

まずRegister.vueに下記を追加してください

Register.vue
<template>
    <div>
        <Header />
        <div class="main-container">
            <v-form v-model="valid">
                <v-text-field v-model="form.name" :rules="nameRules" :counter="10" label="Name" required></v-text-field>
                <v-text-field v-model="form.email" :rules="emailRules" label="E-mail" required></v-text-field>
                <v-text-field v-model="form.password" :rules="passwordRules" label="Password" required type="password"></v-text-field>
                <v-text-field v-model="form.password_confirmation" :rules="repasswordRules" label="Confirm Password" required type="password"></v-text-field>
                <v-btn small @click="register">submit</v-btn>    //追加
            </v-form>
        </div>
    </div>
</template>

<script>
    import Header from './Header';

    export default {
        components: {
            Header
        },
        metaInfo: {
            title: '会員登録',
            htmlAttrs: {
                lang: 'ja'
            }
        },
        created () {
            const user = this.$store.getters['auth/user'];
            if (user !== null) {
                this.$router.push('/todo');
            }
        },
        data () {
            return {
                form : {
                    name: '',
                    email: '',
                    password: '',
                    password_confirmation: '',
                },
                nameRules: [
                    v => !!v || '名前を入力してください',
                ],
                emailRules: [
                    v => !!v || 'E-mailを入力してください',
                    v => /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(v) || 'E-mailを正しく入力してください'
                ],
                passwordRules: [
                    v => !!v || 'パスワードを入力してください',
                    v => v.length >= 8 || 'パスワードは8文字以上で入力してください'
                ],
                repasswordRules: [
                    v => !!v || 'パスワードの再入力を行ってください',
                v => v == this.form.password || 'パスワードが一致しません'
                ]
            }
        },
        methods: {    //追加
            async register() {
                await this.$store.dispatch('auth/register', this.form);
                this.$router.push('/todo');
            }
        }
    }
</script>

<style>
    .main-container {
        width: 500px;
        margin: auto;
    }
</style>

①クリックイベントを追加しています
クリックすることでregisterメソッドを呼び出します

②このメソッドによって登録処理を実行します
厳密に言うと、登録処理をするアクションを呼び出しています(auth.jsについてはこの後実装します)
会員登録の処理後に、Todoページに遷移する様にしています

次に、register()でdispatchしているauth.jsregisterの実装をしていきます

auth.js
import axios from 'axios';

const state = {
    user: null    //追加
}

const getters = {
    user: state => state.user    //追加
}

const mutations = {
    setUser (state, user) {    //追加
        state.user = user;
    }
}

const actions = {
    async register({ commit }, data) {    //追加
        const response = await axios.post('/api/register', data)
        commit('setUser', response.data);
    },

    async searchUser({ commit }) {    //追加
        const response = await axios.get('/api/user');
        const user = response.data ? response.data : null
        commit('setUser', user);
    },

}

export default {
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}
main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router/router';
import store from './store/store';
import vuetify from './plugins/vuetify';
import axios from 'axios';
import VueMeta from 'vue-meta';

Vue.config.productionTip = false

Vue.use(axios);
Vue.use(VueMeta, { refreshOnceOnNavigation: true });

const createApp = async () => {    //追加
    await store.dispatch('auth/searchUser');

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

createApp();    //追加

一気にauth.jsの追加とmain.jsの一部追加を行いました
一つづ説明していきます

auth.js
const state = {
    user: null  
}

stateでuserの情報を管理します
このアプリケーション内では、全てこのuserの値の有無を見てログイン認証やユーザー情報の所得を行います

auth.js
const getters = {
    user: state => state.user
}

stateのuserの情報を所得するgetterを定義しています

auth.js
const mutations = {
    setUser (state, user) {
        state.user = user;
    }
}

受け取ったデータをstateのuserに値をセットするミューテーションを定義しています

auth.js
    async register({ commit }, data) {    //追加
        const response = await axios.post('/api/register', data)
        commit('setUser', response.data);
    }

Laravel側のapi.phpで定義したregisterに対してpostしています
第二引数のdataはフォームに入力された値がv-modelでバインドされたdataの中身が渡されています
ここでの返り値として、先ほどオーバーライドしたregistered()メソッドでの$userの値がresponseにセットされます
その値をsetUserに対してcommitしてstateのuserに値を設定しています

auth.js
    async searchtUser({ commit }) {    //追加
        const response = await axios.get('/api/user');
        const user = response.data ? response.data : null;
        commit('setUser', user);
    }

Laravel側の実装の際にapi.phpにて定義した/userのルートに対してアクセスをしています
/userのルートはAuth::user()として認証しているユーザーの情報を返却する様に作りました
Auth::user()は認証していればユーザー情報が、認証されていなければnullが返ってきます
それを利用して、上記アクションでは/api/userに対してリクエストをしてその戻り値(認証されていればユーザー情報、認証されていなければnull)を
変数responseに入れています
const user = response.data ? response.data : null;で認証されていてresponseに値が入っていればその値を
認証されておらずnullが入っていればnullを変数userに入れています
そのuserをsetUserでcommitしてstateのuserに値を入れています
なのでstateのuserはログインしていればユーザー情報、ログインしていなければnullが常に入っている様にしています
あとはこれを常時実行するためにどうしているかと言うと、先ほど追加したmain.jsの追加部分になります

main.js
const createApp = async () => {
    await store.dispatch('auth/searchUser');

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

createApp();

ここでVueインスタンスが作られる際に毎回、createApp()を実行することにより
auth.jssearchUserアクションを実行しています
これにより、auth.jssearchUserが毎回実行されることで
Laravelで定義した/userにリクエストを投げ現在の認証情報を所得しauth.jssetUserがcommitされ
stateのuserに値がセットされると言うことになります

Register.vue
created () {
    const user = this.$store.getters['auth/user'];
    if (user !== null) {
        this.$router.push('/todo');
    }
}

この部分でそのページにアクセスする度にcreated()が実行され
auth.jsのgettersを利用してstateの現在のuser情報を所得し
ログインしていれば/todoのページへ遷移する様に設定しています(ログインしていない場合はログインページが表示される)

ここまでの実装で
会員登録が行える様になりますので、フォームから入力して登録を実行してみてください
正常であれば、入力内容がDBに保存され登録処理ができます

終わりに

今回はヘッダーのコンポーネントの作成と、会員登録機能の実装を一通り行いました
次回は、今回登録した内容を利用してログインができる様に、ログイン機能の実装をやっていきます

次のパートはこちら→Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part4

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

Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part2

前回のパート

前回はVue CLIとLaravelの環境構築を含め、VuexやVue RouterのセットアップとVue MetaとVuetifyの
インストールを行いました
前回の記事はこちら→Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part1
今回は、本記事で作成するTodoリストに使うテーブル作成から行います

Authの導入

まずはターミナルから$ php artisan serve$ npm run serveを実行して
LaravelとVue CLIを動かしておいてください

また事前に、.envファイルのDBの設定とDBの作成を行ってください
Laravelの認証を使うためにAuthを導入していきます
コマンドにて下記を実行してください
$ composer require laravel/ui
$ php artisan ui vue --auth
$ php artisan migrate
$ npm install
$ npm run dev
上記を順に実行することで、LaravelでAuthが導入できLaravel側でのデフォルトの認証画面にアクセスできる状態になります(今回はview側はVueを使用するため使いません)

マイグレーションの作成

まず今回使うテーブルは2種類になります
ユーザーの情報を扱う、UsersテーブルとTodoの情報を管理するTodosテーブルになります
Usersテーブルは上記のAuthの導入をした際に、作成されているUsersテーブルをそのまま使うので
ここで作るテーブルはTodosテーブルのみになります
早速Todosテーブルのマイグレーションを作成していきます
コマンドにて下記を実行
$ php artisan make:migration create_todos_table --create=todos

作成されたファイルdatabase/migrations/XXXX_XX_XX_XXXXXXX_create_todos_table.phpを開き下記と同じ様に書き換えてください

XXXX_XX_XX_XXXXXXXX_create_todos_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class TodosCreateTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('todos', function (Blueprint $table) {
            $table->id();
            $table->integer('user_id');
            $table->text('text');    
            $table->softDeletes();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('todos');
    }
}

上記が完了したら、マイグレーションを実行しましょう
$ php artisan migrate
実行したら作成したマイグレーションのテーブルが作成できているか、確認してください

以上で今回使用する、テーブルの準備が整いました

終わりに

今回は、Authの導入とマイグレーションファイルの作成を行いました
次回から会員登録やログインなどの認証まわりの実装に入っていきます

次のパートはこちら→Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part3

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

Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part1

はじめに

本記事は、Vue CLIとLaravelに加えてVuetifyを使ってTodoリストを作るチュートリアルです
Vuetifyは各自採用するかは決めていただければと思います。
本記事にはVuetifyの記載が多く登場しますが、Vuetifyを使わずにこのチュートリアルを進められる方はVuetifyの部分は無視してもらい
自身でマークアップを行ってください。
また、本チュートリアルはこちらの記事を参考にさせて頂き制作しました

このチュートリアルで学べること

  • Vue CLIとLaravelを利用した開発の流れ
  • Vue(SPA)での開発
  • LaravelとVueでの認証周りのあれこれ
  • Vuexの活用方法
  • Vue Routerの活用方法

このチュートリアルの対象者

  • Laravelの基本を学んだ方
  • Vueの基本を学んだ方
  • Vue CLIとLaravelで何か作ってみたい方

バージョン

Vue CLI - 4.0.5
laravel - 7.0.4

Vue CLI × Laravelの環境構築

まずはLaravelでアプリケーションを作成していきます
コマンドにて下記を実行
$ laravel new VueTodo
作ったアプリケーションに移動します
$ cd VueTodo
次にVue CLIをLaravelに作っていきます
$ vue create client
Manualyを選択
スクリーンショット 2020-03-15 16.28.26.png
RouterとVuexを選択
スクリーンショット 2020-03-15 16.28.44.png
historyモードを使用するのでyを押してEnter
スクリーンショット 2020-03-15 16.28.56.png
今回はエラー防止のみのESLintを使用するのでそのままEnter
スクリーンショット 2020-03-15 16.29.06.png
保存時にLintを実行するため、そのままEnter
スクリーンショット 2020-03-15 16.29.12.png
package.jsonで管理するため、In package.jsonを選択してEnter
スクリーンショット 2020-03-15 16.29.22.png
今回の設定を今回は特に保存しないので、nを押してEnter
スクリーンショット 2020-03-15 16.43.52.png
これでLaravelにclientと言う名前でVue CLIが構築されます
ここまでで、LaravelとVue CLIの準備は完了

proxyの設定を行う

Vue CLIとLaravel間ではドメインが違うため、お互いに通信を行うための設定が必要です
今回はproxyを使います
Vue CLIの機能を使いproxyの設定をすることができます。

clientディレクトリにvue.config.jsファイルを作成
下記を追加
これによりVue CLIからの通信は http://127.0.0.1:8000 に変換され同一ドメインでの通信が可能になります
(ここのパスは環境によって変わるため、$ php artisan serveをした際にアクセスできるLaravel側の自身の環境に書き換えてください)

vue.config.js
module.exports = {
    devServer: {
        proxy: {
            '/api': {
                target: 'http://127.0.0.1:8000'
            }
        }
    }
}

RouteServiceProviderの変更

app/Http/Providers/RouteServiceProvidermapApiRoutes()メソッドの変更を行います
デフォルトでは下記のようになっています

RouteServiceProvider.php
    protected function mapApiRoutes()
    {
        Route::prefix('api')
             ->middleware('api')  //・・・①
             ->namespace($this->namespace)
             ->group(base_path('routes/api.php'));
    }

①の部分がデフォルトではapiとなっています
このmiddlewareの設定を下記のように書き換えます

RouteServiceProider.php
    protected function mapApiRoutes()
    {
        Route::prefix('api')
             ->middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/api.php'));
    }

何故ここを書き換えるのかと言うと
apiとwebでは適応されるmiddlewareが違います
apiのmiddlewareはCSFRトークンやセッションなどのmiddlewareが含まれていません
ただ今回の場合は、Laravelのセッションの認証をするためにセッションや、クッキーを必要とするため
webに変更しています
従来のAPIとしてLaravelを利用する場合は、apiのデフォルトのままで大丈夫です

axiosのインストール

コマンドにて下記を実行
$ npm install axios

clietn/src/main.jsにてaxiosをuseする

main.js
import Vue from 'vue';
import App from './App.vue';
import axios from 'axios';

Vue.config.productionTip = false

Vue.use(axios);

new Vue({ 
    render: h => h(App)
}).$mount('#app')


Vue Routeのセットアップ

Vue Routerセットアップを行います
すでにVue CLIの作成時にRouterを導入してるのでインストールは不要です
client/src/routerと言うディレクトリがRouterのファイルになります

client/src/index.jsのファイル名をわかりやすい様にリネームし、router.jsと変更し
router.jsに下記に書き換えてください

router.js
import Vue from 'vue';
import Router from 'vue-router';

Vue.use(Router);

export default new Router({
    mode: 'history',
    routes: [
        //今は空にしておく
    ]
})

router.jsの作成が完了したら、main.jsにて下記を追加

main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router/router';    //追加
import axios from 'axios';

Vue.use(axios);

new Vue({
    router,    //追加
    render: h => h(App)
}).$mount('#app')

これでVue Routerのセットアップは完了です

Vuexのセットアップ

こちらも、Vue CLIの作成時にインストールしているのでインストールは不要です

client/src/storeがVuexのファイルになります
こちらも、わかりやすい様にリネームしてstore.jsとして、新規ファイルでauth.jsを作成してください
作成したらstore.jsを下記に書き換えてください

store.js
import Vue from 'vue';
import Vuex from 'vuex';
import auth from './auth';

Vue.use(Vuex);

export default new Vuex.Store({
    modules: {
        auth
    }
})

auth.jsにも下記を追加

auth.js
import axios from 'axios';    //axiosを今後使うので読み込んでます

const state = {
}

const getters = {
}

const mutations = {
}

const actions = {
}

export default {
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}

main.jsに下記を追加する

main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router/router';
import store from './store/store';    //追加
import axios from 'axios';

Vue.use(axios);

new Vue({
    router,
    store,    //追加
    render: h => h(App)
}).$mount('#app')

以上でVuexのセットアップは終了です

Vue Metaのインストール

Vue Metaを導入することでVueのscript内でheadのlang設定やtitleなどの設定を行えるようになります
今後使っていくので使い方等は追々説明しますので、ここではインストールとセットアップのみ手順にしたがって行ってください

コマンドにて下記を実行
$ npm install vue-meta

main.jsにて下記を追加する

main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router/router';
import store from './store/store';
import axios from 'axios';
import VueMeta from 'vue-meta';    //追加

Vue.use(axios);
Vue.use(VueMeta, { refreshOnceOnNavigation: true });    //追加

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

Vuetifyの導入

※Vuetifyを使わない方はここを飛ばしてもらってOKです

$ cd clientに移動して下記コマンドを実行
$ vue add vuetify
コマンドを実行することでclient/pluginsvuetify.jsが作成されていることを確認してください
また、main.jsに自動的に追加されていることも確認してください(追加されていない場合は追加してください)

main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router/router';
import store from './store/store';
import vuetify from './plugins/vuetify';    //追加されている
import axios from 'axios';
import VueMeta from 'vue-meta';

Vue.use(axios);
Vue.use(VueMeta, { refreshOnceOnNavigation: true });    //追加

new Vue({
    router,
    vuetify,    //追加されている
    store,
    render: h => h(App)
}).$mount('#app')

終わりに

以上でVue CLIとLaravelで今回必要な物のインストールやセットアップなどの環境の構築が終わりました
次回は、今回のTodoリストで使うUserのテーブルとTodoを管理する2つのテーブルのマイグレーションの作成から始めようと思います

次のパートはこちら→Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part2

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

【Nuxt.js】Vue Router基礎編:params, queryを使おう

前置き

とっても便利なparams, queryについてご紹介?
・同じコンポーネントを見せたいけど、
 カテゴリごとにURLだけを変えたい…
・一覧ページからソートして表示させたい

そんな時に便利です♪

params, queryについて
いくつかに分けて書きます✍️
router-linkが分かれば簡単です?
まだ不安な方のためにも
複数の書き方で記載しました?

・params, queryの違い
・使うメリット
・クエリパラメーターとは?
・router-link色々

params, queryの違い

まずはURLを見るのが
分かりやすいと思います?

localhost:3000/param/param?query=123

・パスパラメーター(param)
 ?より前の部分、省略できない
・クエリパラメーター(query)
 ?以降の部分、省略できる

?例えば

localhost:3000/project123

projectごとにURLを変更
表示ページは同じでコンポーネントで表示分け

file
pages/
--| _id/
-----| index.vue

?例えば

localhost:3000/events?today=true

events/index.vueの中で
today=trueでソートをかけて表示

file
pages/
--| events/
-----| index.vue

eventsは絶対省略できないですね。
pages/events/index.vueに
行けなくなってしまいます。

?today=trueは省略しても
ソートが外れるだけなので
ページはきちんと表示されます♪

メリット

# params, queryの違い で書いた通り!
もう少し身近な例でいうと…

例えば!

?イベントサイトで一覧を見たい

https://events

その中でも1ページ目だけ見たい

https://events?page=1

ということが、
できちゃいます!!!

以前paginationで使ったことがあるので
こちらも確認してみてください?
https://note.com/aliz/n/nd9f344e4686f

クエリパラメーターとは

サーバーに情報を送るための文字列のこと✍️
urlの最後に?から始まる文字列をつけて
サーバーにデータが送信されます!
複数のデータを送る時は?で繋げます。

localhost:3000/post?id=123

id=123というデータを
サーバーに送信していますね!

ではディレクトリ や
表示はどうなるかというと…

file
pages/
--| post/
-----| index.vue

サーバーにデータを送りたいだけなので
表示するページ自体はpages/post/index.vue

そこにクエリパラメーターを入れて
パラメーターを参照することで
自分のIDや登録名が見れたり?
フィルターをかけてソートできたり?✨
するわけです!!!

router-link色々

paramsやqueryを使う前に?
pathやnameを使った
router-link(nuxt-link)を理解しましょう!
?template内のlink部分だけ書きます?

【飛びたいURL】

localhost:3000/home

【ディレクトリ】 

file
pages/
--| home/
-----| index.vue

ではvue検証で
nameとpathを見てみましょう?

・nameはhome
・pathは/home

ということが分かりますね!
Frame 3.png

【pathを使った書き方】

◾️router-linkバージョン

index.vue
<router-link
    :to="{path: 'home'}"
>
    home
</router-link>

◾️$router.pushバージョン

index.vue
<button
    type="button"
    @click="$router.push('home')"
>
    home
</button>

【nameを使った書き方】

◾️router-linkバージョン

index.vue
<router-link
    :to="{name: 'home'}"
>
    home
</router-link>

◾️$router.pushバージョン

index.vue
<button
    type="button"
    @click="$router.push({ name: 'home'})"
>
    home
</button>

さあ、ここまではOKですか???

router-linkにparamsとqueryを追加

ではname, pathに
paramsとqueryを追加してみましょう!
基本的な書き方は公式のこちら。

https://router.vuejs.org/ja/guide/essentials/navigation.html

paramsの追加

【path + params を使った書き方】

pathはURLを書けば良いだけ?
こんがらがったら
# params, queryとは
に戻りましょう!

【飛びたいURL】

localhost:3000/post/profile

【ディレクトリ 】

file
pages/
--| post/
-----| profile.vue

◾️router-linkバージョン

index.vue
<router-link
    :to="{ path: '/post/profile'}"
>
    home
</router-link>

◾️$router.pushバージョン

index.vue
<button
    type="button"
    @click="$router.push({ path: 'post/profile'})"
>
    home
</button>

◾️動的ルーティング
user.idごとにページを変えたい(_id.vue)
その場合はuser.idを
fetchでstoreから取ってきたりします!
その辺は別記事にて書こうと思います?
一旦リンクの書き方のみ。

✅'' にurlを書いていましたが、
 動的ルーティングの場合は
 ``を使ってかいていきます✍️

https://ja.nuxtjs.org/guide/routing/

index.vue
<router-link
    :to="{ path: `/post/${user.id}`}"
>
    home
</router-link>

【name + params を使った書き方】

【飛びたいURL】

localhost:3000/post/123

【ディレクトリ 】

file
pages/
--| post/
-----| _id.vue

再びvue検証を見てみましょう?
mix.png

◾️router-linkバージョン

index.vue
<router-link
    :to="{ name: 'post-id', params:  {id: 123} }"
>
    home
</router-link>

◾️$router.pushバージョン

index.vue
<button
    type="button"
    @click="$router.push({ name: 'post-id', params: {id: 123} })"
>
    home
</button>

✍️書き方パターン
・pathはurlをそのまま書く
・nameは追加でparams指定

✍️実際の書き方
・name
 URLの/を-にする
 _id.vueはidにする
・path

index.vue
 { path: 'hoge/hoge' }
 または
 { path: `hoge/${変数}`}

 

queryの追加

【path + query を使った書き方】

【飛びたいURL】

localhost:3000/post?id=123

【ディレクトリ 】

file
pages/
--| post/
-----| index.vue

◾️router-linkバージョン

index.vue
<router-link
    :to="{ path: '/post?id=123'}"
>
    home
</router-link>

◾️$router.pushバージョン

index.vue
<button
    type="button"
    @click="$router.push({ path: 'post?id=123'})"
>
    home
</button>

【nama + query を使った書き方】

【飛びたいURL】

localhost:3000/post?userId=123

【ディレクトリ 】

index.vue
pages/
--| post/
-----| index.vue

◾️router-linkバージョン

index.vue
<router-link
    :to="{ name: 'post', query: {userId: 123} }"
>
    home
</router-link>

◾️$router.pushバージョン

index.vue
<button
    type="button"
    @click="$router.push({ name: 'post', query: {userId: 123} })"
>
    home
</button>

まとめ

すごく簡単にまとめると
この2点が分かれば基礎は⭕️です!

・nameとpathが
 ディレクトリ のどこにあたるか
・params, queryはURLのどこにあたるか

記事が公開したときにわかる様に、
note・Twitterフォローをお願いします?

https://twitter.com/aLizlab

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

Vueのプロジェクトを作成してみるだけの記事

初めに

Vueのプロジェクト作成だけで躓いたを書いた際にそもそも古いバージョンのvue-cliを使っていたことを知り書き直しました。

VueJS触れるときのテンプレートとして作りました。
プロジェクト作成→ローカルでの実行→テストの実行 ができることを目標とします。

実施環境

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.3
BuildVersion:   19D76

$ node -v
v13.9.0

$ npm -v
6.14.2

Vueを使えるようにするまで

npmを使ってVueCLIをインストールする

(今回はグローバルインストールしていない)

mkdir VueJsProjects
cd VueJsProjects
npm init -y
npm install @vue/cli

Vueのパスを通す

sed -i '' 's/\"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"/\"vue\": \"vue\"/g' package.json

プロジェクトを作成する

以下の設定でプロジェクトを作成していきます。

$ npm run vue create hogehoge
Vue CLI v4.2.3
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Linter, Unit, E2E
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a linter / formatter config: Basic
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Pick a unit testing solution: Jest
? Pick an E2E testing solution: Cypress
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? Yes
? Save preset as: hogehoge_preset
? Pick the package manager to use when installing dependencies: Yarn

...(中略)

?  Successfully created project portfolio.
?  Get started with the following commands:

 $ cd hogehoge
 $ yarn serve

unittest参考:https://vue-test-utils.vuejs.org/ja/guides/choosing-a-test-runner.html
E2E参考:https://qiita.com/os1ma/items/5429cd8e12ac43a6a803

実行の前に

yarnを使っていないのでインストールから始めます。

$ brew install yarn
$ yarn --version
1.22.4

実行

cd hogehoge
yarn serve

image.png

Git管理

gitリポジトリは自動的に作成されている…。

$ git status
On branch master
nothing to commit, working tree clean

自動テスト

unittest

$ yarn test:unit
yarn run v1.22.4
$ vue-cli-service test:unit
 PASS  tests/unit/example.spec.js
  HelloWorld.vue
    ✓ renders props.msg when passed (29ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.007s
Ran all test suites.
✨  Done in 5.50s.

e2eテスト

$ yarn test:e2e

image.png
image.png
画面テスト自動化いいね!

後処理

pushするならする

git remote add origin [作成済みのリポジトリを使用]
git push -u origin master

まとめ

普通に、簡単に、VueJsのテスト実行までできました。
前回のようにバージョンミスとかで無駄に時間を取られないように注意していきたいですね。

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

【Circle CI】Nuxt.jsのdotenvを設定して環境変数をSTGとPRDで出し分けする

Nuxt.jsで自動デプロイする時にSTGとPRDを出し分ける

現在開発のプロジェクトではNuxt.jsを利用していて、Circle CIを使ってGKEに対して自動デプロイをしています。

参考:https://qiita.com/arthur_foreign/items/6ac67596a98c0a60d6be

ただ、環境変数をSTGとPRDに分けるには不十分な手順だったため、備忘のため新しく記事を書くことにしました。

Circle CIで環境変数をSTGとPRD向けに設定する

CircleCI.png

Environment Variablesで、STGとPRD向けに作った環境変数を.envファイルに書き込むための布石を打っておきます。

別に分けられれば名前はどうでもいいんですが、以下の命名規則にしました。

  • STG環境で利用する環境変数 => STG_環境変数名
  • PRD環境で利用する環境変数 => PRD_環境変数名

Nuxt.jsの.envに環境変数を書き込むコマンド

Nuxt.jsのCSR時のAPIの向き先とSENDGRIDのAPI KEYを、STGとPRDで出し分けした際に以下のコマンドを書き込みました。

ECHO = echo

inject_envfile_stg:
    $(ECHO) API_URL_BROWSER=${STG_API_URL_BROWSER} > .env
    $(ECHO) SENDGRID_API_KEY=${STG_SENDGRID_API_KEY} >> .env
inject_envfile_prd:
    $(ECHO) API_URL_BROWSER=${PRD_API_URL_BROWSER} > .env
    $(ECHO) SENDGRID_API_KEY=${PRD_SENDGRID_API_KEY} >> .env

※Makefileを使っています。

参考:https://qiita.com/arthur_foreign/items/6ac67596a98c0a60d6be

以下の記事を参考にしました。

参考:https://blog-hello-world.web.app/posts/2019-12-07-nuxt-dotenv-module-circleci/

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

Docker上でVueを動かすときに環境変数が読まれない

なにが起きましたか

  • 環境
    • Docker上
    • @vue/cli
    • npm run build でビルド
    • http-server dist/ で配信

Vueのフロントエンドを作っている際,サーバサイドのAPIのエンドポイントを環境変数に格納して動かす方式を取っていた.
ローカルのビルドではちゃんと環境変数が読まれるが,Azure上にイメージをpushしたビルドでは環境変数が読まれないという状況

原因

原因は主に2つあった.

これは既にそのとおりにしており,VUE_APP_API_ENDPOINTにサーバ側URLを設定していた.しかし,それでも環境変数は読まれない.

  • Dockerfileで環境変数を設定していたが,ビルド後に環境変数を設定していた.

つまりこんな感じに書いていた

Dockerfile.production
FROM node:lts-alpine 

RUN npm install -g http-server && \
    npm install && \
    npm run build
EXPOSE 8000

ENV VUE_APP_API_ENDPOINT='https://hogehoge.net'
CMD [ "http-server", "dist", "-p", "8000", "-g", "-b" ]

なんとなく「環境変数はランタイムで読み込まれるもの」という思い込みが原因であった.加えて,ローカルでは npm run serve で動作していたため,これは実際にランタイムで(コマンドを叩いたタイミング)で環境変数が読み込まれており,何も問題がなかったこともある.
ちゃんとビルドコマンド前にENV ~~~を移動させると,環境変数を参照することができた.

結論

  • クライアントサイドかつDockerでの開発のときは,ENVをビルドコマンドの前に書こう!
    • 実行時に必要ないし,RUNのときに直接指定してもいいかもしれない.そのほうが意味的には良い
  • 思い込み怖いね
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vueのプロジェクト作成だけで躓いた

追記

記事内でvue-cliを使っていますが古いバージョンのようです。
@vue/cliを使用して再度書き直すつもりです。そしたら躓くこともないのかも…!
-> 書き直しました。すんなりできました。

初めに

VueJS触れるときのテンプレートとして作りました。
…がinitした状態のままテスト実行したら躓いたのでその対処法までです。

実施環境

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.3
BuildVersion:   19D76

Vueを使えるようにするまで

npmを使ってVueCLIをインストールする

(今回はグローバルインストールしていない)

mkdir VueJsProjects
cd VueJsProjects
npm init -y
npm install vue-cli

Vueのパスを通す

sed -i '' 's/\"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"/\"vue\": \"vue\"/g' package.json

プロジェクトを作成する

npm run vue init webpack hogehoge

? Project name hogehoge
? Project description vue project
? Author hogehoge@mail.com
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Set up unit tests Yes
? Pick a test runner jest
? Setup e2e tests with Nightwatch? Yes
? Should we run `npm install` for you after the project has been created? (recom
mended) npm

... # インストール開始

To get started:

  cd hogehoge
  npm run dev

実行

cd hogehoge
npm run dev

image.png

Git管理

ここではGitを使いバージョン管理を行う

git init
git add .
git commit -m "first commit."

CI

CI/CDについても気になったので試してみる

npm test

セキュリティエラーでFAILに…。

 FAIL  test/unit/specs/HelloWorld.spec.js
  ● Test suite failed to run

    SecurityError: localStorage is not available for opaque origins

調べてみるとjestのバージョンの問題の可能性があるらしい。

test/unit/jest.conf.js
module.exports = {
  verbose: true,
  testURL: "http://localhost/",
  ...
}

上記を追加して再度実行

npm test
...
PASS  test/unit/specs/HelloWorld.spec.js
  HelloWorld.vue
    ✓ should render correct contents (23ms)

...

Running:  default e2e tests

Error retrieving a new session from the selenium server

Connection refused! Is selenium server started?
{
  value: {
    message: 'session not created: Chrome version must be between 71 and 75\n' +
...

jestは通ったがe3eでエラー。
chromedriverのバージョンをチェックする

$ npm list | grep chromedriver
├─┬ chromedriver@2.46.0
$ npm info chromedriver versions
[
  ...
  '2.46.0',  '73.0.0',   '74.0.0',
  '75.0.0', '75.0.1', '75.1.0',  '76.0.0',  '76.0.1',   '77.0.0',
  '78.0.0', '78.0.1', '79.0.0',  '79.0.1',  '79.0.2',   '79.0.3',
  '80.0.0', '80.0.1'
]

chromedriverをアップデートする。
chromeは普段最新版しか使わないのでドライバーも最新版を使うようにする。

sed -i '' 's/\"chromedriver\": \"^2.27.2\"/\"chromedriver\": \"latest\"/g' package.json
npm install -dev
npm list | grep chromedriver
├─┬ chromedriver@80.0.1

アップデートが完了したので再度実行

npm test
Running:  default e2e tests
{ parser: "babylon" } is deprecated; we now treat it as { parser: "babel" }.
 ✔ Element <#app> was visible after 103 milliseconds.
 ✔ Testing if element <.hello> is present.
 ✔ Testing if element <h1> contains text: "Welcome to Your Vue.js App".
 ✔ Testing if element <img> has count: 1

OK. 4 assertions passed. (8.794s)

テストが実行できるようになったので後処理。

git add .
git commit -m "hoge"
git remote add origin [作成済みのリポジトリを使用]
git push -u origin master

まとめ(というか感想)

Vueをインストールしてテスト&実行するだけですが割と手順が必要でした。
(そのままテストくらいパスするようにならないかな…?:thinking:
解決してまとめてみるとこれくらいの分量ですがnpmをあまり触っていなかったこともあり結構ハマりました。

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

vuetifyのスクロールイベントでトップへ戻るボタンを作る

vuetifyにはデフォルトでスクロールイベントを起こす機能があり、その機能を組み合わせることによりトップへ戻るボタンを作ることができます。

vue.jsでは「vue-go-top」というページ戻り専用のライブラリーはありますが、今回はvuetifyのみを利用して作成します。

クリックしたらTopに戻る

vuetifyには$vuetify.goTo()と指定するだけでスクロールイベントを起こすことができます。
スクローリングディレクティブ

<v-btn @click="$vuetify.goTo(target, options)"></v-btn>

こちらに0をいれると、クリックしたときに一番上まで戻ります。

<v-btn @click="$vuetify.goTo(0)"></v-btn>

scriptに記入する

$vuetify.goTo(0)を下記のようにscriptに記入することでtemplate側をすっきりできます。

<v-btn @click="toTop"></v-btn>
methods: {
  toTop () {
    this.$vuetify.goTo(0)
  }
}

スクロールしたら表示される

こちらはv-scrollを使用します。

スクロールで呼び出す関数をセットします。

<v-btn
  v-scroll="onScroll"
  @click="$vuetify.goTo(0)">
</v-btn>

※デフォルトはウィンドウですが、スクロールの変更を監視するターゲットは任意のIDセレクターに変更できます。

methodsに記入していく

onScroll関数に記入。
typeof window === 'undefined'はターゲットのデフォルトがwindowの場合使用。
window.pageYOffsetで垂直スクロール量を取得target.scrollTopも同様です。

methods: {
  onScroll (e){
    if (typeof window === 'undefined') return
    const top = window.pageYOffset ||   e.target.scrollTop || 0
  }
}

表示・非表示の設定

v-showで表示・非表示を切り替えます。
さきほどのスクロール値を取得してfabに格納。指定の値にきたら表示するようにします。

<v-btn
  v-scroll="onScroll"
  v-show="fab"
  @click="$vuetify.goTo(0)">
</v-btn>
data: () => {
  return {
    fab: false
  };
},
methods: {
  onScroll (e){
    if (typeof window === 'undefined') return
    const top = window.pageYOffset ||   e.target.scrollTop || 0
    this.fab = top > 500
  }
}

すべてまとめて表示する

さきほどの機能をまとめ、装飾やアニメーションを追加するとのようなソースになります。
少し動きも付けたかったのでtransitionを使ってみました。

<transition name="fade">
  <v-btn 
    v-scroll="onScroll"
    v-show="fab"
    fab
    dark
    fixed
    bottom
    right
    color="primary"
    @click="toTop">
    <v-icon>fas fa-angle-up</v-icon>
  </v-btn>
</transition>

<script>
export default {
  data: () => {
    return {
      fab: false
    };
  },
  methods: {
    onScroll (e){
      if (typeof window === 'undefined') return
      const top = window.pageYOffset ||   e.target.scrollTop || 0
      this.fab = top > 500
    },
    toTop () {
      this.$vuetify.goTo(0)
    }
  }
}
</script>

<style scoped>
.fade-enter-active, .fade-leave-active {
  transition: 0.5s;
} 
.fade-enter, .fade-leave-to {
  opacity: 0;
  transform: scale(0);
}
</style>

これで外部ライブラリを使わずvuetifyの機能のみでページへ戻るボタンが作れます。

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

NFCシールを活用して自動打刻ツールを(個人的に)作ってみた話

はじめに

今回はNFCシールを使用して会社の自動打刻システムを、完全に自分用で作ります!

要件定義

なぜつくるか?

現在、弊社の勤怠は、エクセルで管理されています。
実際の打刻フローとしては、

  1. 出社したら出社時刻をエクセル開いて手動で打刻
  2. 保存
  3. 退社するときに退社時刻をエクセル開いて手動で打刻
  4. 保存

。。。
毎日エクセルポチポチするの面倒すぎる!!!!!!!!!

作業自体も面倒なのに、何日か打刻を忘れるとまあ面倒臭いことになります。

せっかくIT企業にいるんだからいろいろスマートにやりたい...
ということで、今回の自動打刻システムの開発を決意しました。

どう作るか?

今回開発する自動打刻システムでは、NFCシールを活用していきます。

処理の流れとしては、

  1. NFCシールにスマホをかざして専用のWEBサイトを表示する
  2. WEBサイトから自動打刻システムにリクエストを投げる
  3. 打刻する

といった感じにしようかと思います。

NFCシールにスマホかざすのとリクエストを投げるところにWEBサイト表示をはさんでいるのは、
意図しない打刻を防ぐためです。

クライアント側で打刻される時刻の確認、出社なのか退社なのかの選択できた方が、
手順は増えますが確実かなあということでワンクッションはさみました。

また、現状では個人用なのでユーザーの識別は行いません。

どう使うか?

想定される使用フローは下記のとおりです。

  1. 出社したらデスクのどこかしらに貼ったNFCシールにスマホをかざす
  2. 表示されるWEBサイトで打刻時間を確認、出社ボタンを押す
  3. (退社時も同じ)

かなりスマート...!(な気がする)

使用技術

インフラはAWSの各サービスを利用します。

メイン処理の部分にはLambda、エクセルファイル(勤怠管理)はS3に保存します。

サーバーサイドにnode.js、WEBフロントエンドにはVue.jsを使用しつつ、HTTP通信はaxiosを使用します。

なぜNFCシールを使うか?

ただ使ってみたかった。

実は今回の開発、個人的にNFCシールを使ったアプリを作ってみたかったので、NFCシールありきで考えていました。

スマホかざすだけで打刻できるのステキじゃん...

なぜnode.jsか?

一番の理由は、Lambdaがnode.jsで書けるからです笑

他にも
java, ruby, pythonなどなど、いろんな言語で書くことができます。

フロントエンド開発に興味があり、日頃からJavaScriptを勉強しているので、
サーバーサイドもJavaScriptで書こう!ということでnode.jsを選びました。

なぜLambdaか?

Lambdaとは、AWSが提供するサーバレスアーキテクチャを構築するためのサービスです。

通常は、EC2インスタンスは常時存在し、アプリケーションも常時起動されているのですが、Lambdaはリクエストが送られてきたときのみインスタンスを生成→アプリケーションを実行→インスタンスを破棄という挙動をします。

今回作成するアプリは常時起動している必要もないので、コストを抑える意味でもLambdaが適しているのではないかと考えました。

なぜVue.jsか?

個人的に使い慣れているのでフロントはVue.jsで書きます。

と言っても、現在時刻を表示するのと、ボタンを二つ配置するだけなので全く難しいことはしません笑

強いて言えば、ローディングのアニメーションを作り込むくらいでしょうか...。

HTTP通信はaxiosを使用します。

設計

アーキテクチャ図

アーキテクチャの全体像としては、下記の通りです。

Image from Gyazo

構成は至ってシンプルで、
HTTPリクエストをAPI Gatewayで受け付け、Lambdaに投げます。

勤怠を管理しているエクセルはS3においておき、Lambdaからそのエクセルファイルに書き込みをしていく感じです。

処理が完了すると、処理結果をSuccessかFailでクライアントに通知します。

アプリケーションの実装

自動打刻システム(node.js)実装

コードの全貌は下記のGitHubリポジトリを御覧ください。

GitHub リポジトリ

エクセルファイルの操作には、「xlsx-populate」というライブラリを使用しました。

最初は「xlsx」というライブラリを使って実装していましたが、このライブラリだと処理をして、保存するとマクロや書式が無効化された状態になってしまうのでつかえず...。

個人的にはドキュメントも「xlsx-populate」のほうが読みやすかったです!

処理としてはファイルを読み込んで、シートを指定して、セルを指定して値を書き込み、保存しているだけです。

弊社の勤怠表は月ごとにシートが分かれているので、処理の頭でDateオブジェクトを生成して、得られた各値でシートや記入するセルを判定しています。

また、弊社は30分ごとに勤務時間として打刻できるので、打刻する時刻を30分単位に変換する関数を用意しています。

今後もっと本格的に運用していくことになったら、このあたりで拡張の余地がありますね。

実装で苦労したのは非同期処理とAWS S3からファイルを取得して、書き込んだものをアップロードし直す処理のところ。

const params = {
  Bucket: 'バケット名',
  Key: 'キー'
}

s3.getObject(params, (err, data) => {
}

上記のように記述すれば、指定されたバケットのオブジェクト(ファイル)を取得できて、data変数に格納されます。

また、アップロードするときは、

const params = {
  Bucket: 'バケット名',
  Key: 'キー',
  Body: 'アップロードしたいファイル'
}

s3.putObject(params, (err, data) => {
})

でアップロードできます!

ここがnode.jsの情報がなかなか転がってなくて苦労しました。

取得も書き込みも注意点としては、取ってきたり送信するためには、データ形式に気をつけなければなりません。

今回僕は、これらの処理の前後にエクセルファイルをバッファーに変換する処理をはさみ、変換したものをparams変数のBodyとしています。

クライアントサイド(vue.js)実装

クライアントサイド(WEB)はVue.jsで作りました。

最終的には静的サイトとしてビルドして、Netlifyでホスティングします。

こちらは特に難しいことはしていません。

UIはVuetifyを使ったので適当に作った割には整っています。

スクショですが、下記のようになりました。

Image from Gyazo

打刻すると、vue-loading-templateを使用したアニメーションが流れて、レスポンスが帰ってくるとアラートが表示されます。

Image from Gyazo

(若干左によってるのはスクショが下手だからです...笑)

インフラ環境構築

構築したもの


いよいよインフラの構築に入ります。

今回は、メインのAPIをLambdaで動かします。

勤怠表(エクセルファイル)はS3にアップロードしておき、Lambdaから読み取り、書き込みを行います。

HTTPリクエストの受け口として、APIGatewayを配置します。

ここに想定されるリクエストがとんできたら、それをトリガーにLambda関数が動く仕組みにしていきます。

また、クライアントサイド(WEBアプリ)はNetlifyという静的サイトのホスティングサービスを利用します。

Netlifyに関しては後日別記事で言及します。

ハマったポイント


私はインフラ超初心者なので、インフラ構築でかなりつまづきました...。

LambdaからS3のファイルをとってこれない

作成したLambdaに正しくロールを付与していなかったため、アクセス権限 is 何の状態が1時間くらい続きました...。


Lambda関数(メインAPI)が非同期処理になっていて肝心の処理を行う前にLambdaが終了してしまっていた

今回使用した「xlsx-populate」は非同期処理をすることが前提のライブラリです。

恥ずかしながら、node.jsだけでなく非同期処理の知識も乏しく、Lambdaはエラーなく終了するのに肝心の処理が実行できてない...。

という状態で約5日間潰しました。

エラー箇所の切り出しが下手だったなあと反省しています。

いろんな記事や書籍を読み漁りつつ、async awaitを駆使してなんとか解決しました。

CROS

実際にクライアントサイドからリクエストを投げる時にはまりました。

今までなーんとなくしか理解してなかったですが、これを機にしっかり学べました。

CROSに関しては別記事でまとめます。

実際につかってみた


実際の動画がこちら

明日から出社と退社が楽しみになりそう。

(ちょっと処理は遅いですが)個人的にほぼノンストレスに打刻できるようになったので満足です。

ただ、本当にきちんと勤怠をつけるためには小難しい会社のルールがあるみたいなので、そのうちきちんとしたものも作りたいです。

今のところはほぼ毎日きっちり定時に退社しているので細かい調整はそんなに必要なさそう...だと思ってます笑

おわりに

NFCさいこう!!!!!たのしい!!!!!

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

Trello風Webアプリケーションを作成してみた

作ったもの

最近、プログラミングから少し離れていたので、思い出すこともかねてTrello風のWebアプリケーションを作ってみた。

vue-trello - Google Chrome 2020_03_17 3_05_51.png

▼デモ( https://x-color.github.io/vue-trello
demo.gif

▼完成品のリポジトリ

使用技術

フロントエンド

フロントエンドはSPAとなっており、Vue.jsで実装している。

  • Vue.js: JavaScriptフレームワーク
  • Vuex: Vue.js用状態管理ライブラリ
  • Vue Router: SPA構築用のルーター
  • Vuetify: Vue.jsのマテリアルデザインコンポーネントフレームワーク
  • Vue.Draggable: ドラッグアンドドロップ処理用ライブラリ

バックエンド

バックエンドはAPIサーバーとなっており、Go言語で実装している。

  • Go言語
  • GORM: Go言語用ORMライブラリ
  • Echo: Go言語用Webフレームワーク
  • jwt-go: Go言語用JWTを扱うライブラリ

実装内容(カードを動かす処理)

今回のアプリケーションで実装したカードを動かす処理の概要を以下で紹介していく。

基本的な実装

今回はカードを動かす処理に、Vue.Draggableを用いているため、draggable タグで動かしたいものを囲むだけで実装可能。
以下の例は、fruits 配列をドラッグアンドドロップで自由に並び替える処理。

<template>
    <draggable v-model="fruits">
       <!-- ここの要素がドラッグアンドドロップ可能になる -->
       <div v-for="(v, i) in fruits" :key="i">{{ v }}</div>
    </draggable>
</template>

<script>
import draggable from 'vuedraggable'

export default {
    components: {
        draggable,
    },
    data() {
        return {
            fruits: [
                "apple",
                "banana",
                "cherry"
            ],
        }
    }
}
</script>

Vuexで管理しているデータを並び替える

今回の場合は、カードのデータや並び順をVuex内で管理しているため、Vuex内のデータを並び替える必要がある。
公式のREADMEに記載されている通り、computed内からVuexのstateを呼び出し、Setterを用いて更新することで対応可能。
シンプルな配列を並び替えたいときは、以下のようにするだけで並び変え可能。

<template>
    <draggable v-model="list">
       <div v-for="(v, i) in list" :key="i">{{ v }}</div>
    </draggable>
</template>

<script>
import draggable from 'vuedraggable'

export default {
    components: {
        draggable,
    },
    computed: {
        list: {
            get() {
                return this.$store.state.list
            },
            set(value) {
                this.$store.commit('updateList', value)
            },
        },
    },
}
</script>

今回作成したアプリでは、カードを並び替えた際に一部データの更新を行う必要があったので、以下のようにメソッドを呼び出し、データの更新処理を行ったあとにデータの移動を反映させる形にした。

computed: {
    lists: {
        get() {
            return this.getListsByBoardId(this.id); // list の配列を取得
        },
        set(value) {
            this.moveList(value); // list が移動した際に行う処理を実施
        },
    },
}

実際には、移動したデータを追跡し、順番を保持している変数値の更新とAPIサーバーとの通信などを実施している。

動かせるものを指定する

<draggable> で囲った要素は基本的にすべて、ドラッグ可能となってしまう。そのため、動かせないものを一緒にタグで囲わなければならない場合、動かしたいものを指定する必要がある。例えば今回の場合は、カードを追加するための「+」ボタンのカードを動かしたくなかった。

以下は失敗例のサンプル。<draggable>の中に動かしたいカードと動かしたくない「+」ボタンが入ってしまっている。そのため、このままだとボタンがドラッグ可能となってしまう。

<draggable v-model="lists">
    <v-col v-for="(list, i) in lists" :key="i" cols="auto">
        <card-list :id="list.id" />
    </v-col>

    <!-- カード追加ボタン -->
    <v-col cols="auto">
        <v-btn>
            <v-icon>mdi-plus</v-icon>
        </v-btn>
    </v-col>
</draggable>

これを改善したのが以下のサンプル。Vue.Draggableでは、draggable 属性を用いて、動かしたいものと動かしたくないものを対象のclass属性で判別することが可能。

<!-- dragable属性(draggable=".item")を付与 -->
<draggable v-model="lists" draggable=".item">
    <!-- ドラッグ可能にするためにclass属性(class="item")を付与 -->
    <v-col v-for="(list, i) in lists" :key="i" cols="auto" class="item">
        <card-list :id="list.id" />
    </v-col>

    <!-- itemクラスが付与されていないためドラッグ不可 -->
    <v-col cols="auto">
        <v-btn>
            <v-icon>mdi-plus</v-icon>
        </v-btn>
    </v-col>
</draggable>

上記の例では、draggable=".item"を用いて、itemクラスを付与されているもののみ移動可能としている。
これにより、「+」ボタンカードを除いたカードのみ移動可能とすることができる。

ドラッグ可能な箇所を指定する

先ほどのサンプルを再掲。
以下のコードだと、実はカード外部でドラッグ可能となってしまう。
ドラッグ対象が <v-col> となっているので、実際ドラッグしたい <card-list> 外部でもドラッグが可能となってしまい、UI的にカードではない部分でドラッグできてしまう。

<draggable v-model="lists" draggable=".item">
    <!-- ドラッグ対象は以下の要素となってしまう -->
    <v-col v-for="(list, i) in lists" :key="i" cols="auto" class="item">
        <!-- ドラッグしたいカード -->
        <card-list :id="list.id" />
    </v-col>

    <v-col cols="auto">
        <v-btn>
            <v-icon>mdi-plus</v-icon>
        </v-btn>
    </v-col>
</draggable>

改善した結果が以下のサンプルとなる。 handle 属性を用いて、ドラッグ判定を出す部分をclass属性で指定することが可能。

<!-- handle属性(handle=".handle")を付与 -->
<draggable v-model="lists" draggable=".item" handle=".handle">
    <v-col v-for="(list, i) in lists" :key="i" cols="auto" class="item">
        <!-- class属性(class="handle")を付与 -->
        <card-list :id="list.id" class="handle" />
    </v-col>

    <v-col cols="auto">
        <v-btn>
            <v-icon>mdi-plus</v-icon>
        </v-btn>
    </v-col>
</draggable>

上記の例では、handle=".handle"を用いて、handle クラスを付与されているものがドラッグ可能と判定している。これにより、<card-list> 内(カード)をドラッグした場合のみドラッグ可能とすることができる。

スムーズなドラッグアニメーションにする

デフォルトの移動時のアニメーションだと、動かしたというよりも瞬間移動した感じが出てしまう。そのため今回は、アニメーションを変更し、スムーズに動かした感じを出すこととした。

<!-- animation属性(:animation="300")を付与 -->
<draggable v-model="lists" draggable=".item" handle=".handle" :animation="300">
    <v-col v-for="(list, i) in lists" :key="i" cols="auto" class="item">
        <card-list :id="list.id" class="handle" />
    </v-col>

    <v-col cols="auto">
        <v-btn>
            <v-icon>mdi-plus</v-icon>
        </v-btn>
    </v-col>
</draggable>

animation属性を用いてアニメーションの時間を変更している。今回は時間を多めにとることにより、動いている感じを出している。アニメーションも属性を一つ追加すればよいだけなのでとても簡単にできる。

最後に

久々のプログラミングだったので、細かなところなどを結構忘れていて、実装に時間がかかってしまった。

また、初めてドラッグアンドドロップを実装したが、Vue.Draggableを用いることで簡単に実装することができた。ドラッグアンドドロップを実装したい場合はとてもおすすめ。

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

GoとVue.jsでTrello風Webアプリケーションを作成してみた

作ったもの

最近、プログラミングから少し離れていたので、思い出すこともかねてTrello風のWebアプリケーションを作ってみた。

vue-trello - Google Chrome 2020_03_17 3_05_51.png

▼デモ( https://x-color.github.io/vue-trello
demo.gif

▼完成品のリポジトリ

使用技術

フロントエンド

フロントエンドはSPAとなっており、Vue.jsで実装している。

  • Vue.js: JavaScriptフレームワーク
  • Vuex: Vue.js用状態管理ライブラリ
  • Vue Router: SPA構築用のルーター
  • Vuetify: Vue.jsのマテリアルデザインコンポーネントフレームワーク
  • Vue.Draggable: ドラッグアンドドロップ処理用ライブラリ

バックエンド

バックエンドはAPIサーバーとなっており、Go言語で実装している。

  • Go言語
  • GORM: Go言語用ORMライブラリ
  • Echo: Go言語用Webフレームワーク
  • jwt-go: Go言語用JWTを扱うライブラリ

実装内容(カードを動かす処理)

今回のアプリケーションで実装したカードを動かす処理の概要を以下で紹介していく。

基本的な実装

今回はカードを動かす処理に、Vue.Draggableを用いているため、draggable タグで動かしたいものを囲むだけで実装可能。
以下の例は、fruits 配列をドラッグアンドドロップで自由に並び替える処理。

<template>
    <draggable v-model="fruits">
       <!-- ここの要素がドラッグアンドドロップ可能になる -->
       <div v-for="(v, i) in fruits" :key="i">{{ v }}</div>
    </draggable>
</template>

<script>
import draggable from 'vuedraggable'

export default {
    components: {
        draggable,
    },
    data() {
        return {
            fruits: [
                "apple",
                "banana",
                "cherry"
            ],
        }
    }
}
</script>

Vuexで管理しているデータを並び替える

今回の場合は、カードのデータや並び順をVuex内で管理しているため、Vuex内のデータを並び替える必要がある。
公式のREADMEに記載されている通り、computed内からVuexのstateを呼び出し、Setterを用いて更新することで対応可能。
シンプルな配列を並び替えたいときは、以下のようにするだけで並び変え可能。

<template>
    <draggable v-model="list">
       <div v-for="(v, i) in list" :key="i">{{ v }}</div>
    </draggable>
</template>

<script>
import draggable from 'vuedraggable'

export default {
    components: {
        draggable,
    },
    computed: {
        list: {
            get() {
                return this.$store.state.list
            },
            set(value) {
                this.$store.commit('updateList', value)
            },
        },
    },
}
</script>

今回作成したアプリでは、カードを並び替えた際に一部データの更新を行う必要があったので、以下のようにメソッドを呼び出し、データの更新処理を行ったあとにデータの移動を反映させる形にした。

computed: {
    lists: {
        get() {
            return this.getListsByBoardId(this.id); // list の配列を取得
        },
        set(value) {
            this.moveList(value); // list が移動した際に行う処理を実施
        },
    },
}

実際には、移動したデータを追跡し、順番を保持している変数値の更新とAPIサーバーとの通信などを実施している。

動かせるものを指定する

<draggable> で囲った要素は基本的にすべて、ドラッグ可能となってしまう。そのため、動かせないものを一緒にタグで囲わなければならない場合、動かしたいものを指定する必要がある。例えば今回の場合は、カードを追加するための「+」ボタンのカードを動かしたくなかった。

以下は失敗例のサンプル。<draggable>の中に動かしたいカードと動かしたくない「+」ボタンが入ってしまっている。そのため、このままだとボタンがドラッグ可能となってしまう。

<draggable v-model="lists">
    <v-col v-for="(list, i) in lists" :key="i" cols="auto">
        <card-list :id="list.id" />
    </v-col>

    <!-- カード追加ボタン -->
    <v-col cols="auto">
        <v-btn>
            <v-icon>mdi-plus</v-icon>
        </v-btn>
    </v-col>
</draggable>

これを改善したのが以下のサンプル。Vue.Draggableでは、draggable 属性を用いて、動かしたいものと動かしたくないものを対象のclass属性で判別することが可能。

<!-- dragable属性(draggable=".item")を付与 -->
<draggable v-model="lists" draggable=".item">
    <!-- ドラッグ可能にするためにclass属性(class="item")を付与 -->
    <v-col v-for="(list, i) in lists" :key="i" cols="auto" class="item">
        <card-list :id="list.id" />
    </v-col>

    <!-- itemクラスが付与されていないためドラッグ不可 -->
    <v-col cols="auto">
        <v-btn>
            <v-icon>mdi-plus</v-icon>
        </v-btn>
    </v-col>
</draggable>

上記の例では、draggable=".item"を用いて、itemクラスを付与されているもののみ移動可能としている。
これにより、「+」ボタンカードを除いたカードのみ移動可能とすることができる。

ドラッグ可能な箇所を指定する

先ほどのサンプルを再掲。
以下のコードだと、実はカード外部でドラッグ可能となってしまう。
ドラッグ対象が <v-col> となっているので、実際ドラッグしたい <card-list> 外部でもドラッグが可能となってしまい、UI的にカードではない部分でドラッグできてしまう。

<draggable v-model="lists" draggable=".item">
    <!-- ドラッグ対象は以下の要素となってしまう -->
    <v-col v-for="(list, i) in lists" :key="i" cols="auto" class="item">
        <!-- ドラッグしたいカード -->
        <card-list :id="list.id" />
    </v-col>

    <v-col cols="auto">
        <v-btn>
            <v-icon>mdi-plus</v-icon>
        </v-btn>
    </v-col>
</draggable>

改善した結果が以下のサンプルとなる。 handle 属性を用いて、ドラッグ判定を出す部分をclass属性で指定することが可能。

<!-- handle属性(handle=".handle")を付与 -->
<draggable v-model="lists" draggable=".item" handle=".handle">
    <v-col v-for="(list, i) in lists" :key="i" cols="auto" class="item">
        <!-- class属性(class="handle")を付与 -->
        <card-list :id="list.id" class="handle" />
    </v-col>

    <v-col cols="auto">
        <v-btn>
            <v-icon>mdi-plus</v-icon>
        </v-btn>
    </v-col>
</draggable>

上記の例では、handle=".handle"を用いて、handle クラスを付与されているものがドラッグ可能と判定している。これにより、<card-list> 内(カード)をドラッグした場合のみドラッグ可能とすることができる。

スムーズなドラッグアニメーションにする

デフォルトの移動時のアニメーションだと、動かしたというよりも瞬間移動した感じが出てしまう。そのため今回は、アニメーションを変更し、スムーズに動かした感じを出すこととした。

<!-- animation属性(:animation="300")を付与 -->
<draggable v-model="lists" draggable=".item" handle=".handle" :animation="300">
    <v-col v-for="(list, i) in lists" :key="i" cols="auto" class="item">
        <card-list :id="list.id" class="handle" />
    </v-col>

    <v-col cols="auto">
        <v-btn>
            <v-icon>mdi-plus</v-icon>
        </v-btn>
    </v-col>
</draggable>

animation属性を用いてアニメーションの時間を変更している。今回は時間を多めにとることにより、動いている感じを出している。アニメーションも属性を一つ追加すればよいだけなのでとても簡単にできる。

最後に

久々のプログラミングだったので、細かなところなどを結構忘れていて、実装に時間がかかってしまった。

また、初めてドラッグアンドドロップを実装したが、Vue.Draggableを用いることで簡単に実装することができた。ドラッグアンドドロップを実装したい場合はとてもおすすめ。

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

「Scrapboxにコードを書いて実行する」を説明してみる

この記事は株式会社クロノス「~2020年春~勝手にやりますアドベントカレンダー」の12日目の記事です!

はじめに

今回の投稿はScrapboxのUserScriptテンプレートまとめに引き続き、Scrapboxネタです。(よっぽど好きだということです)

まずは以下のリンク先ページをご覧ください。
Scrapboxにコードを書いて実行する

なんとっ Scrapbox上に書いたJavaScriptのコードが実行されてるじゃないですか! すごい。UserScriptととはまた違ったことやってる!
自分もやりたいぃってことで、どうやって実現しているのか調べてみました。

Vue.jsタグにさせてもらいましたが、Vue.js自体は実演で使わせてもらっただけで、チュートリアルの域を出ていないです。ご注意ください。

知れること・知れないこと

知れること

  • Scrapbox上にコード記法で記載したJavaScriptのコードを実行して表示させる方法

知れないこと

  • Scrapbox上に書いたJavaScript以外(コンパイルが必要になるような言語)を実行させる方法
  • Scrapbox上に実行結果を埋め込む方法

仕組み

どうやって実現させているか紐解く鍵は、下のコードを実行のリンクの中身にあります。
遷移した後のURLを見るのでも構いませんが、
https://[アカウント名].github.io/[リポジトリ名]/?code=[ほにゃらら]/[ほにゃらら].jsとなっているはずです。

Tip1 : CDN

(他にもやりようはあるかとは思いますが)各種プログラムを実行するために、お馴染みのCDN(Contents Delivery Network)を利用します。

Tip2 : GitHub Pages

urlを見てもらったら分かるように、github.ioの静的ホスティングサービスであるGitHub Pagesを利用します。
(実際は静的ホスティングサービスであれば、何であっても構わないと思うのですが、今回は参考元のやり方のGitHub Pagesで説明させてもらいます)

Tip3 : ScrapboxのAPI

公式で大々的に説明があるAPIではありませんが、コード記法で書いた内容にアクセスできるAPIがあります。
形式 : https://scrapbox.io/api/code/[プロジェクト名]/[ページ名]/[付けたファイル名]
画面収録 2020-03-13 22.15.03.mov.gif
普段は上記のようにコード記法で書いたコードをコピーするために利用されます。
(APIのURLにアクセスすればブラウザ上にコードの中身が表示されます)

「Scrapboxにコードを書いて実行する」の仕組みを、一言で(ざっくり)言うなら
静的ホスティングしたサイトにScrapboxで書いたコードを返却するAPIを渡して、コード記法で書かれた該当のコードを書き込み、CDNを利用して実行する
となります。

実装方法〜〜ユースケースとともに〜〜

本家Scrapboxにコードを書いて実行するのように、動きのあるコードの方が、面白味があるとは思いますが、今回はVue.jsのチュートリアルのコードを実行してみます。

GitHub Pagesの準備(簡易説明)

  • Github上にリポジトリを作成する。
  • index.htmlファイルを作成する。
  • branch : gh-pagesを作成する
  • 後はrepositoryのURLにアクセスでindex.htmlの内容が表示される!

コードの全容

私が今回説明で使っているソースはこちらです。
フォルダ構成

├── index.html
└── index.js

Github上に置くファイルはGithub Pagesで準備したindex.htmlindex.jsだけ!!(簡単)
README.mdファイルは省略して記載しています。

index.js (ScrapboxのAPIのURLをGetパラメータから取得して、画面に読み込ませる)

ここが一番肝要なところですが、
本家様のコードをほぼほぼ流用しています。基本、本家様のコードを参照でお願いします。:bow:

本家様コード
ちなみにgh-pagesブランチとmasterブランチで内容が違っていたので、見比べて勉強させてもらいました。(jsだけでなくstyle読み込んだりなどなど)

今回Vue.jsのコードを動かしたい関係で、jQueryありきの部分については少し変更を加えています。
今回のindex.js

index.js
// jQueryお馴染みの「$」の部分
$(function(){

// 純粋なJavaScriptに変更
window.addEventListener('DOMContentLoaded', function(){

コードを見てもらったらわかりますが、JavaScriptでアクセスしたURLを解析して、
?code=の=以降の値(Getパラメータの値)を読み取って、その値をscriptタグとして追加する実装になっています。
(実行する際は?code=[ScrapboxのAPIのURL]としてアクセスしてください)

index.html (必要なCDNの読み込みや簡易のレイアウト記載)

今回はこんなかんじ。

index.html
<!DOCTYPE html>
<html>

<head>
    <title>Scrapboxでプログラミングの勉強をする</title>
    <!-- bulma -->
    <link href="https://cdn.jsdelivr.net/npm/bulma@0.8.0/css/bulma.min.css" rel="stylesheet">
    <link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
</head>

<div id="app">
    <app-template></app-template>
</div>

<!-- vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="./index.js"></script>

</html>

基本CDNと先ほどのindex.jsを読み込んでいるだけ!
CDNはここで自分の利用したいものをカスタマイズしましょう。
今回はVue.jsと表示の調整でBulmaを書きました。

ここまでで下準備は完了!

Scrapboxにコードを書いて実行

では、Scrapboxでコードを書いて実際に実行してみましょう。
コードはVue.jsのチュートリアルを参考に書いています。
Githubに挙げているコードは変更しない方向で、<app-template></app-template>をカスタム要素として利用した書き方に調整しています。

コード記法は拡張子「js」でファイル名書くようにしてください。

  • Hello World
 const Messages = {
     template:
      `<div class="hero">` +
      '<div class="hero-body has-text-centered">{{ message }}</div>' +
      '</div>',
     data: function() {
       return {
         message: 'Hello World!!',
       }
     }
 }

 new Vue({
   el: '#app',
   components: {
     'app-template': Messages
   }
 })

実行の様子。上部は切り取っていますが、実行すると新規タブが開きます。
画面収録 2020-03-14 21.33.44.mov.gif

※押しているボタンについてはおまけで後述します。やってることはhttps://[アカウント名].github.io/[リポジトリ名]/?code=[ScrapboxのAPIのURL]にアクセスするだけです。

Scrapboxのコードを実行しているだけなので、Scrapboxのコードを書き換えると、当然結果も変わります。
画面収録 2020-03-14 21.55.59.mov.gif

他の例も用意したので、載せておきます。

  • v-for
const BlogPost = {
    template:
        `<div class="hero">` +
        '<div class="hero-body has-text-centered">' +
        '<div v-for="post in posts" v-bind:key="post.id">' +
        '{{post.title}}' +
        '</div>' +
        '</div>' +
        '</div>',
    data: function () {
        return {
            posts: [
                { id: 1, title: 'My journey with Vue' },
                { id: 2, title: 'Blogging with Vue' },
                { id: 3, title: 'Why Vue is so fun' }
            ]
        }
    }
}

new Vue({
    el: '#app',
    components: {
        'app-template': BlogPost
    }
})

画面収録 2020-03-14 22.26.39.mov.gif

  • ボタン
 Vue.component('app-template',{
    data: function(){
        return {
            count1: 0,
            count2: 0
        }
    },
    template:
        '<div class="hero">'
        + '<div class="hero-body has-text-centered">'
        + '<button v-on:click="count1++">You clicked me {{count1}} times.</button>'
        + '<br>'
        + '<button v-on:click="count2++">You clicked me {{count2}} times.</button>'
        + '</div>'
        + '</div>'
 })

 new Vue({ el: '#app' })

画面収録 2020-03-14 22.28.26.mov.gif

アクセスするたびに同じ画面だけど違う結果が出てくる
というのはなかなかに面白いものです。
上記の3つのコードを続け様で実行した場合↓
画面収録 2020-03-15 0.32.54.mov.gif

どういった時に使える?

本家にも書いてありますが「プログラミング体験」として抜群です。
自分で勉強するにしても人に教えるにしても、文面と実行できるコードを共存して管理できるというのは、利点が多いのではないでしょうか。(いろいろな使い方ができそうです)

注意

言わずもがな、自分のコードは自分のGitHub Pages(あるいは別の静的ホスティングサービス)にアクセス・実行するようお願いします。

といっても他人のページだとCDNのカスタマイズもできないですし、自分で用意した方がいろいろ可能性が広がって楽しいと思います。

おまけ

開いているページ(前回はカードと書いていた)上のコード記法にアクセスするAPIを抽出して、https://[アカウント名].github.io/[リポジトリ名]/?code=[ScrapboxのAPIのURL]を開くUserScript作っているので、参考で載せておきます。
(今までのgif画像でも使っていました)

ScrapboxのUserScriptの詳しい説明については前回記事ScrapboxのUserScriptテンプレートまとめScrapboxのヘルプ参照ください。

下準備

前回記事の番外テンプレート(1)を作成するために、画像を用意して1つページを作ります。
スクリーンショット 2020-03-15 1.20.05.png

UserScript

UserScriptとはこんな感じ。

script.js
const GITHUB_REPOSITORY = 'https://[githubユーザ名].github.io/[リポジトリ名]';
const SCRAPBOX_URL = 'https://scrapbox.io';
const $appRoot = $('#app-container');
$appRoot.on('click', 'img[class="icon"]', e => {
    const $icon = $(e.target).closest('img[class="icon"]');
    const iconName = $icon.attr('title');
    // 「programming」アイコンの場合に処理を実行
    if (iconName === 'programming') {
        let codeUrl;
        $('a').each(function (index, atag) {
            let hrefStr = String($(atag).attr('href'));
            // getパラメータの作成
            if (hrefStr.startsWith('/api/code') && hrefStr.endsWith('js')) {
                codeUrl = (codeUrl == null) ?
                    'code=' + SCRAPBOX_URL + hrefStr
                    : codeUrl + '&code=' + SCRAPBOX_URL + hrefStr;
            }
        })
        console.log('呼び出し先コードのURL :' + codeUrl);
        window.open(GITHUB_REPOSITORY + '?' + codeUrl);
        return false;
    }
});

これで、Scrapboxの[programming.icon]アイコン記法)と書かれた場所をクリックすれば、プログラムの実行(条件を満たした状態でGitHub Pagesにアクセス)できます!!

※ScrapboxのUserScriptは自分にしか効かない(Scrapboxのヘルプ参照)ので、Publicで公開しているプロジェクトにおいて、閲覧者に実行してもらいたい場合等は、リンクをScrapbox上に書くようにしてください。

おわりの余談

前回のブログを書いていた頃含め、1年以上Scrapboxを書いてきたわけですが、アドベントカレンダーやろう! ってなったときも、内容考えるのすごく楽でした。
Scrapboxは項目と項目をつなげることで新たな発想が生まれたり、思考がクリアになったりと、使うほどにいろんな効果があるような気がしています。(個人の感想)

ちなみに……
Scrapboxでアウトプットするというのも一つですが、私個人として「Scrapboxの内容をまとめてブログに書く」使い方はこれからもしていくと思います。(私にとってScrapboxはネタ帳の色合いが濃いです)

以上です!

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

入門の次のステップに進めないVue.js学習履歴(随時更新)

概要

ドットインストールの「Vue.js入門」を実施してある程度Vue.jsをわかった気になった。
https://dotinstall.com/lessons/basic_vuejs_v2

しかし、実際にリリースされているVue.jsのソースを見るとさっぱりわからなかった。
このため、疑問点と調査経緯を自分のメモ目的でこの記事に残していく。

疑問点

yarn run xxx

package.jsonのscriptsで定義されたxxxを実行する。

"scripts": {
    "xxx": "~~~~~~~~", ←これを実行
    "yyy": "~~~~~~~~",
    :
    :
  },

■yarn runのドキュメントはこちら。
https://classic.yarnpkg.com/ja/docs/cli/run

app.use(nuxt.render)

expressのミドルウェアとしてNuxt.jsを使う。

 const express = require('express')
 const app = express()
  :
 app.use(nuxt.render)
  :

Node.jsの「ミドルウェア」という概念がいまいちわかっていない・・・。

■API: nuxt.render(req, res)
https://ja.nuxtjs.org/api/nuxt-render/

■ExpressのミドルでNuxt.jsを利用
https://www.wakuwakubank.com/posts/666-nuxtjs-express-middle/

module.exports={}

外部(別ファイル)から参照できるようにする。

module.exports = {
  mode: 'xxx',
  router: {
    base: '/yyy/'
  },

上記の定義をしたjsファイルをrequireすると、jsファイルの中身を参照できる。

■module.exportsとは何か、どうもわからなかったので実験してみた〜Node.jsにて外部moduleをrequireする〜
http://karoten512.hatenablog.com/entry/2018/01/28/191928

this.$store.dispatch(~~~)

「$store」はどこにも宣言されていない。
Vuex(ビューックス?)のステートオブジェクトとのこと。
セッションみないたもの??セッションよりは奥が深そう。

■Vuexステート
https://vuex.vuejs.org/ja/guide/state.html

■Vue.js + Vuexでデータが循環する全体像を図解してみた
https://qiita.com/m_mitsuhide/items/f16d988ec491b7800ace

this.$store.dispatch(~~~)その② dispatchについて

「$store.dispatch」でステートのactionを実行(らしい)
actionは非同期処理(らしい)

actionの実行とは何か?

this.$store.dispatch(~~~)その③ actionについて

「$store.dispatch」でステートのactionを実行するとしてactionとは何をするのか?
実態が不明。

\store\login.jsexport const actionsexport const mutationsがあった。
つまり「$store.dispatch」を実行すると、\store\login.jsexport const actionsのような気がしてきた。

async function() {const response = await this.$store.dispatch(~~~)}

asyncで非同期関数。
awaitでpromiseのresolveを実行。つまり、\store\login.jsのactionを非同期実行した結果がresponseに入る?
※このあたり、理解が曖昧。以下などを見て、なんとなく上記の理解。

 https://qiita.com/niusounds/items/37c1f9b021b62194e077

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