20191004のvue.jsに関する記事は10件です。

Laravel + Vue.js + Vuetifyでページネーションを実現する

バージョン

Laravel : 5.8
Vue.js : 2.5
Vuetify : 1.5

作る画面

サーバーサイドにLaravel、フロントエンドにVue.js、デザインにVuetifyを使用して検索つきのページネーションを作ります。
データは何でもいいので、本を検索することにしました。
このような画面が出来上がります。
book_list.png

booksテーブルはtitle(タイトル)とpublishing_year(発行年)だけのシンプルなテーブルです。
book_table.png

Vuetifyとは

簡単に言うとCSSを使わずに、独自のHTMLタグでデザインを完成させてしまえる優れものです。
その他にもVue.jsで使えるマテリアルデザインコンポーネントはQuasarやBootstrapVueもあるみたいですが、何となくVuetifyが良さげな雰囲気を出しているので採用しました。
https://vuetifyjs.com/ja/

インストール

まずはVue.jsとVuetifyを使う上で必要なライブラリをインストールします。
前述の通りVuetifyは1系を使います。

npm install vue-router vuex vuetify@1 css-loader material-design-icons-iconfont vuex-persistedstate

ディレクトリ構成

主なファイルの配置です。
LaravelとVue.jsの一般的な構造なので特に問題ないと思います。

├── app
│   ├── Http
│   │   └── Controller 
│   │       └── BookController.php
│   └── Book.php
├── resources
│   └── js
│       ├── components
│       │   ├── Book.vue
│       │   ├── BookList.vue
│       │   └── SearchArea.vue
│       ├── app.js
│       ├── bootstrap.js
│       ├── router.js
│       ├── store.js
│       ├── util.js
│       └── App.vue
└── routes
    ├── api.php
    └── web.php

余談ですがresources/js/componentsにBook.vueとBookList.vueがあるのが腑に落ちない方はAtomic Designがピッタリです。
https://uxdaystokyo.com/articles/glossary/atomic-design/

ルーティング

ここからはコードをどんどん載せていきます。

routes/web.php
<?php

Route::get('/{any?}', function () {
    return view('index');
})->where('any', '.+');

画面の変化はJavaScriptで行うことになるので、どのURLでもindex.blade.phpを呼びます。

resources/views/index.blade.php
<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>vuetify pagination</title>
  <script src="{{ mix('js/app.js') }}" defer></script>
</head>
<body>
  <div id="app"></div>
</body>
</html>

Laravel Mixでコンパイルしたapp.jsを読み込みます。
VuetifyがあるのでCSSは使いません。

webpack.mix.js
const mix = require("laravel-mix");

mix.js("resources/js/app.js", "public/js")
    .version();

webpack.mix.jsはこれだけです。
ここでもCSSは不要です。

routes/api.php
<?php

Route::get('/books', 'BookController@index')->name('books');

apiのルーティングは本を検索するためのものです。

JavaScript

resources/js/app.js
import "./bootstrap";
import Vue from "vue";

import Vuetify from "vuetify";
Vue.use(Vuetify);

import "vuetify/dist/vuetify.min.css";
import "material-design-icons-iconfont/dist/material-design-icons.css";

import router from "./router";
import store from "./store";
import App from "./App.vue";

new Vue({
    el: "#app",
    router,
    store,
    components: { App },
    template: "<App />"
});

app.jsにVuetifyを使用するための記載をします。

resources/js/router.js
import Vue from "vue";
import VueRouter from "vue-router";

import BookList from "./components/BookList.vue";

Vue.use(VueRouter);

const routes = [
    {
        path: "/",
        component: BookList
    }
];

const router = new VueRouter({
    mode: "history",
    routes
});

export default router;

router.jsでルートパスにアクセスしたらBookList.vueが呼ばれるように設定します。

resources/js/store.js
import Vue from "vue";
import Vuex from "vuex";
import createPersistedState from "vuex-persistedstate";

Vue.use(Vuex);

const store = new Vuex.Store({
    plugins: [createPersistedState()]
});

export default store;

store.jsのvuex-persistedstateはブラウザをリロードしてもVuexのストアを保持してくれるもので、ログイン認証の永続化でよく使われるみたいです。
今回は特に使いませんが便利なので載せときましょう。

resources/js/bootstrap.js
import { getCookieValue } from "./util";

window.axios = require("axios");

// Ajaxリクエストであることを示すヘッダーを付与する
window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";

window.axios.interceptors.request.use(config => {
    // クッキーからトークンを取り出してヘッダーに添付する
    config.headers["X-XSRF-TOKEN"] = getCookieValue("XSRF-TOKEN");

    return config;
});

window.axios.interceptors.response.use(
    response => response,
    error => error.response || error
);
resources/js/util.js
/**
 * クッキーの値を取得する
 * @param {String} searchKey 検索するキー
 * @returns {String} キーに対応する値
 */
export function getCookieValue(searchKey) {
    if (typeof searchKey === "undefined") {
        return "";
    }

    let val = "";

    document.cookie.split(";").forEach(cookie => {
        const [key, value] = cookie.split("=");
        if (key === searchKey) {
            return (val = value);
        }
    });

    return val;
}

bootstrap.jsはとutil.jsはCSRF対策のためのトークンをクッキーから取り出して、リクエストに含める処理です。
こちらのサイトを参考にさせてもらっています。
https://www.hypertextcandy.com/vue-laravel-tutorial-authentication-part-3/
素晴らしいサイトでかなりお世話になりました!

Vue

resources/js/App.vue
<template>
  <v-app>
    <v-content tag="div">
      <v-container fluid>
        <RouterView />
      </v-container>
    </v-content>
  </v-app>
</template>

やっとVuetifyのタグが登場しました。
<v-app>で囲む必要があります。
公式を見れば便利なタグがたくさんあるので、こちらを参考に。
https://vuetifyjs.com/ja/components/paginations

resources/js/components/BookList.Vue
<template>
  <div>
    <h3>Book List</h3>
    <search-area @search="searchBooks($event)"></search-area>
    <v-layout justify-end>
      <v-pagination v-model="page" :length="length"></v-pagination>
    </v-layout>
    <v-layout wrap>
      <v-flex sm6 pa-2 v-for="(book, key, index) in books" :key="index">
        <book :title="book.title" :publishingYear="book.publishing_year"></book>
      </v-flex>
    </v-layout>
  </div>
</template>

<script>
// Book.vueとSearchArea.vue(検索エリア)を読み込みます。
import Book from "../components/Book.vue";
import SearchArea from "../components/SearchArea.vue";
export default {
  data() {
    return {
      books: [],    // 一覧データ
      page: 1,      // 表示中のページ(v-paginationにバインド)
      length: 0,    // ページネーションのリンクの数(v-paginationのprops)
      urlParams: "" // 検索パラメータ
    };
  },
  methods: {
    // 検索ボタンをクリックしたら呼ばれる
    async searchBooks(params) {
      // 検索パラメータをURLに付与してapiを叩く
      this.urlParams = params;
      let url = "/api/books?page=" + this.page + "&" + this.urlParams;
      const response = await axios.get(url);
      // 戻り値をデータに代入すれば表示が変わってくれます
      let books = response.data.data;
      this.books = books;
      this.length = response.data.last_page;
    }
  },
  watch: {
    // ページネーションのリンクをクリックするとpageが変わる。
    // pageを監視して、変更されたらsearchBooksを実行
    page: function(newPage) {
      this.searchBooks(this.urlParams);
    }
  },
  components: {
    Book,
    SearchArea
  }
};
</script>

BookList.Vueが今回の肝になるファイルで、ページネーションの処理はここで扱います。
pageというVue.jsで保持しているデータがトリガーになっていて、pageが変更されたら本を検索するapiが発火して、booksというデータが変更され、画面の表示が変わるという流れです。
通常のマルチページアプリケーションではページネーションのリンクのURLに直接遷移することが多いので、一番の違いはここではないでしょうか。

resources/js/components/Book.Vue
<template>
  <v-card class="indigo lighten-5">
    <v-card-title class="pa-1">タイトル:{{title}}</v-card-title>
    <v-card-text class="pa-1">発行年:{{publishingYear}}</v-card-text>
  </v-card>
</template>

<script>
export default {
  props: {
    title: {
      type: String,
      required: true
    },
    publishingYear: {
      type: Number,
      required: true
    }
  }
};
</script>

Book.vueはpropsにタイトルの発行年があるだけで簡単です。
<v-card>のclassは色をつけるためのもで、Vuetifyが提供してくれます。
たくさんあるので、これだけあれば困ることはないでしょう。
https://vuetifyjs.com/ja/styles/colors

resources/js/components/SearchArea.Vue
<template>
  <div>
    <v-layout wrap>
      <v-flex sm4 pa-2>
        <v-text-field v-model="searchForm.title" label="タイトル"></v-text-field>
      </v-flex>
      <v-flex sm4 pa-2>
        <v-text-field v-model="searchForm.publishing_year" label="発行年"></v-text-field>
      </v-flex>
      <v-flex pa-2>
        <v-btn @click="clickHandler">検索</v-btn>
      </v-flex>
    </v-layout>
  </div>
</template>

<script>
const querystring = require("querystring");
export default {
  data() {
    return {
      searchForm: {
        title: "",
        publishing_year: ""
      }
    };
  },
  methods: {
    clickHandler() {
      let params = querystring.encode(this.searchForm);
      this.$emit("search", params);
    }
  }
};
</script>

イベント名をsearch、引数をparams(検索パラメータ)にして検索ボタンにクリックイベントを定義しています。
paramsは検索項目に入力されている値をquerystringで文字列に変換してます。
title=A&publishing_year=2018みたいな文字列になります。

PHP

Laravel側で本を検索する処理を作ります。

app/Book.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
}

Modelはあれば良いので中身は空です。

app/Http/Controllers/BookController.php
<?php

namespace App\Http\Controllers;

use App\Book;
use Illuminate\Http\Request;

class BookController extends Controller
{
    public function index(Request $request)
    {
        $per_page = 5; // 1ページあたりの件数
        $input = $request->all();
        $books = Book::select('id', 'title', 'publishing_year');
        if (!empty($input['publishing_year'])) {
            $books = $books->where('publishing_year', $input['publishing_year']);
        }
        if (!empty($input['title'])) {
            $books = $books->where('title', 'LIKE', "%{$input['title']}%");
        }
        $books = $books->paginate($per_page);

        return response()->json($books);
    }
}

検索してます。それだけですw

一応これで完成です!めでたし!!

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

Vue.jsの"なければならない"

コンポーネント

dataは関数でなければならない

Vue.component('my-component', {

...

   data: function () {
      return {
         message: 'Hello Vue.js'
      }
   }
})

テンプレートの要素は一つでなければならない

templatel: '<span>a</span><span>b</span>'

↑はNG

template: '<div><span>a</span><span>b</span></div>'

のように大きく一つにまとめればOK

.nativeで発火

コンポーネント内でv-onを使いたいときは、.nativeをつけなければならない.

<my-component v-on:click="eventClick"></my-component>

↑ではクリックしても、eventClickは実行されない。
この場合実行するには、子コンポーネントで$emitを使って発火しなければならない。

これを回避するには、

<my-component v-on:click.native="eventClick"></my-component>

とすればよい。

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

Go(Echo) + Vue.js + nginx の環境をDocker Composeで立てる。

はじめに

goa、ginと触ったので、Echoあたりも触ってみようと思ったのと、自分自身、サーバーサイドもフロントエンドも一括で担当することが多いこともあり、「どうせだ、docker環境でフロントエンドも含めて環境を作ってみっか。」というのが始まりです。

GoコンテナはAPIを配信、Vue.jsでAPIを叩いて、値を画面にレンダリング。
みたいな想定でやっています。また、nginx噛ませてルーティングさせてます。

駄文だったらすいません。
先に言っておくと、長文です。

なお、以下のようにしています。

Go

  • Go Modules
  • ホットリロード

を利用してます。

Vue.js

  • vue-cli3
  • aixos

を利用してます。

環境

  • Mac OS X 10.14.6(Mojave)
  • Docker version 19.03.2
  • docker-compose version 1.24.1

※ ベースの環境だけ記述しておきます。GoのバージョンなどはDockerfileに記述してますので。

手順

初めのファイル構造

こっからスタートします。
nginxは後から設定するのでmyapp/etc/nginx配下は一旦空にしています。

myapp
├── docker
│   ├── go
│   │   └── Dockerfile
│   └── vue
│       └── Dockerfile
├── docker-compose.yml
└── etc
    └── nginx
        └── .

各Dockerfileの中身

Go

非常にシンプルです。
Goのバージョンは1.13。
Go Modulesを利用するため、ENV GO111MODULE=onを指定。
ホットリロード環境を作りたいのでfreshgo getしています。

myapp/docker/go/Dockerfile
FROM golang:1.13.1-alpine

ENV GO111MODULE=on

RUN apk update && \
    apk add emacs curl git && \
    go get github.com/pilu/fresh

Vue.js

nodeのバージョンは、現時点(2019年10月)で最新の8.16
vue-cli3を利用するので@vue/clinpm installしています。

mysqpp/docker/vue/Dockerfile
FROM node:8.16-alpine

RUN apk update && \
    npm install -g npm && \
    npm install -g @vue/cli

docker-compose.ymlの中身(初期)

nginxの設定は後で足します。
まずは、GoとVue.jsのコンテナを作るところから始めていきたいので。

docker-compose.yml
 version: '3'
 services:
   vue:
     build:
       context: ./docker/vue
     container_name: myapp-vue
     ports:
       - 8080:8080
     volumes:
       - .:/app
     working_dir: /app
     tty: true
     # command: sh -c "cd assets && yarn install && yarn serve"

   go:
     build:
       context: ./docker/go
     container_name: myapp-go
     ports:
       - 8082:8082
     volumes:
       - .:/go/src
     working_dir: /go/src/app
     tty: true
     # command: fresh

ちなみに、govue共にcommandがコメントアウトしているのは、一旦コンテナで作業する必要があるので、コメントアウトしています。
goは、Go Modulesの初期設定をしてからホットリロードを設定しないとエラーになります(なりました)。
vueは、コンテナ内でvue createをしたいので、コメントアウトしています。

コンテナ立ち上げ

まずはなにはともあれ、ビルドします。

$ docker-compose build

※ npm周りでWARNが出る可能性がありますが、ここは無視します。
 

up -dでバックグラウンド立ち上げをします(オプション-d無くてもいいですが、その場合は以降は別タブで作業してください)。

$ docker-compose up -d

 

コンテナが立ち上がっているか確認。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                               NAMES
9897f0c5c15c        nginx               "nginx -g 'daemon of…"   9 seconds ago       Up 7 seconds               0.0.0.0:10080->80/tcp               myapp-nginx
9e8c34dacba8        kaikairanban_go     "/bin/sh"                11 seconds ago      Up 9 seconds               0.0.0.0:8082->8082/tcp              myapp-go
7178d2a496dc        kaikairanban_vue    "docker-entrypoint.s…"   40 seconds ago      Up 39 seconds              0.0.0.0:8080->8080/tcp              myapp-vue

この時点でappディレクトリがmyappディレクトリ内にできているので、ls -laとかで確認してみてください。

Goのコンテナを設定していく

appディレクトリに移動して、main.goファイルを作ります。

$ cd app && emacs main.go

※ emacsの部分は、vimでもなんでもいいです。筆者はemacsを使っているのでこうなります。
 

main.goの中身は一旦こんな感じにしておきます。

main.go
package main

import (
       "fmt"
)

func main () {
     fmt.Println("Hello World !!")
}

 
Goのコンテナに入ります。

$ docker exec -it myapp-go /bin/sh
/go/src/app #
 
# コンテナ内で ls -la で確認してみるとこんな感じになっているはず。
/go/src/app # ls -la
total 4
drwxr-xr-x    4 root     root           128 Oct  3 08:35 .
drwxr-xr-x    5 root     root           160 Oct  3 08:25 ..
-rw-r--r--    1 root     root            90 Oct  3 08:35 main.go
drwxr-xr-x    2 root     root            64 Oct  3 08:25 tmp

 
コンテナ内でGo Modulesの初期設定をします。

/go/src/app # go mod init
go: creating new go.mod: module app

/go/src/app # ls -la
total 8
drwxr-xr-x    5 root     root           160 Oct  3 08:41 .
drwxr-xr-x    5 root     root           160 Oct  3 08:25 ..
-rw-r--r--    1 root     root            20 Oct  3 08:41 go.mod
-rw-r--r--    1 root     root            90 Oct  3 08:35 main.go
drwxr-xr-x    2 root     root            64 Oct  3 08:25 tmp

go.modができましたね。
 
Ctr + dとかでコンテナの外に出て、go.mogファイルの中身を確認すると以下のうようになっています。

go.mod
module app

go 1.13

 
では、Echoを導入していきます。
コンテナの外からで良いので、以下のようにmain.goを編集します。
なんてことはない、Echoのクイックスタート(ほぼ)そのままです。

main.go
package main

import (
       "net/http"
       "github.com/labstack/echo"
)

func main () {
     e := echo.New()
     e.GET("/", func(c echo.Context) error {
        return c.String(http.StatusOK, "Hello, World!")
     })
     e.Logger.Fatal(e.Start(":8082"))
     // e.Startの中はdocker-composeのgoコンテナで設定したportsを指定してください。
}

 
main.goが編集できたら、docker-compose.ymlのgoコンテナの記述部分のcommandのコメントアウトを外します。

docler-compose.yml
# docker-compose.ymlの一部抜粋
go:
  build:
    context: ./docker/go
  container_name: myapp-go
  ports:
    - 8082:8082
  volumes:
    - .:/go/src
  working_dir: /go/src/app
  tty: true
  command: fresh # ここのコメントアウトを外す。

保存したら、docker-compose upで更新します(一旦、一つ前のコンテナ内作業後、docker-compose downでコンテナを停止しておいても良いです)。

以下のような状態になったら、Echo導入完了&ホットリロードもOnになりました。

$ docker-compose up
myapp-vue is up-to-date
Recreating myapp-go ... done
Recreating myapp-nginx ... done
Attaching to myapp-vue, myapp-go, myapp-nginx
myapp-go | 8:53:07 runner      | InitFolders
myapp-go | 8:53:07 runner      | mkdir ./tmp
myapp-go | 8:53:07 runner      | mkdir ./tmp: file exists
myapp-go | 8:53:07 watcher     | Watching .
myapp-go | 8:53:07 main        | Waiting (loop 1)...
myapp-go | 8:53:07 main        | receiving first event /
myapp-go | 8:53:07 main        | sleeping for 600 milliseconds
myapp-go | 8:53:08 main        | flushing events
myapp-go | 8:53:08 main        | Started! (5 Goroutines)
myapp-go | 8:53:08 main        | remove tmp/runner-build-errors.log: no such file or directory
myapp-go | 8:53:08 build       | Building...
myapp-go | 8:53:14 runner      | Running...
myapp-go | 8:53:14 main        | --------------------
myapp-go | 8:53:14 main        | Waiting (loop 2)...
myapp-go | 8:53:14 app         |
myapp-go |    ____    __
myapp-go |   / __/___/ /  ___
myapp-go |  / _// __/ _ \/ _ \
myapp-go | /___/\__/_//_/\___/ v3.3.10-dev
myapp-go | High performance, minimalist Go web framework
myapp-go | https://echo.labstack.com
myapp-go | ____________________________________O/_______
myapp-go |                                     O\
myapp-go | 8:53:14 app         | ⇨ http server started on [::]:8082

上記の状態で、localhost:8082にアクセスすると、以下のような画面が表示されます。
スクリーンショット 2019-10-03 12.21.43.png

見事に世界に挨拶ができましたね。

ちなみに、go.modはこんな感じになっています。

go.mod
module app

go 1.13

require (
        github.com/labstack/echo v3.3.10+incompatible
        github.com/labstack/gommon v0.3.0 // indirect
        golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc // indirect
)

Vueのコンテナを設定していく

コンテナが立ち上がっている状態で、vueのコンテナに入ります。

$ docker exec -it myapp-vue /bin/sh
/app #

vue-cliでvue環境を設定していきます。

/app # vue create assets

上記コマンドを打つと、質問形式で色々聞かれます。

?  Your connection to the default yarn registry seems to be slow.
   Use https://registry.npm.taobao.org for faster installation? (Y/n) Y ←Yesにします。

と聞かれた後、Vueの設定に入っていきます。
お好みで設定すれば良いと思いますが、今回は以下のようにします。

スクリーンショット 2019-10-03 12.41.11.png
スクリーンショット 2019-10-03 12.45.38.png

Enterを無心で押していくと、以下のような感じで設定が始まります。
スクリーンショット 2019-10-03 12.45.54.png

サクセスすると、以下のような表示になるかと思います。
スクリーンショット 2019-10-03 18.10.01.png
 
ここまできたら、Ctr + dでコンテナを抜けます。
docker-compose downで一旦コンテナを落としておきます。
そして、docker-compose.ymlのvueコンテナの部分でコメントアウトにしていた部分のコメントアウトを外します。

vue:
  build:
    context: ./docker/vue
  container_name: myapp-vue
  ports:
    - 8080:8080
  volumes:
    - .:/app
  working_dir: /app
  tty: true
  command: sh -c "cd assets && yarn install && yarn serve" # ここのコメントアウトを外す。

 
バックグラウンドでコンテナを立ち上げた後、vueコンテナのlogだけを表示させてみます。

$ docker-compose up -d
$ docker-compose logs -f vue

 
以下のような感じでvueコンテナが立ち上がればOKです。
スクリーンショット 2019-10-03 18.17.43.png
 
上記画面が出た状態で、localhost:8080にアクセスすると、以下のような画面が表示されます。
スクリーンショット 2019-10-03 18.20.06.png
Vue.js Appの世界に無事、迎え入れられてもらうことができました。

nginxのコンテナを作る

一旦、docker-compose downで、コンテナを落としておきます。
そして、docker-compose.ymlに追記&nginx.confを作ります。

docker-compose.yml
version: '3'
services:
  vue:
    build:
      context: ./docker/vue
    container_name: myapp-vue
    ports:
      - 8080:8080
    volumes:
      - .:/app
    working_dir: /app
    tty: true
    command: sh -c "cd assets && yarn install && yarn serve"

  go:
    build:
      context: ./docker/go
    container_name: myapp-go
    ports:
      - 8082:8082
    volumes:
      - .:/go/src
    working_dir: /go/src/app
    tty: true
    command: fresh
  # こっから下を追加
  nginx:
    image: nginx
      depends_on:
      - go
    container_name: myapp-nginx
      ports:
      - 80:80
      environment:
      - TZ=Asia/Tokyo
      volumes:
      - ./etc/nginx/nginx.conf:/etc/nginx/nginx.conf
nginx.conf
worker_processes auto;

events {
  worker_connections 1024;
}

http {
  server {
    listen 80;

    location /api/ {
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Host $host;
      proxy_pass http://go:8082/;
    }

    location / {
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Host $host;
      proxy_pass http://vue:8080/;
    }
  }
}

 
準備ができたら、docker-compose up -dでコンテナを立ち上げます。
docker-compose logs -fなどで、go、Vueどちらのコンテナも立ち上がって、準備ができたのを確認できたら、http://localhost でアクセスしてみましょう。
スクリーンショット 2019-10-03 18.20.06.png
この画面になったらOKです。

Vue側からGo側へリクエストを送り、値を得る。

axiosを使って、GoのAPIを叩き値を取ってくることを想定して、もう少しファイルを編集していきます。

axiosを使えるようにする。

axiosを使えるようにするため、package.json(assetsディレクトリ内にあるはずです)を編集します。
dependenciesの部分にaxiosを追加します(バージョンは、2019年10月最新のものにしてます)。
併せて、console.log()が入っているときにWaringが出ないようにするため、esLintConfgrulesに、
"no-console": "off"を追加します。

package.json
{
  ...
  "dependencies": {
    "core-js": "^2.6.5",
    "vue": "^2.6.10",
    "axios": "^0.19.0"
  },
  ...
  ...
  "eslintConfig": {
    ...
    "rules": {
      "no-console": "off"
    },
    ...
  },
  ...
}

 
グローバルにaxiosを使えるように、main.jsに登録をします。

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

// ここから
import axios from 'axios'
Vue.prototype.$axios = axios
// ここまでを追加

Vue.config.productionTip = false

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

ファイルが編集できたら、docker-compose restart vueで、設定を更新します。

axiosで、GoのAPIを叩く。

今回は超簡易的に、

  1. ブラウザで http://localhost にアクセス。
  2. APIが叩かれる(GET)。
  3. Go側からレスポンスを返す。
  4. console.log()を使って、ブラウザのコンソール画面でレスポンスの中身を確認する。

ということを行います。

では、App.vueを編集していきます。
Vueのcreatedフックのなかで、axiosを使うように記述します。
(変更箇所のあるscriptタグのブロックだけ以下に表示させてます。)

App.vue
// <template> のブロックがある

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'app',
  components: {
    HelloWorld
  },
  // createdの中でaxiosを使います。get()の中のURLは、nginx.confで設定してるので、 /api/ になっています。
  created () {
    this.$axios.get('http://localhost/api/')
      .then(response => {
        console.log(response)
      })
  }
}
</script>

// <style> のブロックがある

できたら、ブラウザの開発者ツールでコンソールタブを開いて、 http://localhost にアクセスしてみましょう。
(もしくは、リロードしてみましょう。)

スクリーンショット 2019-10-04 12.51.09.png

画像のように、レスポンスが返ってきているのが確認できたらOKです。
あとは、返ってきた値を上手く調理するなどして、画面にレンダリングするとかしてみてみるといいんじゃないでしょうか。
(その辺は、余裕あったら続きを書こうと思います。記録としても残しておく意味で。)

以上。

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

plunkerでvue その42

概要

plunkerでvueやってみた。
練習問題やってみた。

練習問題

qiita apiを叩け。監視プロパティを使え。

成果物

https://embed.plnkr.co/UvjK0REGe5cogJHKJ7BH/

以上。

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

plunkerでvue その41

概要

plunkerでvueやってみた。
練習問題やってみた。

練習問題

qiita apiを叩け。無限スクロールせよ。

成果物

https://embed.plnkr.co/xfzDmoQ7aos7JkHWKTIL/

以上。

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

Vue CLIプロジェクトがネストされるとgitHooksが動作しない問題の解決

問題

Vue CLIでプロジェクトを作る際にLint and fix on commitにチェックを入れたが、コミットをしてもリンターが動作しない。

原因

リポジトリの中にフロントエンド(Vue)用のディレクトリとサーバーサイド用のディレクトリがあったため。

解決方法

リポジトリのルートでgitHooksを呼び出せばよい。

リポジトリのルートでnpm init -y && npm i -D yorkie
yorkieはGit hookを手軽に記述できるhuskyからフォークされたもので、@vue/cli-serviceについてくる。

package.jsonにgitHooksを記述する。

{
  "name": "nesting-yorkie-example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "gitHooks": {
    // コミット時の動作を記述する
    "pre-commit": "cd 'ネストされたVueCLIプロジェクト' && node_modules/.bin/lint-staged"
  },
  "devDependencies": {
    "yorkie": "^2.0.0"
  }
}

サンプル

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

vue + laravel

axiosを使った通信

viewのaxiosを使用してTestsControllerのcreateメソッドに値を渡す。
またTestsControllerのcreateメソッドからviewに値を返し(res.data)viewで受け取っています。

welcome.blade.php
        axios
            .post('http://localhost/public/test/create', postParam)
            .then((res) => {
                console.log(res.data);
                alert('TestController@createから帰ってきたデータは' + res.data.test);
            }).catch((ex) => {
                console.log('failed');
            });

TestsController
<?php

namespace App\Http\Controllers;

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

class TestsController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        Log::info('Showing user profile for user: ');
        return view('welcome');
    }
    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create(Request $request)
    {
        Log::info('Showing user profile for user: ');
        $data = $request->all();

        return $data;
    }
}
web.php
Route::get('/test', 'TestsController@index');
Route::get('/test/create', 'TestsController@create');
Route::post('/test/create', 'TestsController@create');

バリデーション

1.バリデーション定義を作成

StoreBlogPostは適当な名前です。

cmd
php artisan make:request StoreBlogPost

app\Http\Requestsの中に生成される

  • ルールの追加
StoreBlogPost
public function rules()
    {
                // 必須かつ最大文字数10文字
        return [
            'test' => 'required|max:10',
        ];
    }

参考資料:https://www.slideshare.net/ssuser817ccb/laravel-bladevuejs

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

v-bind:disabledで配列構文が書けなかった話

はじめに

2回目の投稿です。
分からないことだらけで勉強中なので、アウトプットの練習にQiitaで投稿しています。
何か間違いなどあれば教えてください。

やろうとしたこと

Vueでフォームのバリデーションを作りたかった。

  1. 名前に禁止文字(ゼロ幅スペースとか)が含まれているか確認するnameValid
  2. 名前欄を含む入力項目に不備があるか確認するvalid

という、二種類のバリデーションをcomputedに作り、1に引っかかった場合はフォーム下に「登録できない文字が入っています」といった警告文を出し、1と2いずれかに引っかかっている時は「登録」のボタンが押せないようにしようとした。
タイトルの通り、登録ボタンのところでv-bind:disabled配列構文を用いて以下のように書こうとしたところ、上手くいかず。

v-bind:disabled="[!valid, !nameValid]"

原因

必要なデータがbooleanだから。

boolean型について

trueまたはfalseのどちらかのデータが必ず入ることが決まっているデータ型のこと。

改善案

論理演算子を使う。

v-bind:disabled="!valid || !nameValid"

→今度は上手くいったー

おわりに

そもそもVueのドキュメントに「v-bind:style 向けの配列構文は、同じ要素に複数のスタイルオブジェクトを適用することができます」としか書いてないんですよね…
そりゃあ上手くいかないわけです。boolean型についても全然理解できていませんでした。
もっと勉強します。

参考

【Java入門】booleanとBooleanの使い方(初期値も解説) https://www.sejuku.net/blog/41241
論理演算子 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_Operators

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

plunkerでvue その40

概要

plunkerでvueやってみた。
練習問題やってみた。

練習問題

qiita apiを叩け。

成果物

https://embed.plnkr.co/inGmlRc7wpqWrasWqPSg/

以上。

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

vue.js コンテンツを右寄せ、中央揃えにする

要素を右寄せにする

参考

bootstrap-vue-layout
https://bootstrap-vue.js.org/docs/components/layout/

Bootstrap4に用意されているクラス【flex編】
https://webnetamemo.com/coding/bootstrap4/201906138320

スクリーンショット 2019-10-04 8.07.36.png

もう迷わない!CSS Flexboxの使い方を徹底解説
https://webdesign-trends.net/entry/8148


b-container

親要素に指定する
flexboxの親要素(container)として扱われる
container以下の要素は全て子要素(item)になる

d-flex

flexboxを使用するためのクラス

justify-content-end

子要素を右寄せにするためのクラス

some_component.vue
<b-container class="d-flex justify-content-end">
  hoge
</b-container>

これで要素を右寄せに出来る。

中央揃えの場合は

justifiy-content-center

を使用。

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