- 投稿日:2019-10-04T21:17:54+09:00
Laravel + Vue.js + Vuetifyでページネーションを実現する
バージョン
Laravel : 5.8
Vue.js : 2.5
Vuetify : 1.5作る画面
サーバーサイドにLaravel、フロントエンドにVue.js、デザインにVuetifyを使用して検索つきのページネーションを作ります。
データは何でもいいので、本を検索することにしました。
このような画面が出来上がります。
booksテーブルはtitle(タイトル)とpublishing_year(発行年)だけのシンプルなテーブルです。
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.jsconst 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.jsimport "./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.jsimport 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.jsimport 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.jsimport { 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/paginationsresources/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/colorsresources/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
一応これで完成です!めでたし!!
- 投稿日:2019-10-04T18:54:56+09:00
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>とすればよい。
- 投稿日:2019-10-04T13:21:34+09:00
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
を指定。
ホットリロード環境を作りたいのでfresh
をgo get
しています。myapp/docker/go/DockerfileFROM golang:1.13.1-alpine ENV GO111MODULE=on RUN apk update && \ apk add emacs curl git && \ go get github.com/pilu/freshVue.js
nodeのバージョンは、現時点(2019年10月)で最新の
8.16
。
vue-cli3を利用するので@vue/cli
をnpm install
しています。mysqpp/docker/vue/DockerfileFROM node:8.16-alpine RUN apk update && \ npm install -g npm && \ npm install -g @vue/clidocker-compose.ymlの中身(初期)
nginxの設定は後で足します。
まずは、GoとVue.jsのコンテナを作るところから始めていきたいので。docker-compose.ymlversion: '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ちなみに、
go
、vue
共に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.gopackage 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 tmpgo.modができましたね。
Ctr + d
とかでコンテナの外に出て、go.mog
ファイルの中身を確認すると以下のうようになっています。go.modmodule app go 1.13
では、Echoを導入していきます。
コンテナの外からで良いので、以下のようにmain.go
を編集します。
なんてことはない、Echoのクイックスタート(ほぼ)そのままです。main.gopackage 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にアクセスすると、以下のような画面が表示されます。
見事に世界に挨拶ができましたね。
ちなみに、
go.mod
はこんな感じになっています。go.modmodule 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の設定に入っていきます。
お好みで設定すれば良いと思いますが、今回は以下のようにします。Enterを無心で押していくと、以下のような感じで設定が始まります。
サクセスすると、以下のような表示になるかと思います。
ここまできたら、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です。
上記画面が出た状態で、localhost:8080にアクセスすると、以下のような画面が表示されます。
Vue.js Appの世界に無事、迎え入れられてもらうことができました。nginxのコンテナを作る
一旦、
docker-compose down
で、コンテナを落としておきます。
そして、docker-compose.yml
に追記&nginx.conf
を作ります。docker-compose.ymlversion: '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.confnginx.confworker_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 でアクセスしてみましょう。
この画面になったらOKです。Vue側からGo側へリクエストを送り、値を得る。
axios
を使って、GoのAPIを叩き値を取ってくることを想定して、もう少しファイルを編集していきます。axiosを使えるようにする。
axiosを使えるようにするため、
package.json
(assetsディレクトリ内にあるはずです)を編集します。
dependencies
の部分にaxiosを追加します(バージョンは、2019年10月最新のものにしてます)。
併せて、console.log()
が入っているときにWaringが出ないようにするため、esLintConfg
のrules
に、
"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.jsimport 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を叩く。
今回は超簡易的に、
- ブラウザで http://localhost にアクセス。
- APIが叩かれる(GET)。
- Go側からレスポンスを返す。
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 にアクセスしてみましょう。
(もしくは、リロードしてみましょう。)画像のように、レスポンスが返ってきているのが確認できたらOKです。
あとは、返ってきた値を上手く調理するなどして、画面にレンダリングするとかしてみてみるといいんじゃないでしょうか。
(その辺は、余裕あったら続きを書こうと思います。記録としても残しておく意味で。)以上。
- 投稿日:2019-10-04T12:38:26+09:00
plunkerでvue その42
概要
plunkerでvueやってみた。
練習問題やってみた。練習問題
qiita apiを叩け。監視プロパティを使え。
成果物
https://embed.plnkr.co/UvjK0REGe5cogJHKJ7BH/
以上。
- 投稿日:2019-10-04T12:36:23+09:00
plunkerでvue その41
概要
plunkerでvueやってみた。
練習問題やってみた。練習問題
qiita apiを叩け。無限スクロールせよ。
成果物
https://embed.plnkr.co/xfzDmoQ7aos7JkHWKTIL/
以上。
- 投稿日:2019-10-04T12:07:44+09:00
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" } }
- 投稿日:2019-10-04T12:07:29+09:00
vue + laravel
axiosを使った通信
viewのaxiosを使用してTestsControllerのcreateメソッドに値を渡す。
またTestsControllerのcreateメソッドからviewに値を返し(res.data)viewで受け取っています。welcome.blade.phpaxios .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.phpRoute::get('/test', 'TestsController@index'); Route::get('/test/create', 'TestsController@create'); Route::post('/test/create', 'TestsController@create');バリデーション
1.バリデーション定義を作成
StoreBlogPostは適当な名前です。
cmdphp artisan make:request StoreBlogPostapp\Http\Requestsの中に生成される
- ルールの追加
StoreBlogPostpublic function rules() { // 必須かつ最大文字数10文字 return [ 'test' => 'required|max:10', ]; }参考資料:https://www.slideshare.net/ssuser817ccb/laravel-bladevuejs
- 投稿日:2019-10-04T11:12:53+09:00
v-bind:disabledで配列構文が書けなかった話
はじめに
2回目の投稿です。
分からないことだらけで勉強中なので、アウトプットの練習にQiitaで投稿しています。
何か間違いなどあれば教えてください。やろうとしたこと
Vueでフォームのバリデーションを作りたかった。
- 名前に禁止文字(ゼロ幅スペースとか)が含まれているか確認するnameValid
- 名前欄を含む入力項目に不備があるか確認する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
- 投稿日:2019-10-04T11:12:42+09:00
plunkerでvue その40
概要
plunkerでvueやってみた。
練習問題やってみた。練習問題
qiita apiを叩け。
成果物
https://embed.plnkr.co/inGmlRc7wpqWrasWqPSg/
以上。
- 投稿日:2019-10-04T08:25:56+09:00
vue.js コンテンツを右寄せ、中央揃えにする
要素を右寄せにする
参考
bootstrap-vue-layout
https://bootstrap-vue.js.org/docs/components/layout/Bootstrap4に用意されているクラス【flex編】
https://webnetamemo.com/coding/bootstrap4/201906138320もう迷わない!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を使用。