- 投稿日:2021-10-31T22:10:08+09:00
【学習記録⑮】Vue Routerを用いてURLごとに表示を切り替えてみる!
はじめに Vue.jsを最近勉強し始めたので学んだ文法などを備忘録としてメモしていこうと思います。 今回はVue Routerを用いてページごとに表示を切り替える方法について記載していきます。 Vue Router Vue RouterはVue.jsにおいてルーティングを制御するためのライブラリです。 ※現在僕の学習環境はVue.js 3のため、Vue Routerのバージョンは4で動作確認をしています。 セッティング まずはVue Routerをインストールします。 npm install vue-router@4 ルートファイルの設定 上記にてvue-routerをインストール後、router.jsなどのファイルを作成し、以下のようにrouterの設定を行います。 インストールしたvue-routerからcreateRouter, createWebHistoryをimportします。 createRouterメソッドがルーティング情報を生成し、createWebHistory()はhistoryモードを指しています。 historyモードに設定することでURLに'#'などが付かなくなります。 (createWebHashHistory()を設定するとURLに'#'が付きます。) 今回はMorningページとAfternoonページを用意しているのでそれぞれをroutesにセットします。 router.js import Morning from './views/Morning.vue'; import Afternoon from './views/Afternoon.vue'; import { createRouter, createWebHistory } from 'vue-router'; const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', component: Morning }, { path: '/afternoon', component: Afternoon } ] }); export default router; Main.jsでの呼び出し 上記で設定したルーター情報をMain.jsで呼び出します。 Main.js import { createApp } from 'vue'; import App from './App.vue'; import router from './router'; createApp(App).use(router).mount('#app'); ルート先それぞれのコンポーネント 今回はMorningページとAfternoonページを使用するので、それらのVueファイルを作成します。 Morning.vue <template> <div>おはよう</div> </template> Afternoon.vue <template> <div>こんにちは</div> </template> 出力結果 npm run serveコマンドを実行し、結果を見てみます。 URLがlocalhost:8080のときはMorningページが出力されていることが分かります。 URLがlocalhost:8080/afternoonのときはAfternoonページが出力されていることが分かります。 おわりに 今回はVue Routerを利用してURLごとにページを切り替える方法を学びました。 次回はrouter-linkタグを用いて画面からURLを切り替えていく方法についてまとめていこうと思います。
- 投稿日:2021-10-31T18:48:51+09:00
【Vue / Nuxt】inputコンポーネントにenterでフォーカス移動する
input内でenterを押下した際に次のinputにフォーカスさせる処理、よくありますよね。 フォーカスしたいinputがコンポーネントの時に悩んだので備忘録です。 子コンポーネントの書き方 Input.vue <template> <div> <input ref="input" :value="value" :type="type" :placeholder="placeholder" @keydown="event=>$emit('focus', event)" /> </div> </template> <script> export default { name: 'Input', props: { type: { type: String, required: false, default: 'text' }, value: { type: String, required: false, default: '' }, placeholder: { type: String, required: false, default: '' } }, methods: { focus () { this.$refs.input.focus() } } } </script> 親コンポーネントの書き方 コンポーネントのinput -> 通常input -> コンポーネントのinputの順でフォーカス移動するサンプルにしました。 index.vue <template> <div> <Input :value="value" type="text" placeholder="name" @focus="event=>nextFocus(event,'emailRef')"/> <input ref="emailRef" :value="value" type="text" placeholder="email" @keydown="event=>nextFocus(event,'passwordRef')"/> <Input ref="passwordRef" :value="value" type="text" placeholder="password"/> </div> </template> <script> import Input from '@/components/Input.vue' export default { components: { Input }, data() { return { value: '' } }, methods: { nextFocus(event, refName) { if (event.keyCode != 13) {return} this.$refs[refName].focus() } } } </script> 解説 Input.vue <input ref="input" :value="value" :type="type" :placeholder="placeholder" @keydown="event=>$emit('focus', event)" /> 子コンポーネント側の@keydown="event=>$emit('focus', event)"で、何かしらキーが押下されるたびにeventを渡すfocusメソッドを読んでいます。 このeventを元にフォーカス処理をするために@focus="event=>nextFocus(event,'ref名')"でメソッドを呼びます。 通常のinputの場合は直接@keydownで問題ありません。 index.vue nextFocus(event, refName) { if (event.keyCode != 13) {return} this.$refs[refName].focus() } nextFocusメソッドでイベントと対象のref名をもらいます。今回はenterの場合に移動したいので、keyCodeが13(enter)の時以外はなにも処理しません。 this.$refs[refName].focus()で受け取ったref名に対して focus処理をしています。 Input.vue focus () { this.$refs.input.focus() } フォーカス先がコンポーネントの場合、コンポーネント(Input)のrefではなく、コンポーネント内に実際に書かれているinput要素にフォーカスする必要があります。 そのため実際にフォーカスしたいコンポーネント内のinputに対するフォーカスのメソッドが必要になります(説明が下手ですみません) 私はこれを書かなかったことによりfocus() is undefinedになり原因解明に時間がかかってしまいました。。。 最後に 他にもっといい書き方がありそうな気がしますが、フォーカス移動付きコンポーネントに関する記事が全く見つからなかったので私にはこれが限界でした。。。 今の現場では$listenersを使用する方法で記述していましたが、vue3では廃止されているようなので自分で考えて書いてみました。ものすごく時間がかかった。。。 もっといい書き方があるよ〜とか、俺ならこう書くぜ!などコメントいただけると大変嬉しいです。 最後まで読んでいただきありがとうございます!
- 投稿日:2021-10-31T17:58:39+09:00
【学習記録⑭】transition-groupを用いてリストのトランジションを実装する!
はじめに Vue.jsを最近勉強し始めたので学んだ文法などを備忘録としてメモしていこうと思います。 今回はtransition-groupを用いてv-for等の複数のタグが作成される場面でトランジションを実装していきたいと思います。 transition-group transition-groupはv-for属性等を用いて複数のタグが作られる際にそれらに対してまとめてトランジションを適用したい場合に付けます。 例えば以下の場合、transitionタグで囲っても正常にトランジションは動作しません。 example.vue <li v-for="number in numbers" :key="number"> {{ number }} </li> また、transaction-groupタグを用いる際は必ずkey属性を付ける必要があります。 以上を用いてサンプルを作ってみる 以上を用いてサンプルを作ってみます。 内容としては、初期状態で画面上に数字の「1,2,3」があり、数字追加ボタンをクリックすると4以降の数字が順番に追加され、対象の数字にカーソルをあててクリックするとその数字が削除されるというものとなっています。 App.vue <template> <numbers></numbers> </template> <script> import Numbers from "./components/Numbers.vue"; export default { components: { Numbers }, }; </script> Numbers.vue <template> <button @click="addNumber">数字追加</button> <transition-group name="fade"> <li v-for="(number, index) in numbers" :key="number" @click="remove(index)"> {{ number }} </li> </transition-group> </template> <script> export default { data() { return { numbers: [1, 2, 3], nextNumber: 4, }; }, methods: { addNumber() { this.numbers.splice(this.numbers.length, 0, this.nextNumber++); }, remove(index) { this.numbers.splice(index, 1); }, }, }; </script> <style scoped> .fade-enter-from { opacity: 0; } .fade-enter-active { transition: opacity 0.5s; } .fade-enter-to { opacity: 1; } .fade-leave-from { opacity: 1; } .fade-leave-active { transition: opacity 0.5s; } .fade-leave-to { opacity: 0; } </style> 結果 以下のようにボタンをクリックしたら数字が追加され、数字をクリックしたらその数字が消えることが分かります。 おわりに transition-groupを用いてv-for属性がセットされた要素に対してまとめてレンダリングをすることが出来ました。 transitionは結構難しいですがしっかり理解していきたいと思います。
- 投稿日:2021-10-31T15:21:04+09:00
【学習記録⑬】カスタムトランジションクラスとAnimate.cssを用いてアニメーションを実装する!
はじめに Vue.jsを最近勉強し始めたので学んだ文法などを備忘録としてメモしていこうと思います。 今回はカスタムトランジションクラスとAnimate.cssを用いてアニメーションを実装する方法について記載していきます。 カスタムトランジションクラス 前回の記事ではtransitionコンポーネントのname属性に任意の名前を付け、その属性を用いてstyleタグ内にて組み込みのトランジションクラスへCSSを適用しました。 今回利用するカスタムトランジションクラスは任意のクラス名を組み込みのトランジションクラスのように使いたいとき(説明が難しくてこんな表現ですみません...)に利用します。 例えば、今回利用するAnimate.cssではライブラリが用意したクラス名をトランジションクラスに利用したいのですが、前回の記事の内容ではクラス名は組み込みのものを利用しているため、ライブラリが用意したクラスを利用することができません。 そこで任意のクラスを用いたいが、だがしかし組み込みのトランジションクラスのように特定の発火時を指定したい(v-enter-activeやv-leave-activeなど)ときに、このカスタムトランジションクラスを使います。 利用方法 利用方法は割と単純でtransitionタグに以下のように特定のカスタムトランジションクラスを用意し、その中に任意のクラス名を入れます。各トランジションクラスについてはそれぞれ組み込みのトランジションクラスの意味と同様です。 exampleTemplate.vue <template> <transition enter-from-class="任意のクラス名" enter-active-class="任意のクラス名" enter-to-class="任意のクラス名" leave-from-class="任意のクラス名" leave-active-class="任意のクラス名" leave-to-class="任意のクラス名" > </transition> </template> 以上を用いてサンプルを作ってみる それでは以上を用いてサンプルコードを作ってみます。 今回はおはようボタンをクリックし、あいさつ文が現れたり消えたりする内容にします。文字が現れる際はAnimate.cssのbounceモーションが、文字が消える際はAnimate.cssのflashモーションが適用されるようにしていきます。 Animate.cssはanimate__animated animate__動作のようにクラス名をセットすることで利用が出来ます。 (今回のサンプルでは省略していますが、ライブラリ参照についてはCDNを利用しており、index.htmlファイルにその設定をしています。) Morning.vue <template> <button @click="show = !show">おはようボタン</button> <transition enter-active-class="animate__animated animate__bounce" leave-active-class="animate__animated animate__flash" > <div v-if="show">{{ greetMessage }}</div> </transition> </template> <script> export default { data() { return { greetMessage: "Good Morning!", show: true, }; }, }; </script> App.vue <template> <morning></morning> </template> <script> import Morning from "./components/Morning.vue"; export default { components: { Morning }, }; </script> 結果 以下のように文字が現れる際はbouceが、消える際はflashが適用されていることが分かります。 おわりに 今回Vue.jsの勉強をしていて偶然Animate.cssを見つけたのですが、これとても便利ですね! 今後アニメーションを実装したいと思った際はこちらをぜひ使ってみようと思います!!
- 投稿日:2021-10-31T12:40:42+09:00
【学習記録⑫】transitionコンポーネントを用いてアニメーションを作ってみる!
はじめに Vue.jsを最近勉強し始めたので学んだ文法などを備忘録としてメモしていこうと思います。 今回はtransitionコンポーネントを用いてアニメーション(簡単なフェードイン、フェードアウト)を作ってみようと思います。 transitionコンポーネント Vue.jsでアニメーションを実装する際は組み込みコンポーネントであるtransitionコンポーネント、もしくはtransition-groupコンポーネントを用いて実装します。 基本的な使い方 基本的な使い方としては以下のようにアニメーションさせたい部分をtranasitionコンポーネントで囲み、name属性へ任意の値を入れます。 exampleTemplate.vue <template> <transition name="任意の値"> <div></div> </transition> </template> その後、上記で付けた「任意の値」を用いて以下のクラスを作成します。 [任意の値]-enter-from [任意の値]-enter-active [任意の値]-enter-to [任意の値]-leave-from [任意の値]-enter-active [任意の値]-enter-to 以下は「任意の値」をfadeとしたときの例です。 exampleStyle.vue <style scoped> .fade-enter-from { /* 処理 */ } .fade-enter-active { /* 処理 */ } .fade-enter-to { /* 処理 */ } .fade-leave-from { /* 処理 */ } .fade-leave-active { /* 処理 */ } .fade-leave-to { /* 処理 */ } </style> これらのクラスをトランジションクラスと言い、それぞれの意味や発火時については以下のドキュメントが参考になります。 以上を用いてサンプルを作ってみる 以上を用いて、サンプルコードを書いてみます。 内容としてはおはようボタンというボタンをクリックするとGood Morning!という文字がフェードインしてくるものとします。 サンプルコード Morning.vue <template> <button @click="show = !show">おはようボタン</button> <transition name="fade"> <div v-if="show">{{ greetMessage }}</div> </transition> </template> <script> export default { data() { return { greetMessage: "Good Morning!", show: true, }; }, }; </script> <style scoped> .fade-enter-from { opacity: 0; } .fade-enter-active { transition: opacity 0.5s; } .fade-enter-to { opacity: 1; } .fade-leave-from { opacity: 1; } .fade-leave-active { transition: opacity 0.5s; } .fade-leave-to { opacity: 0; } </style> App.vue <template> <morning></morning> </template> <script> import Morning from "./components/Morning.vue"; export default { components: { Morning }, }; </script> 結果 以下のように挨拶文がフェードイン・フェードアウトしていることが分かります。 おわりに 今回はtransitionコンポーネントを用いたアニメーション作成の学習を行いました。 次回はAnimate.cssを用いて色々なアニメーションを実装してみたいと思います。
- 投稿日:2021-10-31T00:15:47+09:00
コンポーネントは compnents 以下にフラットに全部置くのが良い
はじめに 巷では Vue.js や React など、コンポーネント指向フレームワークにおいて、どのようにコンポーネントのディレクトリを切り分けるか について議論がなされているようです。 Atomic Design ベースの Vue コンポーネント設計 Atomic Designをやめてディレクトリ構造を見直した話 なに?マクドナルドから学ぶ、優れたcomponentsディレクトリ構造?! 私自身も、ここ 1.5 年ほどフロントエンドの開発を行っており、いくつかのディレクトリ構造を経験しました。 結論、components 以下に全てのコンポーネントをフラットに配置するのが一番しっくり来ています。 フラット構造がオススメの理由 とりあえず概要だけ先に書いておきます。 1年ほど前から全社的に導入しているが、この方法で全く困ったことがない。 どのフォルダに入れるかを全く考えなくていい。 検索が容易。 フラットなディレクトリ構造を実践してみる こんな感じです。 src ├── components │ ├── AppBackButton │ ├── AppSubmitButton │ ├── ArticleCard │ ├── ArticleTextEditor │ ├── ArticleTextColorPallet │ ├── BaseInput │ ├── BaseSelect │ ├── BaseTextArea │ ├── ProfileCard │ ├── ProfileForm │ ├── ProfileFormLayout │ └── ProfileGenderSelect └── pages ├── ArticleListPage ├── ArticleEditPage ├── ProfilePage └── ProfileEditPage ポイント: 命名規則 全てのコンポーネントは原則として 属性 + 要素 という形式で命名されています。 ArticleTextColorPallet Article = 記事投稿機能に関連する TextColorPallet = テキストの色選択要素 AppBackButton App = アプリケーション全体で共通の BackButton = 戻るボタン このように名前を付けることで、どの機能に関連するものなのか、どのような要素なのか、が明確になります。 機能をまたがって使う場合は、App やプロダクト名等のプレフィックスを付けましょう。 検索するときも、機能 → 要素 と絞り込んでいけるので楽です。 ポイント: Base コンポーネント Base という名前がついているコンポーネントは、プロジェクト全体で使われる最も基本的な要素 を指しています。 Atomic Design で言うところの Atoms に相当します。 もちろん Base 以外のプレフィクスを付けても OK です。 チームで合意が取れていれば Core でも Hoge でも何でも OK です。 ポイント: page ディレクトリ 各ページ最上位に当たるコンポーネントは page 以下で管理します。 「全て」フラットじゃないのかよ!!というツッコミもあるかと思います。すいません。 別に components/ だけ問題はありません。Page という要素であることが明確だからです。 我々のチームでは、Page 以外で api 等のリソースを直接使ってはいけない、というルールを敷いていたので、ディレクトリを分けて、Page コンポーネントが特別であるということを表現しました。 他のやり方との比較 Atomic Design 私自身 Atomic Design のディレクトリ構造を試したことがありますが、どのディレクトリかを考えるのは結構大変です。 Atoms は割と決めやすいですが、 molecules と organisms は基準が曖昧になりがちです。 時間をかけて分類しても、得られるものが少なすぎました。 機能ごとにディレクトリを切る方法 先程の例の、Article Profile のような機能ごとにディレクトリを切ってみたりもしていました。 このやり方は、機能ごとにコンポーネントが見やすくなるという点では優れています。 一方で、次のような状況が発生します。 src └── components ├── article | ├── Card // 名前が同じ! | ├── TextEditor | └── TextColorPallet └── profile ├── Card // 名前が同じ! ├── Form └── GenderSelect この状態でファイル名で検索すると Card コンポーネントが複数表示されます。 もちろんディレクトリ名を見れば特定できますが、VsCode の ctrl + p での検索では、ディレクトリ名はやや見づらいです。 細かいことですが、コーディング中は何回も繰り返す動作なので、効果はかなり大きいです。 その他 命名規則は徹底する チーム内で命名規則を決めて、徹底することが大切です。 徹底できれば、名前だけでスコープと機能を伝えることができるようになります! 車輪の再開発を防げる 「こういうコンポーネントつくらないとな...」と思ったときに、ファイル検索をすると、実はもう既に存在していた! みたいなことがちょいちょいあります。 components ディレクトリが巨大になる問題 また、components ディレクトリが巨大なりすぎるんじゃないの? という疑問もあるかも知れません。 はい、なります。開くとズラーッとコンポーネントが表示されます。 でも問題となったことはありません。コンポーネントファイルは検索して開けば良いのです。 命名が長くなりすぎる問題 ArticleTextColorPallet とかは長いな、と感じた方もいるかも知れません。 確かに長いですが、それで問題になったことはありません。 むしろ名前が長いコンポーネントは、それだけ狭い範囲で使われているコンポーネントなんだ、ということが分かります。 逆に名前の短いものは、汎用的で広い範囲で使われているコンポーネントであることが分かります。(例外もありますが。) まとめ いろんなコンポーネント管理方法が記事になっていますが、フラットに管理する、というものはあまり見ないので書いてみました。 もちろんプロジェクトの規模によってベストな方法は変わってくるとは思います。 ですが、我々の社内では小さいプロジェクトから大きいプロジェクトまでこの方法を採用していますが、困ったことは一度もありません。 迷っていたら、是非試してみてください。