- 投稿日:2019-08-28T23:46:22+09:00
【Vue.js】ローカル環境構築(Vue CLI v3.10.0)インストール手順
開発環境
?Mac OS MojaveCodePenやJSFiddleでCDN(インターネット経由)でも開発できますが、
ローカル環境での構築手順をまとめます。Vue.jsの公式サイト
http://vuejs.org/
↑英語Vue.jsの公式 日本語訳されたサイト
http://jp.vuejs.org/
↑日本語【Vue.js】Vuejsをchromeブラウザでデバッグする方法
https://qiita.com/nonkapibara/items/8b587013b6b817d6dfc41.nodebrewをインストールする
brew install nodebrew下記エラーが出た。><
xcrun: error: active developer path ("/Applications/Xcode.app/Contents/Developer") does not exist
Usesudo xcode-select --switch path/to/Xcode.appto specify the Xcode that you wish to use for command line developer tools, or usexcode-select --installto install the standalone command line developer tools.
Seeman xcode-selectfor more details.
Error: An exception occurred within a child process:
CompilerSelectionError: nodebrew cannot be built with any available compilers.
Install GNU's GCC:
brew install gccエラー内容を見ると、CLTをインストールしたら良いっぽいので、
CLTをインストールするbrew install gccCLTをインストールできたので
再度、Nodebrewをインストールするbrew install nodebrewインストール確認をする
nodebrew -vインストール成功
nodebrew 1.0.12.Node.jsをインストールする
nodebrew/src のディレクトリを作る
mkdir -p ~/.nodebrew/srcNode.jsをインストールする
nodebrew install-binary latestInstalled successfully
が表示され、インストール成功バージョンを確認する
nodebrew lsv12.8.0
が表示される使用するバージョンを指定する。
nodebrew use v12.8.0
3.パスを通す
bash_profileを開いて
vi ~/.bash_profile以下の内容を追加する
export PATH=$HOME/.nodebrew/current/bin:$PATHvimで書き込みを行うときは、iを押します。
一番下の行に-- INSERT --と出て、入力モードになります。
書き込みが済んだら、escを押して入力モードを解除します。この状態で、:wqと打つと保存してvimを終了してくれます。
(保存しないで終了したい場合は:q)確認する
cat ~/.bash_profile4.設定ファイルを読み直す。
exec $SHELL -l5.ここまでの確認をする
node -vv12.8.0
が表示されたOKpm -v6.10.2
が表示されたOK6.Vue CLI3のインストールする
インタラクティブなプロジェクトのひな型作成 - @vue/cli
設定なしに即使えるプロトタイプ作成 - @vue/cli + @vue/cli-service-globalnpm install -g @vue/cli npm install -g @vue/cli-service-globalバージョンの確認
vue --version3.10.0
が表示されOK7.Vue.js Devtoolsをインストール
Vue.js Devtoolsは、Vue.jsの開発をサポートする Chromeブラウザの拡張機能Vue.js devtools
https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd8.新しいプロジェクトを作成する
vue create testone-app下記表示がされた
? Your connection to the default npm registry seems to be slow.
Use https://registry.npm.taobao.org for faster installation? Yes
翻訳すると、デフォルトのnpmレジストリへの接続が遅いようです。
とりあえずYでEnter下記表示がされた
Vue CLI v3.10.0
? Please pick a preset: default (babel, eslint)9.アプリケーションの起動
cd testone-appサーバー起動
npm run serve下記が表示された
DONE Compiled successfully in 2670ms
App running at:
- Local: http://localhost:8080/
- Network: http://10.38.109.192:8080/Note that the development build is not optimized.
To create a production build, run npm run build.
下記にアクセスする
http://localhost:8080/★開発サーバを停止する時は ctrl + c
- 投稿日:2019-08-28T23:34:47+09:00
Vue.js の v-slot でスロットのスコープ変数をなんとか推論させる
Vue.js の v-slot でスロットのスコープ変数をなんとか推論させる
最近の Vetur では
<template>配下でも変数の型を確認できるようになってきましたが
スロットのスコープ変数についてはanyになりがちです。child<template> <div> child <slot :id="id" :namae="namae" /> </div> </template> <script> export default { data() { return { id: 1, namae: 'Taro', }; }, }; </script>parent<template> <div> parent <child> <template v-slot="slotProps"> child 使用 {{ slotProps }} </template> </child> </div> </template> <script> import Child from './child.vue'; export default { components: { Child, }, }; </script>
child自身では template 中の変数の型を確認可能だが・・・
parent側で使用した際の変数ではany実際の画面表示では
slotPropsの中身はid,namaeをchildにて指定した通りこれについて
parent側にてidなどの型の確認ができないかなどをやってみます。スロット側で変数を明確にする関数を定義して
exportスロットを持つ
child側にて「何もしない」が型を明示する関数を用意してみます。child-vs<script> /** * @typedef {Object<string, any>} SlotProps * @property {number} id * @property {string} namae */ /** * @param {SlotProps} slotProps * @return {SlotProps} */ export const vs = slotProps => slotProps; export default { data() { return { id: 1, namae: 'Taro', }; }, }; </script>定義された関数
vsは引数に渡された値をそのまま返すだけのアロー関数です。
@typedefにより型定義したSlotPropsはそれぞれchildでの<slot>に渡している要素と同一の構造のオブジェクトの定義となります。使用側でスロット側で定義した変数用関数を適用
上記の
vsをparentにて適用すると・・・parent-vs<template> <div> parent <child> <template v-slot="slotProps"> child 使用 {{ vs(slotProps) }} {{ vs(slotProps).id }} {{ vs(slotProps).namae }} </template> </child> </div> </template> <script> import Child, { vs } from './child.vue'; export default { components: { Child, }, methods: { vs, }, }; </script>
child.vueよりvsをimportしてparentのmethodsに追加しています。
これをエディタ上で確認してみると以下のようになります。
slotPropsは相変わらずany
childよりimportしたvsは定義した通りで推論されます。
vs(slotProps)の結果より生やしたidはJSDocで定義した通りnumberで確認できました。
(残念ながらvs(slotProps)の結果から.idなどは候補としては取得できませんでした・・・)
JSDocにて定義していないababababを指定してみたところ
SlotProps型に存在しない旨のメッセージが表示され、想定しないプロパティへのアクセスであることも確認できました。
- 投稿日:2019-08-28T23:02:44+09:00
【Vue.js】CodePenでVue.jsを実装する方法
2019.08.28時点
CodePen
https://codepen.io/4.Vue.jsのCDNを追加する
「Add External Scripts/Pens」のサーチエリアに「vue」と入力する
5.APIリクエストで「axios」を使用する場合は、
「Add External Scripts/Pens」のサーチエリアに「axios」と入力する
nonVuejsAxiosAPI by nonkapibara (@nonkapibara) on CodePen.
8.HTMLにdivから書く事ができる。
index.html<div id="app"> {{ info }} </div> <script src="./main.js"></script>main.jsnew Vue({ el: '#app', data() { return { info: null } }, mounted () { axios .get('https://api.coindesk.com/v1/bpi/currentprice.json',{ responseType: 'arraybuffer' }) .then(response => (this.info = response)) } })
- 投稿日:2019-08-28T23:02:44+09:00
【Vue.js】CodePenでVue.jsを実装する方法とaxiosでAPIリクエストやってみた
2019.08.28時点
Vue.js サンプル axiosでAPIリクエスト
See the Pen
nonVuejsAxiosAPI by noriko fujita (@nonkapibara)
on CodePen.
■CodePenのサイト
https://codepen.io/4.Vue.jsのCDNを追加する
「Add External Scripts/Pens」のサーチエリアに「vue」と入力する
5.APIリクエストで「axios」を使用する場合は、
「Add External Scripts/Pens」のサーチエリアに「axios」と入力する
8.HTMLにdivから書く事ができる。
index.html<div id="app"> {{ info }} </div> <script src="./main.js"></script>main.jsnew Vue({ el: '#app', data() { return { info: null } }, mounted () { axios .get('https://api.coindesk.com/v1/bpi/currentprice.json',{ responseType: 'arraybuffer' }) .then(response => (this.info = response)) } })Fullだとこんな感じ
index.html<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Vue.js API</title> <!-- 開発バージョン --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> </head> <body> <div id="app"> {{ info }} </div> <script src="./main.js"></script> </body> </html>
- 投稿日:2019-08-28T22:58:31+09:00
Vue.js:Vuexのエラー:「[vuex] Do not mutate vuex store state outside mutation handlers」の原因と対応例
原因
- コンポーネントの「v-model」に、stateの値を設定していたため。
- v-modelは参照と設定を同時に行うため、タイトルのエラーが発生する。
issue.vue<template> <!-- v-modelにstateの値を設定 -> <v-test-comp v-model="theValue"></v-test-comp> </template> <script> import { mapState } from "vuex"; export default { computed: { //stateの値にアクセスできるよう設定 ...mapState(["theValue"]) } } </script>対応
- v-modelに設定する値を算出プロパティに置き換える。
- 算出プロパティのgetでstateの値を返却し、set内で、storeのactionを呼び出す。
resolve.vue<template> <!-- v-modelにstateの値を設定 -> <v-test-comp v-model="theValue"></v-test-comp> </template> <script> import { mapState } from "vuex"; export default { computed: { theValue: { get() { return this.$store.theValue }, set(value) { this.$store.dispatch("setTheValue", value) } } } } </script>
- 投稿日:2019-08-28T22:45:19+09:00
【Vue.js】Vue.js サンプル「カウントアップ」
↓↓完成図
https://twitter.com/nonnonkapibara/status/1166711295384510465
⛱️Vue.js⛱️CodePen⛱️
— non (@nonnonkapibara) August 28, 2019
Vue.jsをCodePenで実装してみたよぉ。
CDN(インターネット経由)でできるので、めっちゃ便利♪♪https://t.co/z92om6dOAu pic.twitter.com/FrcWwWINq0Vue.jsで、ハート型のボタン「Count Up」をTapする度に、カウントアップしていくサンプル。
See the Pen nonVueJsCountUp by nonkapibara (@nonkapibara) on CodePen.
index.html<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Vue.js カウントアップ</title> <!-- 開発バージョン --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <!-- 本番バージョン --> <!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script>--> <link rel="stylesheet" type="text/css" href="./style.css"> </head> <body bgcolor="#FFF8DC"> <div id="app"> <center> <div class="titleStyle">Vue.js カウントアップ</div> <div class="sytle001">{{count_number}}回</div><br> <input v-on:click="click_count_up" type="image" class="heartButton" src="pic/button.png"> </center> </div> <script src="./main.js"></script> </body> </html>main.jsvar app = new Vue({ el: '#app', data:{ count_number: 1 }, methods:{ click_count_up: function(){ this.count_number++; } } });style.css.titleStyle{ font-size: 30px; color: #c71585; font-family: 'Hiragino Maru Gothic Pro','ヒラギノ丸ゴ Pro W4', sans-serif; } .sytle001{ font-size: 40px; color: #ff69b4; font-family: 'Hiragino Maru Gothic Pro','ヒラギノ丸ゴ Pro W4', sans-serif; } .heartButton { border: 1px solid #ddd; width: 80px; height: 70px; margin: 0 auto; overflow: hidden; cursor: pointer; } .heartButton:hover { box-shadow: 5px 5px 5px rgba(0,0,0,0.5); transform: translateY(-10px); transition-duration: 0.5s; } .heartButton:active { transform: scale(1.2) rotate(0deg); transition-duration: 0.0s; }CodePenを埋め込むには、右下の「Embed」を選択する
HTMLタブを選択して、内容をコピーすれば、Qiitaに埋め込める
はてなブログに、CodePenを埋め込むには、「iframe」を貼り付けたらできました。
「はてなブログ」にCodePenが埋め込まれています。
かぴばらさんの覚書ブログ nonkapibara
- 投稿日:2019-08-28T22:32:29+09:00
typescriptでbuefyのtoastやmodalを使う
buefyはbulmaをベースとしたvue.js用のUIコンポーネントです。
もともとbuefyをよく使っていたのですが、最近typescriptでも使ってみたところ、少し詰まったところがあったのでまとめました。vue.jsでmodalやtoastを使用する場合
公式のドキュメントのサンプルコードをそのままコピペするだけで、このようなtoastが作成できます。
実際にscript内に書くコードはこれだけなのですが、typescriptを使う場合にこのままだと動きませんでした。
this.$buefy.toast.open('Something happened')参考
https://buefy.org/documentation/toasttypescriptで使う場合
先ほどのコードをそのまま使うと下記のようなエラーが出てしまいます。
TS2339: Property '$buefy' does not exist on type 'App'.typescriptで使用する場合には、下記の書き方をすれば使用できるようです。
this.$toast.open('Something happened');同様にmodalなんかを使う場合には、vue.jsだとこのように書くので
this.$buefy.modal.open( `<p class="image is-4by3"> <img src="https://buefy.org/static/img/placeholder-1280x960.png"> </p>` )typescriptで使う場合には、これで使えます。
this.$modal.open( `<p class="image is-4by3"> <img src="https://buefy.org/static/img/placeholder-1280x960.png"> </p>` )
- 投稿日:2019-08-28T22:28:31+09:00
Rails & Nuxt.jsのアプリケーションにGraphQLを導入する
前提
Rails & Nuxt.jsのDocker環境をalpineイメージで構築する
こちらのポストの環境をもとに進めるので、Dockerのサービス名等は適宜読み替えていただくようにお願いします。ディレクトリ構成
後述のコマンドでは、Railsはbackend、NuxtはfrontendがDockerのサービス名になっています。. ├── backend <- Ruby on Rails │ ├── Dockerfile │ ├── Gemfile │ ├── Gemfile.lock │ (中略) │ ├── frontend <- Nuxt.js │ ├── Dockerfile │ ├── README.md │ ├── nuxt.config.js │ ├── package-lock.json │ ├── package.json │ (中略) │ ├── docker-compose.yml └── .envライブラリ追加
Rails
- graphql-ruby ... RubyでGraphQLを導入するならコレ
- graphiql-rails ... GraphQL IDE のRails版。ブラウザから
./backend/Gemfileを修正し、bundle installします。## (中略) ## gem 'graphql' #added group :development do gem 'listen', '>= 3.0.5', '< 3.2' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' gem 'graphiql-rails' #added end ## (中略) ##$ docker-compose exec backend bundle installNuxt
こちらのライブラリをインストールします。
本記事では graphql-tag は使いません。$ docker-compose exec frontend yarn add @nuxtjs/apollo実装
Rails
generator で雛形を作成します。
$ docker-compose exec backend rails g graphql:installgraphiql-railsの Readme にしたがって、Railsのconfigファイルを修正します。
./backend/config/routes.rbGraphiQLエンジンをマウントし、ブラウザからアクセスできるようにします。
Rails.application.routes.draw do post "/graphql", to: "graphql#execute" #generatorでinsertされる # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html #added if Rails.env.development? mount GraphiQL::Rails::Engine, at: '/graphiql', graphql_path: '/graphql' end end
./backend/config/application.rbAPIモードの場合に必要な修正です。
## (中略) ## - # require "sprockets/railtie" + require "sprockets/railtie" ## (中略) ##GraphiQLで動作確認
dockerコンテナを再起動後、ブラウザで http://localhost:3000/graphiql にアクセスし、GraphiQLを開きます。
./backend/app/graphql/types/query_type.rbのサンプルを利用して、下記のようにqueryの結果が返ってくればOKです。$ docker-compose restart backendNuxt
Nuxtアプリのルートに、下記のディレクトリ、ファイルを追加、編集します。
今回はmutationは使いませんが、あわせて作成しておきます。. └── frontend ├── nuxt.config.js │ ├── pages │ └── index.vue │ └── apollo ├── client-configs │ └── default.js └── gqls ├── mutations └── queries └── getTestField.gql
./frontend/nuxt.config.jsNuxtでapolloクライアントを使用するための設定を追加します。
default.jsを読み込まず、nuxt.config.jsに直書きしてもOKです。export default { /* (中略) */ modules: [ '@nuxtjs/apollo', //added ], /* (中略) */ apollo: { clientConfigs: { default: '~/apollo/client-configs/default.js' } } }
./frontend/apollo/client-configs/default.jsapolloには様々なオプションありますがが、今回はqueryの実行が確認できればよいので最低限です。
uriのホスト名は、DockerのRailsアプリのサービス名backendになります。import { HttpLink } from 'apollo-link-http' export default () => { const httpLink = new HttpLink({ uri: 'http://backend:3000/graphql' }) return { link: httpLink } }
./frontend/apollo/gqls/queries/testField.gqlGraphiQLで実行したものです。
query { testField }
./frontend/pages/index.vuequeryを実行した結果を表示します。
<template> <p>{{ testField }}</p> </template> <script> import testField from '~/apollo/gqls/queries/testField'; export default { data() { return { testField: {} } }, apollo: { testField: { query: testField } } } </script>お疲れさまでした。
(簡略化シすぎた感)
- 投稿日:2019-08-28T21:45:41+09:00
Textareaで未確定文字がvalueに勝手にinsertされてしまう現象を修正した
概要
社内アプリケーションにていつからか、Windowsユーザの方から
「未確定文字がtextareaに勝手にはいって、かつ、未確定文字は残っている」
という不思議な現象が起きるようになった。結論
input eventを使えばいい
解消した方法
Vue.jsを使っており、textareaにて、様々なイベントをつけていた。
その一部で keyup eventを使っていたが、それを input event に変更した。<template> <textarea v-focus rows="8" cols="40" accesskey="g" :value="value" @keyup.esc="anything" @keypress.enter.exact="something" @keyup="update"></textarea> </template>↓
<template> <textarea v-focus rows="8" cols="40" accesskey="g" :value="value" @keyup.esc="anything" @keypress.enter.exact="something" @input="update"></textarea> </template>原因
正直わからない。(調べ方がわからない)
あるkeyによって起きるということではなく、たまに起きる。ということ、おそらくIMEの問題ではないかと思っている。
詳しい人がいれば教えて下さい。
- 投稿日:2019-08-28T18:54:22+09:00
分からねえ!!
Node.jsをインストールしたはいいが、おかしい。
$ npm install -g vue-cli
って打ち込んでEnterしたら
npm ERR! code ENOTFOUND
npm ERR! errno ENOTFOUND
以下略。。って表示が出て何やらできてないっぽい。。。
なんだ?国会図書館のWifi使ったからか?そこのあなた助けてくだざい。。。
(追記)
家のwifi繋いだら無事できました。
見てくれた皆さまお騒がせしてすいません。
ありがとうございました。
- 投稿日:2019-08-28T13:46:22+09:00
【Vue・React・Elm】ビューの書き方を比べてみた
Vue.jsの場合
Vueのビューはこんな感じ
<template> <div> <button v-on:click="decrement">-1</button> <div>{{ count }}</div> <button v-on:click="increment">+1</button> </div> </template>ほぼHTMLですね。見やすいです。
Vueでの条件分岐や繰り返し
v-ifやv-forなどのディレクティブというものが用意されていて、それをHTMLの属性みたいに書きます。
【例】記事タイトル一覧
記事があれば、その分だけ繰り返し表示するし、1件もなければ「記事がありません。」と表示する例です。
<template> <ul v-if="items.length"> <li v-for="item in items"> {{ item.title }} </li> </ul> <p v-else>記事がありません。</p> </template>v-ifとかv-forとか色々覚えないといけませんが、個人的には割と分かりやすいと思います。
Reactの場合
Reactのビューはこんな感じ
render() { return ( <div> <button onClick={decrement}>-1</button> <div>{ count }</div> <button onClick={increment}>+1</button> </div> ) }Babelというトランスパイラを使うことで、ReactのビューもHTMLみたいに書けます。
これはJSXという書き方なんですが、これが一部の方からは「何か気持ち悪い」と不評みたいです。。。
個人的には、ほぼHTMLそのままで読みやすいと思します。ちなみにJSX記法を使わない場合は、以下の様にReact.createElementメソッドを使用します。
render() { return ( React.createElement('div', null, React.createElement('button', { onClick: decrement }, '-1'), React.createElement('div', null, count), React.createElement('button', { onClick: increment }, '+1') ) ) }
Reactでの条件分岐や繰り返し
JSXの中では、if文やfor文は使えません。
そのため三項演算子や配列のmapメソッドを使って記述します。【例】記事タイトル一覧
render() { return ( <div> { items.length > 0 ? ( <ul> { items.map((item) => { return <li>{ item.title }</li>; })} </ul> ) : ( <p>記事がありません。</p> )} </div> ) }JSの構文と混じると、少し読みづらいかもしれません。。。
Elmの場合
賢い人は考えた
「HTML要素って、要は
タグ名と属性と中に入ってる子要素たち・・・」
「この3つから構成されているやん?」<div class="container" id="hoge"> <span>子要素</span> </div>「じゃあ、
divとかspanっていう関数を作って・・・」
「第一引数には[ class "containor", id "hoge" ]みたいに属性のリストを渡して」
「第二引数には子要素のリストを渡せばええやん」div [ class "container", id "hoge" ] [ span [] [ text "子要素" ] ]「↑こう書いたらHTML要素を返してくれるような・・・」
「各タグ名に対応したHTML関数たちを作ればええんや!」
「ただの関数やから、ループさせるのに(v-ifとかv-forのような)専用の書き方とか要らんで」
「ElmのifやList.map関数とかと、シームレスに組み合わせられるんや!」
Elmでは
divやspanすらも関数Elmでは、各HTML要素に対応した関数があらかじめ用意されています。
(header, section, p 等々・・・)このHTML関数たちを使って、ビュー部分とプログラム部分をシームレスかつ柔軟に書くことができます。
「配列の分だけループして表示させるための特別な構文」もありませんし、
「属性値を動的に生成するための特別な書き方」もありません。
ということで、Elmのビューはこんな感じ
view model = div [] [ button [ onClick Increment ] [ text "+1" ] , div [] [ text <| String.fromInt model.count ] , button [ onClick Decrement ] [ text "-1" ] ]
Elmでの条件分岐や繰り返し
条件分岐や繰り返しに関して、ビュー専用の構文はありません。
普通にElmのList.map関数とかifなどを使用します。【例】記事タイトル一覧
view model = div [] [ if List.length model.items > 0 then ul [] (model.items |> List.map liComponent) -- 記事(items)が1件以上あれば、 -- その分だけliComponentを呼び出して表示する else p [] [ text "記事がありません。" ] ] -- ただ関数を作ればコンポーネントのように利用できる liComponent title = li [] [ text title ]
シンプルでいい感じ!
完
- 投稿日:2019-08-28T13:13:11+09:00
【Vue.js】子から親コンポーネントのイベント実行・データ受け渡し
子から親コンポーネントのデータを更新
初心者用記事です。Vue.jsに少し慣れたので忘れないうちに記事にします。
今回、二つの方法に触れます。
$emitで子から親コンポーネントの処理を呼び出す
$emitで子から親コンポーネントへ値を渡す以下の記事を参考に追加機能付きで作成しました。
https://dev83.com/vue-emit/
分かりやすい記事なのでお勧めです。親から子の受け渡しを行うアプリで、ボタンを押すと数が増減する簡単なアプリ作っていきます。
↓ 例
実際に作ってもいいですが、JSFiddleで動作テストしてもいいと思います。
<div id="app"> </div> new Vue({ el: '#app', data: { // 下部に出てる合計個数 totalCount: 0, items: [ { name: 'りんご', price: 100, imgUrl: 'https://4.bp.blogspot.com/-uY6ko43-ABE/VD3RiIglszI/AAAAAAAAoEA/kI39usefO44/s800/fruit_ringo.png' }, { name: 'バナナ', price: 200, imgUrl: 'https://1.bp.blogspot.com/-JaRzIloEZw4/UgSMOL-UzYI/AAAAAAAAW_A/vOiX6Tz5oO4/s800/fruit_banana.png' }, ], }, });style部分
.item-wrap { list-style-type: none; display: flex; flex-wrap: wrap; margin: 0; padding: 0; } .item-wrap li { padding: 1em; } .item-wrap img { border-radius: 50%; } .total-count { padding: 1em; background-color: #222; color: #fff; }現状では何も表示されません。
簡単アプリを追加
本体に追加
<div id="app"> <ul class="item-wrap"> <item v-for="item in items" :item="item"></item> </ul> <div class="total-count">合計:{{ totalCount }}個</div> </div>子コンポーネント追加。ファイル読み込んだ方がいいですが今回はjsFiddle使って確認したので一つにまとめて書いてます。
Vue.component('item', { // 親から値もらう props: ['item'], // 子コンポーネントのテンプレート部分 template: ` <li> <img :src="item.imgUrl" style="height: 200px;"> <div>{{ item.name }} = {{ childTotal }}個</div> <button @click="addCart">増やす</button> <button @click="removeCart">減らす</button> </li> `, // 子コンポーネントデータ data: function () { return { childTotal: 0 }; }, // ボタン押すと発火する処理 methods: { addCart: function () { this.childTotal += 1; }, removeCart: function () { if (this.childTotal > 0) { this.childTotal -= 1; } }, }, }); new Vue({ // 省略。さっき書いたところ });ここまでの状態だと子コンポーネントから親コンポーネントに値を渡していないので
「合計:個」には変化が起きません。親コンポーネントのデータを更新
子コンポーネントのデータが更新されたら親コンポーネントのデータが更新されるようにします。
子コンポーネントのmethodsを修正。
methods: { addCart: function () { this.childTotal += 1; // ↓追加。親の合計個数増やす this.$emit('addbtn'); }, removeCart: function () { if (this.childTotal > 0) { this.childTotal -= 1; // ↓追加。親の合計個数減らす this.$emit('removebtn'); } }, },親コンポーネントを修正
itemコンポーネント部分
methods追加<div id="app"> <ul class="item-wrap"> <item v-for="item in items" :item="item" @addbtn="addParentTotal" @removebtn="removeParentTotal" > </item> </ul> <div class="total-count">合計:{{ totalCount }}個</div> </div>new Vue({ el: '#app', data: { totalCount: 0, items: [ { name: 'RedApple', imgUrl: 'https://4.bp.blogspot.com/-uY6ko43-ABE/VD3RiIglszI/AAAAAAAAoEA/kI39usefO44/s800/fruit_ringo.png' }, { name: 'GreenApple', imgUrl: 'https://1.bp.blogspot.com/-JaRzIloEZw4/UgSMOL-UzYI/AAAAAAAAW_A/vOiX6Tz5oO4/s800/fruit_banana.png' }, ], }, methods: { addParentTotal: function () { this.totalCount += 1; }, removeParentTotal: function () { this.totalCount -= 1; }, }, });最終的な子コンポーネント
Vue.component('item', { props: ['item'], template: ` <li> <img :src="item.imgUrl" style="height: 200px;"> <div>{{ item.name }} = {{ childTotal }}個</div> <button @click="addCart">増やす</button> <button @click="removeCart">減らす</button> </li> `, data: function () { return { childTotal: 0 }; }, methods: { addCart: function () { this.childTotal += 1; this.$emit('addbtn') }, removeCart: function () { if (this.childTotal > 0) { this.childTotal -= 1; this.$emit('removebtn'); } }, }, });ひとまず完成
@addbtn=”addParentTotal”
@removebtn=”removeParentTotal”
親コンポーネントの<item>~~~</item>に追加したのはこのふたつ。子コンポーネントの
this.$emit('addbtn')
もしくはthis.$emit('removebtn');が発火したら
親コンポーネントのmethodsにあるaddParentTotalremoveParentTotal
を呼び出してくださいという処理です。子から親に値を受け渡す
現状だと親コンポーネントで合計を計算していますが、子コンポーネントからの
値を直接受け取り、計算したい場合もあると思います。サンプル:値段を計算
親コンポーネントに値段を定義して、子コンポーネントから受け取った個数をもとに合計金額を計算する機能を追加します
受け渡しは引数を追加してやります。
this.$emit('addbtn', this.childTotal, name)この場合だとthis.childTotalとnameを渡しています。
親の受け取る側addParentTotal: function (total, name){ }これで子から親へデータを渡すことができます。
サンプルを作ったのですが、 改造してたら意外とシンプルにならずに申し訳ないです…
<div id="app"> <ul class="item-wrap"> <item v-for="item in items" :item="item" @addbtn="addParentTotal" @removebtn="removeParentTotal" > </item> </ul> <div class="total-count">合計:{{ totalCount }}個</div> <p class="total-count" v-for="item in items"> {{ item.name }}の合計金額:¥{{ item.totalYen }} </p> </div>子コンポーネント
Vue.component('item', { props: ['item'], template: ` <li> <img :src="item.imgUrl" style="height: 200px;"> <div>{{ item.name }} = {{ childTotal }}個</div> <button @click="addCart(item.name)">増やす</button> <button @click="removeCart(item.name)">減らす</button> </li> `, data: function () { return { childTotal: 0 }; }, methods: { addCart: function (name) { this.childTotal += 1; this.$emit('addbtn', this.childTotal, name) }, removeCart: function (name) { if (this.childTotal > 0) { this.childTotal -= 1; this.$emit('removebtn', this.childTotal, name); } }, }, });親コンポーネント
new Vue({ el: '#app', data: { totalCount: 0, items: [ { name: 'リンゴ', price: 100, imgUrl: 'https://4.bp.blogspot.com/-uY6ko43-ABE/VD3RiIglszI/AAAAAAAAoEA/kI39usefO44/s800/fruit_ringo.png', number: 0, totalYen: 0 }, { name: 'バナナ', price: 200, imgUrl: 'https://1.bp.blogspot.com/-JaRzIloEZw4/UgSMOL-UzYI/AAAAAAAAW_A/vOiX6Tz5oO4/s800/fruit_banana.png', number: 0, totalYen: 0 }, ], }, methods: { addParentTotal: function (total, name) { this.totalCount += 1; // 名前一致する該当の要素をオブジェクトから入れる const item = this.items.find(ele => ele.name === name) item.number = total item.totalYen = total * item.price }, removeParentTotal: function (total, name) { this.totalCount -= 1; // 名前一致する該当の要素をオブジェクトから入れる const item = this.items.find(ele => ele.name === name) item.number = total item.totalYen = total * item.price }, }, });.item-wrap { list-style-type: none; display: flex; flex-wrap: wrap; margin: 0; padding: 0; } .item-wrap li { padding: 1em; } .item-wrap img { border-radius: 50%; } .total-count { padding: 1em; background-color: #222; color: #fff; }それぞれのオブジェクトに個数を操作。
また、1個当たりの値段から金額を計算するアプリ完成。
これなにに使えるの?
色々ありますけど、モーダルなどが分かりやすい例です。
モーダルを子コンポーネントにして、フォームの入力をしてもらうと親の値も変わるみたいな感じです。それについては次の機会に
- 投稿日:2019-08-28T11:40:28+09:00
Vue CLI で VSCode+TypeScript+ESLint+Prettierの環境構築
はじめに
TypeScriptの場合も、これからはESLintらしい。
Vue CLIのV3を使って、TypeScript+ESLintの初期構築手順をまとめる。
手順
vue-cliのインストール
# npm i -g @vue-cli# vue -V 3.11.0Vue CLIによるプロジェクト作成
# vue create myprojectマニュアルを選択
? Please pick a preset: default (babel, eslint) ❯ Manually select featuresインストールしたい機能を選択する。
TypeScriptとLinter / Formatterを有効化。その他はお好みで。? Check the features needed for your project: ◉ Babel ◉ TypeScript ◯ Progressive Web App (PWA) Support ◉ Router ◉ Vuex ◉ CSS Pre-processors ❯◉ Linter / Formatter ◯ Unit Testing ◯ E2E Testing以降は有効化した機能に関する質問が続く。
Linterとフォーマッタに関する質問で、
ESLint + Prettierを選択。? Pick a linter / formatter config: TSLint ESLint with error prevention only ESLint + Airbnb config ESLint + Standard config ❯ ESLint + Prettierそれ以外の質問はお好みでOK。
VSCodeの設定追加
ESLintの拡張機能を追加。
ESLintさらに、プロジェクト設定を追加。
setting.json{ "eslint.autoFixOnSave": true, "eslint.validate": [ "javascript", { "language": "typescript", "autoFix": true }, { "language": "vue", "autoFix": true } ], }Prettierの設定追加
.prettierrcをルートディレクトリに追加する。{ "tabWidth": 2, "semi": true, "singleQuote": true }
.eslintrc.jsのrulesに追加してもOKeslintrc.jsmodule.exports = { root: true, env: { node: true }, extends: ["plugin:vue/essential", "@vue/prettier", "@vue/typescript"], rules: { "no-console": process.env.NODE_ENV === "production" ? "error" : "off", "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off", // 以下を追加 "prettier/prettier": [ "error", { "singleQuote": true, "semi": false } ] }, parserOptions: { parser: "@typescript-eslint/parser" } };ESLintの実行
デフォルトの設定だと、Linterが勝手に修正してしまう。
https://teratail.com/questions/186587無効化したい場合は、
package.jsonを修正するpackage.json{ "name": "myproject", "version": "0.1.0", "private": true, "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", // --no-fixを追加 "lint": "vue-cli-service lint --no-fix", // 追加 "lint:fix": "vue-cli-service lint" }, "dependencies": { // 各種ライブラリ }, "devDependencies": { // 各種ライブラリ }ESLintを実行
# npm run lint警告が多数検出されたら、正常に動作している。
warning: Replace `"Avenir"` with `'Avenir'` (prettier/prettier) at src/App.vue:13:16:補足
既存のプロジェクトをTSLintからESLintに切り替える場合は、色々ライブラリを追加する必要があるみたい
Vue.jsでtypescript-eslint + Prettierを導入する
- 投稿日:2019-08-28T05:14:28+09:00
【Vue初心者向け】超シンプルなお買い物リストアプリを作る
Vue.jsで作ったシンプルなサンプルコードです。
対象者は、Vue.jsを始めたところで、色々サンプルコードをいじってみたい人です。
商品名、個数を入力して登録すると買い物リストが表示されます。重要な機能のコードが分かるよう、エラー処理はしていません。
実際に動作はこちらで確認できます。
お買い物リストアプリ<template> <div class="shopping_component"> <section> <div class="input_data"> <p>買うもの:<input v-model="name" type="text" placeholder="買うもの"></p> <p>個数:<input v-model="number" type="text" placeholder="個数"></p> </div> <button @click="input">登録する</button> </section> <section> <div class="shopping_list"> <li v-for="(item, index) in shoppingList" :key="index"> {{item.name}}{{item.number}}個 <button @click="deleteItem(index)">削除</button> </li> </div> </section> </div> </template> <script> export default { data(){ return{ name: '', number: 1, shoppingList: [] } }, methods:{ input(){ var item = {name:this.name, number: this.number} this.shoppingList.push(item) this.name = '' }, deleteItem(index){ this.shoppingList.splice(index, 1) } } } </script> <style scoped> </style>ポイントは、配列をv-forで表示する時にindexにつけることです。indexをつけておけば、削除ボダンにこのindexを渡すことで簡単に該当する項目を削除できます。
splice(index,1)は「index番目から始める要素を1つ削除してね」という意味です。宣伝:ブログやっています→ ブログ

































