- 投稿日:2019-05-02T22:59:47+09:00
初心者がVue.jsのVeeValidateでハマったこと
送信ボタンを押してもバリデートがかからない。
という問題。
フォーム自体にはリアルタイムでちゃんとバリデーションがかかる。
でも送信ボタンを押したらバリデーションスルーして進んじゃう。
なんでだ…。
VueやVeeValidateのインストールは割愛しますが、CDNで読み込んでいます。
new Vue({ el: '#valid', methods: { validate() { this.$validator.validateAll() .then((result) => { //ここにifとかでtureの場合falseの場合の処理を書かないといけなかった! if(result=== true) { trueの時の処理 } else{ falseの時の処理 } }); } } });なぜか巷の情報の多くではこの分岐させる処理がなくて、バリデーションスルーして次のページに行ってしまっていたので、一応そこでつまっている方のために残しておきます。
(もしかしたらCDN版特有でnpmとかなら必要ない処理なのかな…?)
- 投稿日:2019-05-02T22:02:48+09:00
Vue.js&Nuxt.jsで初めてアプリを自作したときに躓いた点
はじめに
Vue.js&Nuxt.js超入門(秀和システム)を読んで勉強したのでアプリを作った。
「囀暦」というアプリで「てんれき」と読む。Twitterでつぶやかれている内容の中で「○月○日にxxします!」という告知をカレンダー上にプロットするもの。以前にもRailsでちょこっと作っていたが今回改めて作り直してみた次第。教科書通り作るのとはわけが違う。エラー&エラーに悩まされましたのでここにまとめます。
構成
- Vue.js(フロント)
- Nuxt.js(バック)
- Firebase(認証)
また、ライブラリとして下記を使用。
- Materialize
- fullcalendar
初期設定
$ npx create-nuxt-app tenreki > Generating Nuxt.js project in /Users/hoshito/RubymineProjects/tenreki ? Project name tenreki ? Project description My primo Nuxt.js project ? Use a custom server framework none ? Choose features to install (Press <space> to select, <a> to toggle all, <i> to invert selection) ? Use a custom UI framework none ? Use a custom test framework none ? Choose rendering mode spa ? Author name hoshito ? Choose a package manager npmディレクトリ構成
初めて扱うフレームワークだったので何をどこに置いたらいいのか、あのファイルどこにいったっけと探すのが大変だった。
nuxt.config.jsはいろいろ書いたので全部のせておく。
nuxt.config.jsimport pkg from './package' require('dotenv').config(); const { CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET } = process.env; export default { mode: 'spa', /* ** Headers of the page */ head: { title: pkg.name, meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: pkg.description } ], script: [ { src: "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js" }, { src: "https://unpkg.com/popper.js"}, { src: "https://unpkg.com/tooltip.js"} ], link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, { rel: "stylesheet", href: "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"} ] }, /* ** Customize the progress-bar color */ loading: { color: '#fff' }, /* ** Global CSS */ css: [ ], /* ** Plugins to load before mounting the App */ plugins: [ { src: '~/plugins/calendar.js', ssr: false } ], /* ** Nuxt.js modules */ modules: [ '@nuxtjs/dotenv', ], /* ** Build configuration */ build: { /* ** You can extend webpack config here */ extend(config, ctx) { config.node = { fs: "empty" // TwitterAPIを使うのに必要 }; } }, serverMiddleware: [ '~/server' ], env : { CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET } }躓いたところを一つずつ記載。
環境変数を使う
npm install --save @nuxtjs/dotenv
- nuxt.config.jsに情報を記載
dotenv
とかenv
とか書かれているところ- この設定だけでけっこう散らばって記載しているけどこれがベストなのかは疑問
- .envファイルに環境変数を記載(このファイルはコミットしない)
- 下のような感じ
CONSUMER_KEY="xxx" CONSUMER_SECRET="xxx" ACCESS_TOKEN_KEY="xxx" ACCESS_TOKEN_SECRET="xxx"
サーバ起動前に環境変数を設定する方法もありそうだったが、毎回設定するよりは外部ファイルに置いておく方が好みなのでこの方法を取った。
localStorage, sessionStorageを使用する際はSPAモードで実行
これは書籍にもあった。SPAとSSRの違いがよく分かっていないので(サーバレンダリングの有無だけ?)もう少し勉強する必要がある。
今回はsessionStorageにTwitterのトークン情報を保存している。
https://developer.twitter.com/en/docs/basics/authentication/guides/securing-keys-and-tokens.html
We would not normally recommend using LocalStorage, although there may be a few exceptions to this.
Using SessionStorage is normally more preferable than LocalStorage when thinking in terms of security.
Twitterのdevelopページにこう書かれていたので、localStorageではなくsessionStorageを使った。
TwitterAPIを使用するにあたって
npm install --save twitter
npm install --save axios fs net tls
(依存するライブラリたち)fsが使えずに下記のようなエラーが出た。
ERROR in ./node_modules/request/lib/har.js Module not found: Error: Can't resolve 'fs' in '/Users/hoshito/RubymineProjects/tenreki/node_modules/request/lib'fsはファイルシステムのことで、SPAつまりクライアント側でファイルシステムモジュールを使おうとしてエラーになっていた。
下のように書くとエラーを回避できた。
nuxt.config.jsextend(config, ctx) { config.node = { fs: "empty" // TwitterAPIを使うのに必要 }; }SPAだとこれが動かずSSRだとこれが動かず、というのが多く混乱してしまう。
node-sassは(今だけ?)使えない
sassを使いたくて
npm install node-sass
をしたところ脆弱性エラーで進めなかった。調べてみると最近出たエラーっぽい。解決策はいろいろ出てきている。https://github.com/sass/node-sass/issues/2625
https://zatsuzen.com/nodejs/node-sass/package.jsonで
node-gyp
を書き換えろ、という内容であるが、私のpackage.jsonは以下のようなものであり、どこをどう書き換えればよいのか分からずsassの導入を断念しました。package.json{ "name": "tenreki", "version": "1.0.0", "description": "My primo Nuxt.js project", "author": "hoshito", "private": true, "scripts": { "dev": "nuxt", "build": "nuxt build", "start": "nuxt start", "generate": "nuxt generate" }, "dependencies": { "@fullcalendar/core": "^4.1.0", "@fullcalendar/daygrid": "^4.1.0", "@fullcalendar/vue": "^4.1.0", "@nuxtjs/dotenv": "^1.3.0", "axios": "^0.18.0", "cross-env": "^5.2.0", "firebase": "^5.10.1", "fs": "0.0.1-security", "net": "^1.0.2", "nuxt": "^2.4.0", "sass": "^1.19.0", "tar": "^4.4.8", "tls": "0.0.1", "twitter": "^1.7.1" }, "devDependencies": { "nodemon": "^1.18.9" } }ビジネスロジック
serverMiddlewareを使った。
https://ja.nuxtjs.org/api/configuration-servermiddleware/
page/list.vue
から自身にAPIを叩くように使っている。page/list.vueの一部methods: { getTweets(token, secret) { const self = this; const params = {token: token, secret: secret}; axios.post("/api/tweets", params).then(res => { self.events = res.data; }).catch(err => { console.log(err); }); },server/index.jsの全部import express from 'express' import bodyParser from 'body-parser' import {getClient, getTweetInfoForFullCalendar} from '../plugins/twitter' const app = express() // requestでjsonを扱えるように設定 app.use(bodyParser.urlencoded({extended: true})) app.use(bodyParser.json()) app.post('/tweets', (req, res) => { let client = getClient(req.body.token, req.body.secret); // TODO: リクエストパラメータに入れる let params = {owner_screen_name: "hoshitostar", slug: "Love", count: 200}; client.get('lists/statuses', params).then(tweets => { let result = getTweetInfoForFullCalendar(tweets); res.send(result); }).catch((errors) => { // TODO: error処理 console.log(errors); }); }) module.exports = { path: '/api', handler: app }これも最初全然リクエストを投げられず、投げることができたと思ったらリクエストパラメータ取れなくて苦労した。
server/index.js
はRailsでいう(別にRailsじゃなくてもいいけど)Controllerの役割を担っていると思ったので、ロジックはplugins/twitter
に入れた。本当はclient.get...
の部分も含めて外に出そうと思ったけど、client.getの非同期処理でハマってしまったのでやめにした。plugins/twitterの一部// TwitterAPIのクライアントクラスを取得 function getClient(token, secret) { const Twitter = require('twitter'); return new Twitter({ consumer_key: process.env.CONSUMER_KEY, consumer_secret: process.env.CONSUMER_SECRET, access_token_key: token, access_token_secret: secret }); } // --- 省略 --- export {getClient, getTweetInfoForFullCalendar}余談
2019/04/08から技術系のBlogとTwitterを始めてます。このQiitaの記事はブログに記載していたものをまとめたものになります。
Blog: https://hoshitostar.hatenablog.jp/
Twitter: @hoshitostarQiita vs ブログの話題はたまに見るけどやっぱり難しいですね。今回はまとまった記事になったのでQiitaに投稿しました。もっと良い書き方があれば教えていただけると嬉しいです。
アウトプットがんばるぞー
- 投稿日:2019-05-02T21:06:38+09:00
Vueでドロップダウンメニューを作成する
目標
下記のようなドロップダウンメニューを作成しましたので記載します。
今回はjQueryではなくVue.jsを使って作成してみました。
Rails+Vueあれば使い方はjQueryに近く、コードの記述量はjQueryよりも少なくて済む(気がする)と思っています・カテゴリ一覧をドロップダウンで表示させる
・カテゴリーの値はデータベースから取得する
・mouseoverでカテゴリの子要素を表示、mouseleaveで非表示となる
・クリックで各カテゴリページに遷移する・Rails+Vue.jsで作成する
初学者のため不備等多々あるかと思いますが、参照記事は良い記事ばかりです。
間違いやより良い記述方法があればご教示ください
https://i.gyazo.com/24baf3b1c603ee655eb45ecf4d8e4fdf.mp4①Vue.js導入
Webpackerのインストール
gem 'webpacker', github: 'rails/webpacker'bundle installyarnのインストール
brew install yarnWebpackerインストール
rails webpacker:install create config/webpacker.yml Copying webpack core config create config/webpack create config/webpack/development.js create config/webpack/environment.js create config/webpack/production.js create config/webpack/test.js Copying postcss.config.js to app root directory create postcss.config.js Copying babel.config.js to app root directory create babel.config.js Copying .browserslistrc to app root directory create .browserslistrc Creating JavaScript app source directory create app/javascript create app/javascript/packs/application.js apply /Users/sotatakahashi/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/bundler/gems/webpacker-2387331b33c6/lib/install/binstubs.rb Copying binstubs exist bin create bin/webpack create bin/webpack-dev-server append .gitignore Installing all JavaScript dependencies [4.0.2] run yarn add @rails/webpacker from "." : ✨ Done in 7.46s. Webpacker successfully installed ? ?↑終わったら絵文字が出ます(かわいい)
Vueインストール
rails webpacker:install:vueこれでRails上でVueを使う準備はOKです!
詳しくは下記記事にて。参考記事
https://qiita.com/cohki0305/items/582c0f5ed0750e60c951
https://qiita.com/saongtx7/items/fdb77901e7fcf291e2ad②カテゴリーメニューの作成
マウスオーバーとかは後にして、とりあえず見た目の部分を作っていきます。
(CSS割愛します).category_box .genre-box %ul.genre - @parents.each do |parent| = link_to category_path(parent.id), method: :get do %li.genre_list =parent.name .next-box .sub-box %ul.sub %li.sub_list .detail-box %a %ul.detail %li.detail_list親、子、孫にそれぞれulとliを持たせて、リストを作成します。
基本はこの形を使ってドロップダウンメニューを作成していきます!③マウスオーバーで表示/非表示を切り替える
.category_box{"v-show": "menuBool","v-on:mouseleave": "hiddenMenu"} #v-showなどはvueで使われるアクション、menuの表示非表示をこちらで設定 .genre-box %ul.genre - @parents.each do |parent| = link_to category_path(parent.id), method: :get do %li.genre_list{'v-on:mouseover': "setCategoryInfo(#{parent.id})"} =parent.name .next-box{'v-show': 'categoryInfoBool',"v-on:mouseleave": "hiddenSubInfo"} #子カテゴリーのメニューの表示、非表示をこちらで設定 .sub-box %a %ul.sub %li.sub_list{"v-on:mouseover": "setSubInfo(category.id)"} {{category.name}} #マウスオーバーした時に値を取得、表示させる。{{}}には表示する内容が入り、vueで切り替えられる! .detail-box{'v-show': 'SubInfoBool'} %a{"v-for": "sub in SubInfo","v-bind:href": "'/categories/' + sub.id"} %ul.detail %li.detail_list {{sub.name}}new Vue({ el:"#app", data:{ categoryInfo:[], //子カテゴリーの情報を入れる箱 SubInfo:[], //孫カテゴリーの情報を入れる箱 menuBool: false, categoryInfoBool: false, SubInfoBool: false, //基本非表示にさせるため、falseとしておく }, methods: { setCategoryInfo(id){ axios.get(`/api/genres/${id}.json`) //axiosでapiを使う(理屈はまだわかっていません、、) .then(res => { this.categoryInfo = res.data; this.categoryInfoBool = true; }); }, setSubInfo(id){ axios.get(`/api/genres/${id}.json`) .then(res => { this.SubInfo = res.data; this.SubInfoBool = true; }); }, showMenu:function(){ return this.menuBool = true }, hiddenMenu:function(){ return this.menuBool = false; }, hiddenCategory:function(){ return this.categoryInfoBool = false; }, hiddenSubInfo:function(){ return this.SubInfoBool = false }, //viewに乗っかった時にtrue,falseを切り替える } });api/genre
show.json.jbuilderjson.array! @category_children do |category_child| json.name category_child.name json.id category_child.id end④それぞれにリンクを貼る
%header#app.header .header__top .header__top__logo = link_to root_path do %img{alt: "mercari", src: "//www-mercari-jp.akamaized.net/assets/img/common/common/logo.svg?228111635"}/ .header__top__search = form_tag(search_items_path, method: :get, class: "header__top__search__box") do %input.header__top__search__box__input{name: "keyword", placeholder: "何かお探しですか?", type: "search"}/ %button.header__top__search__box__submit{type: "submit"}= fa_icon ("search lg") %form{"accept-charset" => "utf-8", :action => "/", :method => "get"} .header__bottom .header__bottom__leftside{"v-on:mouseleave": "hiddenMenu"} .header__bottom__leftside__left_box{"v-on:mouseover": "showMenu","v-on:mouseleave": "hiddenCategory"} = link_to categories_path, class: "header__bottom__leftside__left_box__content" do = fa_icon ("list-ul") %span カテゴリから探す -# ここからドロップダウンメニュー .category_box{"v-show": "menuBool","v-on:mouseleave": "hiddenMenu"} .genre-box %ul.genre - @parents.each do |parent| = link_to category_path(parent.id), method: :get do %li.genre_list{'v-on:mouseover': "setCategoryInfo(#{parent.id})"} =parent.name .next-box{'v-show': 'categoryInfoBool',"v-on:mouseleave": "hiddenSubInfo"} .sub-box %a{"v-for": "category in categoryInfo","v-bind:href": "'/categories/' + category.id"} #v-bindでaタグにリンクを貼っつける! %ul.sub %li.sub_list{"v-on:mouseover": "setSubInfo(category.id)"} {{category.name}} .detail-box{'v-show': 'SubInfoBool'} %a{"v-for": "sub in SubInfo","v-bind:href": "'/categories/' + sub.id"} %ul.detail %li.detail_list {{sub.name}} -# ここまでドロップダウンメニュー .header__bottom__leftside__right_box = link_to '', class: "header__bottom_box__leftside__right_box__content" do = fa_icon ("tag") %span ブランドから探す .header__bottom__rightside .header__bottom__rightside__bell = link_to '', class: "header__bottom__rightside__bell__content" do = fa_icon("bell lg") %span お知らせ .header__bottom__rightside__check = link_to '', class: "header__bottom__rightside__check__content" do %span = fa_icon("check lg") %span やることリスト .header__bottom__rightside__mypage = link_to '', class: "header__bottom__rightside__mypage__content" do %img.header__bottom__rightside__mypage__content__icon{alt: "", src: "//static.mercdn.net/images/member_photo_noimage_thumb.png", width: "32"}/ %div マイページnew Vue({ el:"#app", data:{ categoryInfo:[], SubInfo:[], menuBool: false, categoryInfoBool: false, SubInfoBool: false, }, methods: { setCategoryInfo(id){ axios.get(`/api/genres/${id}.json`) .then(res => { this.categoryInfo = res.data; this.categoryInfoBool = true; }); }, setSubInfo(id){ axios.get(`/api/genres/${id}.json`) .then(res => { this.SubInfo = res.data; this.SubInfoBool = true; }); }, showMenu:function(){ return this.menuBool = true }, hiddenMenu:function(){ return this.menuBool = false; }, hiddenCategory:function(){ return this.categoryInfoBool = false; }, hiddenSubInfo:function(){ return this.SubInfoBool = false }, } });かんせい!
Vue楽しいので何か違うこともやってみたいです!コンポーネント作るとかも楽しそう参考記事
インストール〜作成までの流れ
https://qiita.com/cohki0305/items/a678b0b17c5b496c1de9
https://qiita.com/saongtx7/items/fdb77901e7fcf291e2ad
axiosの使い方
https://www.webprofessional.jp/fetching-data-third-party-api-vue-axios/
https://qiita.com/ryouzi/items/06cb0d4aa7b6527b3645
vue.jsでmouseoverした時だけ表示する方法
https://qiita.com/sukechansan/items/07a415e4e7e5ce358afc
vue.jsでのリンクの貼り方
https://qiita.com/asaokamei/items/6afa7e2f33207d041588
- 投稿日:2019-05-02T17:54:28+09:00
Vue CLIに関するすること(メモ)
Vue-cliをするまで
こちらのページがわかりやすかった。
npmについても調べたページをメモ。
手順画像
※versionが古いと怒られる・・・
vue create is a Vue CLI 3 only command and you are using Vue CLI 2.9.6.
You may want to run the following to upgrade to Vue CLI 3:
npm uninstall -g vue-cli
npm install -g @vue/cli(意訳)
「『vue create』は3からのコマンドなのにお前の古いよ」
「下のコマンド打って上げろ」つづく
つづく
- 投稿日:2019-05-02T17:19:46+09:00
Macのターミナルで【Vue.js(Vue CLI 3系)】のvue コマンドを使えるようにするまでの話
そもそもなんでVue.js?
現在、WEBサイトのフロントエンド開発を主に仕事でしているのですが、フロントエンドエンジニアとしてJavaScriptのフレームワークのひとつぐらいまともにプログラミングできないとまずいよな〜と思ったのがきっかけです。
日本語のドキュメントもあり、フレームワークを調べてるときに比較的学習コストが少ないということで今回Vue.jsを選択しました。
現在は様々な機能が使えるVueCLIを使って開発するのがトレンドらしく、とりあえず触ってみよう的な試みです。Vue.jsについてはこちらの記事に詳しく書いてありました。
環境セットアップのための予備知識
OS環境 Mac OS 10.13.6(High Sierra) VueCLI 3系をインストールするにあたり、以下のようなサイトを参考にしました。
10分で始めるVue.js(基本編)
Vue CLI 3 をインストールしプロジェクトを作成する方法
Homebrewからnodebrewをインストールして、Node.jsをインストールするまで、、、。
いきなり、なじみのない言葉が、、、npm、homebrew、nodebrew、Node.js????
ということで調べて自分なりの解釈でざっくりと以下のように理解しました。
Node.js
WEBブラウザ以外でjsを動かすための環境のひとつ。
サーバサイドで動くJavaScriptのことでサーバサイドJavaScriptと呼ばれることもある。
従来のjavascriptととの違いは実行環境(内部的に構築されてるみたい)とライブラリからなっている(最初の時点である程度のモジュールが組み込まれているらしい)Homebrew
Macのターミナル用の※パッケージ管理システム
※パッケージ管理システムとは
ターミナル用のAppleストアやgoogleストア的なもの。それらが目的に応じていろいろ用意されている。
Ruby→gem/PHP→compser/などnpm
タスクランナー/モジュール(webpackやbrowserifyなど)などの開発環境系のパッケージ管理するためのもの
nodebrew
node.jsのversion管理するためのパッケージ管理システム
パッケージはそれぞれ、依存関係にあり、Vue.jsをインストールするための流れはざっくりこんな感じ
HomebrewをインストールするためにX codeをインストール
↓
nodebrewをインストールするため、Homebrewをインストール
↓
Node.jsとnpmをインストールするため、nodebrewをインストール
↓
VueCLIをインストールするため、Node.jsとnpmをインストール
(node.jsをインストールする際にnpmをインストールされる)↓
ようやく、VueCLIをインストール
セットアップ
それではいきましょうw
X codeをインストール
コマンドライン・デベロッパーツールをインストール
ターミナルから$ xcode-select --installコマンドを発行すると
以下のようにインストールを要求されて$ xcode-select --install xcode-select: note: install requested for command line developer tools同時にポップアップが出てくるので"インストール"を選択し利用規約に同意します。
Homebrewをインストール
Homebrewの公式サイトからコードをコピペしてEnterを押します。
途中でEnterの入力/インストールユーザのOSパスワードの入力を求められるので入力して進んでください。$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"インストールが確認するには以下のコマンドを実行できればインストールされたことになります。
$ brew doctornodebrewのインストール
$ brew install nodebrewインストールを確認するには
$ nodebrew -v情報が表示されたらインストールされてます!!
Node.jsとnpmのインストール
Node.jsの最新版をインストール
$ nodebrew install latestNode.jsを有効にします。
nodebrew use 先程インストールしたNode.jsのvernodeコマンドを使用するため、パスを通します。
#zshの場合は echo "export PATH=$HOME/.nodebrew/current/bin:$PATH" >> ~/.zshrc #bashの場合は echo "export PATH=$HOME/.nodebrew/current/bin:$PATH" >> ~/.bashrc先程追加したパスが動くようになり、nodeコマンドが使えるようになります。
#zshの場合は $ source ~/.zshrc #bashの場合は $ source ~/.bashrcnpmはNode.jsとともにインストールされます。
npmがインストールしたか確認
$ npm -vNode.jsがインストールしたか確認
$ node -vバージョンが表示されればOKです!!
Vue CLI(Vue.js)のインストール
npm install -g @vue/clivueコマンドを使うためのパスを確認
npm bin -g #/Users/xxxxxxx/npm/binvue コマンドを使用するためにパスを通す
$ export PATH=/Users/xxxxxxx/npm/bin:$PATHvueのインストールを確認
$ vue --versionバージョンが表示されればOKです!!
おしまい
とりあえず、Vueを動かす環境づくりはこんな感じでした。
- 投稿日:2019-05-02T16:00:45+09:00
el・data・データバインディング・リスト(Laravel使用Vue.js入門)#1
◆Vue.js利用準備
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>CDNを利用することで、ファイルをvue.jsのファイルをダウンロードすることなく利用できます。
◆データバインディング(表示しているものとデータの同期)
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="csrf-token" content="{{ csrf_token() }}"> <title>Vue.js</title> <link href="{{ asset('css/app.css') }}" rel="stylesheet" type="text/css"> </head> <body> <div id="app"> <h1>@{{ message }}</h1> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const vue = new Vue({ el: '#app', data: { message: 'Hello Vue.js!!' } }); </script>僕は、laravelのbladeを利用させていただいているため、\@{{message}}と指定しておりますが、bladeを使用されていない方は{{message}}で動作すると思います。
new Vue({})でVueインスタンスを作成して、その中のオプションを指定することでVueアプリケーションを作成することができます。
elは、DOM要素のセレクタを指定します。ちなみにクラスでも指定できます。マウントと言ったりします。
dataは、上のel内で指定した範囲内で利用するデータをもつ変数です。
今回の場合ですと、画面にHello Vue.js!!がデータバインディングにより表示されます。
また、messageの内容を変えると画面に表示される文字も変更されます。これをリアクティブといいます。バインディングは属性やクラスやスタイルも指定可能です。
◆リスト
<body> <div class="app"> <ol> <li v-for="fruit in fruitList"> @{{fruit}} </li> </ol> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const vue = new Vue({ el: '.app', data: { fruitList:[ 'ミカン', 'メロン', 'ブドウ' ] } }); </script>v-forディレクティブを使うと、簡単にリストを配列内のデータを利用し、使用することができます。
◆イベント・条件分岐
先ほどのリストを条件分岐で表示非表示を切り替えてみる
<body> <div class="app"> <ol> <li v-for="fruit in fruitList" v-if="show"> @{{fruit}} </li> </ol> <button v-on:click="handleClick">表示切替</button> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const vue = new Vue({ el: '.app', data: { fruitList: [ 'ミカン', 'メロン', 'ブドウ' ], show: true }, methods: { handleClick: function () { this.show =! this.show } } }); </script>v-onディレクティブを使用することで、DOMのイベントを検知できます。
v-on:clickの中に処理を記述することも可能ですが、処理は分けて記述するほうが良いと思います。this.showはdata内のshowを指しております。
elで指定した範囲内で利用するメソッドを、methodsプロパティ内で記述します。今回なら、showの切り替えです。
v-ifディレクティブはtrueだと、DOMに読み込まれますが、falseだとDOMから削除されます。また、これと似たもので、v-showディレクティブがあるのですが、こちらは削除されず、非表示になります。◆参考にさせていただいた記事
- 投稿日:2019-05-02T12:43:27+09:00
Vue3.x系で作ったアプリをFirebaseにデプロイするまでの流れ【初心者向け】
vue.jsでWebアプリを作ってそれをFirebaseにデプロイするまでにやったことをまとめました。
途中躓いたところが何個かあったので、備忘録として。
環境とかバージョンとか
- Mac OS Mojave(10.14.3)
- npm 6.9.0
- vue-cli 3.5.1
- firebase 6.5.0
1.vue.jsで何かしらアプリを作る
まずはvue-cliというツールをインストールします。
こちらの記事を参考にさせてもらいました。Vue.js を vue-cli を使ってシンプルにはじめてみる
vueには2.x系と3.x系があり、firebaseにデプロイする際の手順で微妙に違いがあるそうです。
今回は最新の3.5.1を使いますので2.x系の話は割愛してます。
$ vue --version
とかで確認しておくと吉。
$ npm run build
を実行してdist配下にデプロイする用のファイルを置いておきます。2.firebase側の準備
Firebaseに今回作成したアプリをデプロイする用のプロジェクトを作る必要があります。
GoogleアカウントでFirebase開き、コンソールから「プロジェクトを追加」をクリックします。そして、firebaseにログイン。
$ firebase login
ここでいろいろ英語で聞かれると思いますが、言われたとおりにハイハイ言っておきます。
(ブラウザに飛んで許可するか聞かれるはず)ログインが終わったらプロジェクトIDをメモっておきます
$ firebase list ┌───────────┬───────────────────────┬─────────────┐ │ Name │ Project ID / Instance │ Permissions │ ├───────────┼───────────────────────┼─────────────┤ │ Cash Book │ プロジェクトID │ Owner │ └───────────┴───────────────────────┴─────────────┘次にさっきのvueのアプリがあるディレクトリまで行き、initを実行。
$ firebase init --project=[FirebaseのプロジェクトID]AAでFIREBASEと表示され、つらつらと色々聞かれます。
######## #### ######## ######## ######## ### ###### ######## ## ## ## ## ## ## ## ## ## ## ## ###### ## ######## ###### ######## ######### ###### ###### ## ## ## ## ## ## ## ## ## ## ## ## #### ## ## ######## ######## ## ## ###### ######## You're about to initialize a Firebase project in this directory: /workspace/vue/vue-cli-test/test-prj ? Which Firebase CLI features do you want to setup for this folder? Press Space to select features, then Enter to confirm your choices. Hosting: Configure and deploy Firebase Hosting sites === Project Setup First, let's associate this project directory with a Firebase project. You can create multiple project aliases by running firebase use --add, but for now we'll just set up a default project. i Using project hogehoge === Hosting Setup Your public directory is the folder (relative to your project directory) that will contain Hosting assets to be uploaded with firebase deploy. If you have a build process for your assets, use your build's output directory. ? What do you want to use as your public directory?設定のあれこれを聞かれますが、基本的にはEnter連打でOK. (Y/n)で聞かれる質問はEnterを押すと大文字の方(Yes)を自動で選択してくれるようになっています。
ただし、
? What do you want to use as your public directory?
はvueのdistフォルダを指定しましょう。
(あとから変更可能です)デフォルトではpublicフォルダが選択されますが、vueではdist配下にソースが格納されるのでdistに指定しなければいけません。
3.firebaseにアプリをデプロイする
$firebase deploy
でサーバーにアプリをデプロイします。
- 投稿日:2019-05-02T08:26:59+09:00
Vue.js + Vuetify + Project-ShangriLa でアニメ情報を取得するアプリ作成
目的
面白いAPIを見つけたのでせっかくだからWebアプリ作ってみよう
環境
Windows Subsystem for Linux
OS: Ubuntu使用技術
Vue.js(SPAフレームワーク)
Vuetify(UIコンポーネントライブラリ)
axios(Ajax通信ライブラリ)
materialdesignicons(マテリアルデザインアイコン)サーバーレス+小規模なアプリなのでいかに低コストで導入できるかで選びました
(ちょっとVue使ってみたかった感もある)やったこと
プロジェクト作成
$ vue create animecheckVuetify追加
オプション指定などできるけどデフォルトを指定する
$ vue add vuetifyマテリアルデザインアイコン用のパッケージインストール
$ npm install @mdi/font --save $ npm install material-design-iconfont --save選択用コンボボックス作成
2014年~現在までの西暦とクールを選択する用のコンボボックスを作成する
search.vue<template src="../view/search.html"> </template> <script src="../js/search.js"> </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped src="../assets/css/search.css"> </style>html, js, css それぞれ別々に書いたほうがわかりやすそうだったので、vueファイルはテンプレートのみ記載する
search.html<v-layout row wrap> <v-flex xs12 sm6> <v-overflow-btn v-model="year" label='年' :items="selectYear" @change="getAnime"></v-overflow-btn> </v-flex> <v-flex xs12 sm6> <v-overflow-btn v-model="season" label='クール(季節)' :items="selectSeason" @change="getAnime"></v-overflow-btn> </v-flex> </v-layout>:items でコンボボックスに入れる選択値を設定する
選択された値は v-model で指定している year, season にそれぞれ入るsearch.jsimport axios from 'axios'; import 'vuetify/dist/vuetify.min.css' import '@mdi/font/css/materialdesignicons.css' import 'material-design-icons-iconfont/dist/material-design-icons.css' export default { data() { return { year: '', season: '', animes: [], selectYear: this.getYear(), selectSeason: [ {value: '1', text: '冬 (1 ~ 3 月)'}, {value: '2', text: '春 (4 ~ 6 月)'}, {value: '3', text: '夏 (7 ~ 9 月)'}, {value: '4', text: '秋 (10 ~ 12 月)'}, ] } }, methods: { /** * 2014 ~ 現在までの年数を取得する関数 */ getYear: function() { let currentYear = (new Date()).getFullYear(); const baseYear = 2014; let years = [] while(currentYear >= baseYear) { years.push({value: currentYear, text: currentYear + '年'}) currentYear -= 1; } return years }, } ... }クールだけは面倒なので固定で書いてしまった
(固定値として別の場所に書きたい)アニメ取得APIとの連携
西暦とクールを選択したら、APIにリクエストを送りレスポンスをいい感じに加工して画面に表示する
search.html<v-layout v-if="animes.length" row wrap> <v-flex lg4 sm12 xs12 v-for="anime in animes"> <v-card raised tile class="grey lighten-3 ma-2"> <v-card-title primary-title> <div> <div class="headline"> {{ anime.title }} </div> </div> </v-card-title> <v-divider light></v-divider> <v-card-actions class="pa-3"> <v-btn flat> <a v-bind:href="anime.public_url"> <v-icon> mdi-laptop </v-icon> </a> </v-btn> <v-btn flat> <a v-bind:href="'https://twitter.com/' + anime.twitter_account"> <v-icon> mdi-twitter </v-icon> </a> </v-btn> <v-btn flat> <a v-bind:href="'https://twitter.com/search?q=%23' + anime.twitter_hash_tag + '&src=typd'"> <v-icon> mdi-pound-box </v-icon> </a> </v-btn> </v-card-actions> </v-card> </v-flex> </v-layout>双方向データバインディングでanimesという変数に値が入っていない場合は、結果部分は何も表示されないようにする
search.js/** * 年 + クールから対象のアニメリストを取得する関数 */ getAnime: function() { this.getYear(); if (this.year && this.season) { // API: ShangriLa Anime API V1 let api_url = "https://api.moemoe.tokyo/anime/v1/master/" this.animes = [] axios.get(api_url + this.year + '/' + this.season, { }).then(response => { for (let i = 0; i < Object.keys(response.data).length; i++) { this.animes.push(response.data[i]) } }) } }コンボボックス側で指定されている関数
選択するたびに走るけど、年とクールが選択されていない限りは情報取得しないようにする外部APIからjsonでデータ取得するためにはaxiosを使用する
アニメ情報取得には以下のAPIを使用しています
GET /anime/v1/master/:year/:n
:yearで指定されたYYYY年アニメの:nで指定されたクールの情報をすべて返します。※参考
放映中のアニメ作品の情報を提供するAnime RESTful API サーバー作りました
axios を利用した API の使用Vuetifyコンポーネントについて
Vuetify Component API Overview
公式のドキュメントに各コンポーネントの例とソースが記載されている
すごくわかりやすいアイコンについて
Icon Component
Material Design IconsMaterial Design Iconsのアイコンの利用をサポートしています。アイコン名にmdi-プレフィックスを付与するだけで使用できます。あなたのプロジェクトにMaterial Design Iconsを導入しておく必要があるので注意して下さい。
search.html<v-icon> mdi-twitter </v-icon>これでTwitterアイコンなどが使用できる
デプロイ
サーバーレス+SPAなので、Github Pagesで簡単に公開したい
そのためビルド先のフォルダをdistからdocsに変更するプロジェクトフォルダ直下に以下のファイルを作成する
vue.config.jsmodule.exports = { publicPath: "./", assetsDir: "", outputDir: "docs" }ビルドする
$ npm run buildビルド完了後にgitに上げてGithub Pagesの設定をしてあげれば出来上がり
完成品
とりあえずお手軽に作れました
最後に
こちらのAPIを使用させていただきました!素晴らしいAPIに感謝です!
https://github.com/Project-ShangriLa/sora-playframework-scalaVueについて少ししか勉強してないのでもっと最適化できる部分あるかもって感じです
よろしければコメントなどでご指摘いただければと思います
- 投稿日:2019-05-02T07:10:21+09:00
Vue.js で子コンポーネントにプロパティを一括で渡す方法
沢山のプロパティを持つコンポーネントに値を渡すとき、
以下のように全プロパティについてズラズラ書いていくのはちょっと面倒です。よくない例<Profile :id="id" :name="name" :nickname="nickename" :address="address" />こういうときは、プロパティ名なしの
v-bind
にオブジェクトを渡すことでプロパティを一括で渡すことができます。良い例<Profile v-bind="{id, name, nickname, address}" />あるいは
data
等にオブジェクトを定義しておくとテンプレートがより簡潔に書けます。良い例<Profile v-bind="profile" /> (中略) data() { return { profile: { id: id, name: name, nickname: nickname, address: address, } } },蛇足
上述の方法は公式ドキュメントにも一応ちょこっと記載はあるのですが、意外と知らない人も多そうだったので記事にしました。
実際、公式の別の箇所では「プロパティが増えてきたらプロパティ定義を一つにまとめよう」的な別の解決策が書かれています。
しかしながらそれだとプロパティのバリデーションがやり辛くなるため、現在ではバッド・プラクティスではないかと思われます。現行のバージョンではプロパティ定義を変えずともオブジェクトで渡せるので是非そうしていきましょう。