- 投稿日:2020-11-27T23:20:33+09:00
Codeignater3を使ったMPAサイトからNuxt.js+Vueへのサイトリニューアル
はじめに
Vue.js(CDN版)を採用したPHP動的サイトから、Nuxt.js+Vueを使ったいわゆるSPAサイトへのリニューアルを敢行した。
経緯と歴史
最初は、フレームワークを使わないサイトとして設計したが、のちにSmatryを採用し、Viewとロジックを分離した第二世代をリリース。その後、Codeignater3を採用し、本格的にPHPフレームワークを採用した第三世代と進化していったが、リプレースの切っ掛けはいずれも機能拡張を繰り返し、いずれも 現状に限界を感じよりモダンな技術を採用していった経緯がある 。
今回は何が限界だったのか
Vueライブラリの複雑化
当初はJqueryを採用していたが、Vue.jsの導入に合わせライブラリが複雑化し、バージョンアップへの不安と煩雑さがつきまとうことになった。
痒いところに手が届かないフレームワークとViewのカスタマイズの煩雑化
UIフレームワークとして採用していたMaterializeはVue前提ではないため、開発を進めるにつれCSSをカスタマイズを行う面が多くなり、フレームワークのメリットが少なくなるとともに、CSSの開発に多くの時間が取られることになった。
更新手順およびViewの煩雑化・複雑化
ページが複雑化するに伴い、PHPのinclude機能で使い回すView画面がスパゲティ化するようになり、速度向上で導入したPWAのServiceWorkerのバージョンを手作業で書き換えるなどの更新の手間が極めて煩雑になりつつあった。
ベストプラクティスな技術を試したい
こうした状況が重なり、最新のフロントエンドのベストプラクティスとも言える技術で再構築を検討することとなった。当初はログインシステムの関係からVue-Cliのみを導入し、MPAのままの構築を行う事も検討したが、ユーザーへのID・パスワードの再設定のデメリットを考慮しても、Firebase Authenticationを採用した方が、セキュリティ面やプログラミング・維持などあらゆる場面でメリットがあると判断。Nuxt.js+VueによるSPAを採用することとなった。
開発
バックエンド
SPAとなれば、必然的にフロントとバックエンドが分離されるが、リニューアル前より無限スクロールを採用していたことから部分的にCodeignaterにAPIを実装し、axiosを用いた非同期通信で情報を取得ていたこともあり、開発時間短縮のために、バックエンドは引き続きCodeignaterを改良およびリファクタリングしてそのまま採用することとなった。
フロントエンド
Vue3およびTSの採用については現時点では見送ることとして、Webにサンプルなどのドキュメントが豊富なVue2.6.11とJSを採用した。
UIフレームワークはvuetifyを採用。最初はとっつきにくかったけど、高機能でデザインの完成度が高いので慣れてしまえば本当に楽。最初からコンポーネント至高なので、こちらも楽だが、無秩序にやってしまうとまたスパゲティになるので注意したい。開発
10月頭に開発がスタートをして、形になるリリースまで1ヶ月半。細かな機能追加と調整に二週間程度で完成することになった。
感想
今回のリニューアルは技術的に本当に勉強になりましたし、サイトの管理と開発が本当に楽になりました。フロントとバックを分離した疎結合化は精神的にも楽になった感があります。Nuxt.jsは現時点でのベストプラクティス的な技術ではありますが、技術的に未熟で採用できないという事情はあるにしろ、基礎を習得しないと応用はできないとはいえ、随分と遠回りした印象もあります。これまでは煩雑な保守管理に時間を浪費していましたが、今後のページはペラ1でも無い限りNuxt.jsファーストで行きたいと思います。
- 投稿日:2020-11-27T21:25:21+09:00
【Vue.js】checkboxでclickイベントが反応しない
checkboxをチェックした時のイベントは、
change イベントで発生する。
clickでは反応しないので注意。
<b-form-checkbox id="hoge-label" v-model="hoge.fuga" @change="hogeFunction">hogefuga</b-form-checkbox>
- 投稿日:2020-11-27T18:30:39+09:00
Vue-multiselectのカスタマイズ方法
概要
Vue-multiselectはセレクトボックスを簡単に実装できる便利なVueライブラリです。
複数選択や自動補完など一般的にセレクトボックスに求められる機能はほぼ全て実現できます。
ここでは公式サイトを元にVue-multiselectのカスタマイズ方法の一部を紹介します。基本の使い方
上図のようにシンプルな単一選択のセレクトボックスは以下のコードで実装できます。
なおCDNを利用するとVue-multiselectを簡単に試せます。See the Pen RwGwBaO by shi-ma (@shi-ma) on CodePen.
options
プロパティには選択肢に設定したい配列を指定します。
custom-label
プロパティに関数を指定すると、その返り値が選択肢として表示されるラベルとなります。
options
が連想配列で各キーのバリューを組み合わせたラベルを作りたい時などは非常に便利です。
一つのキーのバリューのみをラベルとして表示したいときは、代わりにlabel
プロパティを使いlabel=country
というような書き方ができます。
custom-label
やlabel
は必須プロパティではありませんが、options
が単なる配列でなく、連想配列の場合は設定しないと要素がそのまま表示されてしまいます。Events
Vue-multiselectにはイベントプロパティが用意されており、ユーザーの操作をトリガーにして関数を実行することが可能です。
イベントプロパティ一覧
プロパティ名 トリガー @input this.valueの値が変わる @select 選択肢を選ぶ @remove 複数選択の時に選択を取り消す @search-change 検索クエリが変更される @tag タグが追加される @open ドロップダウンが開かれる @close ドロップダウンが閉じられる @removeの利用例
See the Pen Untitled2 by shi-ma (@shi-ma) on CodePen.
例えば複数選択をオン(
multiple="true"
)にして@remove
プロパティを上記のように設定すると、選択を取り消した時にアラートが表示されます。自動補完
Vue-multiselectはデフォルトで自動補完機能がオンになっており、オフにしたい時は
searchable
プロパティをfalse
にします。
この自動補完はlabel
プロパティの値(custom-label
プロパティを指定していればその値)を元に候補を絞っています。もし独自の検索条件を設定したい場合はカスタマイズできます。
カスタマイズ例
See the Pen VwKwBMN by shi-ma (@shi-ma) on CodePen.
internal-search
プロパティをfalse
にするとVue-multiselectの内部検索エンジンがオフになり、options
を自由に設定できるようになります。
@search-change
に指定した関数は検索クエリに変更がある度に実行され、さらに関数の第一引数には検索クエリが入ります。これを利用し、options
をフィルタリングするような関数を書けば、検索クエリが変わる度にoptions
が更新されるようになり、自動補完機能を代替できます。終わりに
Vue-multiselectは用途に合わせてカスタマイズできる余地が大きいライブラリです。
ここでは現時点で日本語での説明が比較的少ない機能を紹介しましたが、Vue-multiselectには面白いカスタマイズ方法がまだまだあります。
Vueでセレクトボックスを実装するときはぜひVue-multiselectをお試しください。
- 投稿日:2020-11-27T18:30:39+09:00
セレクトボックスライブラリ「Vue-multiselect」のカスタマイズ方法
概要
Vue-multiselectはセレクトボックスを簡単に実装できる便利なVueライブラリです。
複数選択や自動補完など一般的にセレクトボックスに求められる機能はほぼ全て実現できます。
ここでは公式サイトを元にVue-multiselectのカスタマイズ方法の一部を紹介します。基本の使い方
上図のようにシンプルな単一選択のセレクトボックスは以下のコードで実装できます。
なおCDNを利用するとVue-multiselectを簡単に試せます。See the Pen RwGwBaO by shi-ma (@shi-ma) on CodePen.
options
プロパティには選択肢に設定したい配列を指定します。
custom-label
プロパティに関数を指定すると、その返り値が選択肢として表示されるラベルとなります。
options
が連想配列で各キーのバリューを組み合わせたラベルを作りたい時などは非常に便利です。
一つのキーのバリューのみをラベルとして表示したいときは、代わりにlabel
プロパティを使いlabel=country
というような書き方ができます。
custom-label
やlabel
は必須プロパティではありませんが、options
が単なる配列でなく、連想配列の場合は設定しないと要素がそのまま表示されてしまいます。Events
Vue-multiselectにはイベントプロパティが用意されており、ユーザーの操作をトリガーにして関数を実行することが可能です。
イベントプロパティ一覧
プロパティ名 トリガー @input
this.valueの値が変わる @select
選択肢を選ぶ @remove
複数選択の時に選択を取り消す @search-change
検索クエリが変更される @tag
タグが追加される @open
ドロップダウンが開かれる @close
ドロップダウンが閉じられる @removeの利用例
See the Pen Untitled2 by shi-ma (@shi-ma) on CodePen.
例えば複数選択をオン(
multiple="true"
)にして@remove
プロパティを上記のように設定すると、選択を取り消した時にアラートが表示されます。自動補完
Vue-multiselectはデフォルトで自動補完機能がオンになっており、オフにしたい時は
searchable
プロパティをfalse
にします。
この自動補完はlabel
プロパティの値(custom-label
プロパティを指定していればその値)を元に候補を絞っています。もし独自の検索条件を設定したい場合はカスタマイズできます。
カスタマイズ例
See the Pen VwKwBMN by shi-ma (@shi-ma) on CodePen.
internal-search
プロパティをfalse
にするとVue-multiselectの内部検索エンジンがオフになり、options
を自由に設定できるようになります。
@search-change
に指定した関数は検索クエリに変更がある度に実行され、さらに関数の第一引数には検索クエリが入ります。これを利用し、options
をフィルタリングするような関数を書けば、検索クエリが変わる度にoptions
が更新されるようになり、自動補完機能を代替できます。終わりに
Vue-multiselectは用途に合わせてカスタマイズできる余地が大きいライブラリです。
ここでは現時点で日本語での説明が比較的少ない機能を紹介しましたが、Vue-multiselectには面白いカスタマイズ方法がまだまだあります。
Vueでセレクトボックスを実装するときはぜひVue-multiselectをお試しください。
- 投稿日:2020-11-27T17:16:24+09:00
Laravel × Vue.jsでハマった簡単なエラー
ターミナルで下記の様に表示された際は、このエラーの上で右クリック+許可するだけ
ESLint is disabled since its execution has not been approved or denied yet. Use the light bulb menu to open the approval dialog.
google先生に頼りすぎていたせいか、思考力が低下していた。気をつけよう・・・
- 投稿日:2020-11-27T16:13:59+09:00
vee-validateで他のフィールド値も含めてバリデーションする方法
始めに
フォームのバリデーションで、他のフィールド値と関連したバリデーションをしたいことがあると思います。
例
+ 最低値から最大値の範囲
+ 開始日から終了日の範囲vee-validateでは
@名前
でValidationProviderの名前を探してその値を入れて渡すことができるため、それでチェックすることが可能です。@名前でパラメータを渡す方法ValidationObserver //- 他のValidationProviderで設定したnameから値を参照する ValidationProvider( rules="max_value:@max" v-slot="{ errors }" ) input( v-model="$data.minValue" type="number" ) .error {{ errors[0] }} //- nameを設定しておく ValidationProvider( name="max" rules="" ) input( v-model="$data.maxValue" type="number" )https://logaretm.github.io/vee-validate/advanced/cross-field-validation.html#targeting-other-fields
これでバリデーションはできるようになりましたが、エラー文言をもう一方の入力フィールドに伝えることができません。なので、エラー文言の表示のやり方を工夫する必要があります。
ここではエラーの表示方法についていくつか案を出したので参考にしてもらえれば幸いです。
バリデーション結果をdataに持って表示する方法
一番単純なのは手動でバリデーションして、その結果をdataに持つやり方です。vee-validateの自動でバリデーションするメリットを潰してしまいますが、これが一番愚直な方法だと思います。
バリデーション結果をdataに持って表示する方法<template lang="pug"> ValidationObserver div ValidationProvider( ref="provMin" rules="min_value:0|max_value:@max" v-slot="{ errors, invalid }" ) input( v-model="$data.min" :class="{ '-error': invalid }" type="number" ) ValidationProvider( name="max" ref="provMax" rules="max_value:10" v-slot="{ errors, invalid }" ) //- 両方のエラーのスタイルを当てる場合はref経由でエラーのルールを調べる必要がある(あるいはdataで持っておくか) input( v-model="$data.max" :class="{ '-error': invalid || ($refs.provMin && !!$refs.provMin.failedRules.max_value) }" type="number" ) .error {{ $data.errorMessage }} </template> <script> export default { data() { return { min: 0, max: 10, }; }, created() { this.$watch( () => [this.$data.min, this.$data.max], async () => { await this.$nextTick(); // バリデーションしてから結果を代入する await this.$refs.provMin.validate(); await this.$refs.provMax.validate(); this.$data.errorMessage = this.$refs.provMin.errors[0] || this.$refs.provMax.errors[0]; } ); }, }; </script>PortalVueで表示場所を移動する
DOMの場所は変えませんが、PortalVueを使って最終的に表示位置を移動する方法です。手動でバリデートを実行する必要は無くなりましたが、エラー文言を1つだけにする場合はPortalを使うタイミングを調整する必要があるので少し手間です。
PortalVueで表示場所を移動する<template lang="pug"> ValidationObserver div ValidationProvider( ref="provMin" rules="min_value:0|max_value:@max" v-slot="{ errors, invalid }" ) input( v-model="$data.min" :class="{ '-error': invalid }" type="number" ) //- エラーの時だけportalを通す template(v-if="invalid") Portal(to="error") div {{ errors[0] }} ValidationProvider( name="max" ref="provMax" rules="max_value:10" v-slot="{ errors, invalid }" ) input( v-model="$data.max" :class="{ '-error': invalid || ($refs.provMin && !!$refs.provMin.failedRules.max_value) }" type="number" ) //- 前のバリデーションが通っている時だけportalを通す template(v-if="invalid && ($refs.provMin && $refs.provMin.flags.valid)") Portal(to="error") div {{ errors[0] }} .error PortalTarget(name="error") </template>一つにまとめたコンポーネントを使う
今まで見たやり方はrefを使ったり少しトリッキーなことをしたりするので扱いづらかったと思います。なので今度はもうシンプルに入力範囲フォームという一つのコンポーネントを作ってしまい、それをバリデーションするという方法です。
凄くシンプルになりましたが、この場合は片方だけバリデーションするということができなくなります。一つにまとめたコンポーネントを使う<template lang="pug"> ValidationObserver ValidationProvider( rules="range_value:0,10" v-slot="{ errors }" ) //- 一つのコンポーネントにまとめる InputRange( v-model="$data.range" :errorMessage="errors[0]" ) </template>終わりに
以上が他のフィールド値も含めてバリデーションする方法でした。どれも一長一短があると思いますが、最後に説明した一つにまとめたコンポーネントを使うのがスッキリしているのかなと思いました。
最後にサンプルコードを共有しますので、興味がある方は是非見てください。
- 投稿日:2020-11-27T16:04:08+09:00
Vuetifyでもっと早く知りたかったこと
はじめに
プログラミング未経験のわたしが初めて UI framework を利用するにあたって、「もっと早く知っておけば!」と思った情報をまとめておきます。
大前提
v-app の中で使用してください。
公式:Application serviceSee the Pen vuetify needs v-app by msickpaler (@msickpaler) on CodePen.
Grid System
Vuetify.js 2.2 の GridSystem について
この記事見ればだいたい分かります。特に v-container, v-row, v-col についてはこちらを参照してください。v-navigation-drawer(サイドバー)
メインコンテンツと被ったとき
その時は、メインコンテンツを v-main で囲ってください(Vuetify 使うと決まったらすぐにやっておくべき)。
ちなみにv-snackbarやv-dialogなどが何かと被ったときはcssのv-indexを使って前に出してもokです。See the Pen navigation without <v-main> by msickpaler (@msickpaler) on CodePen.
なんか表示崩れたとき
サイドバーが原因なら、app プロップス使えば直ります。
See the Pen navbar without app props by msickpaler (@msickpaler) on CodePen.
ユーザーアイコンを一番上に置きたいとき
上ならprepend、下ならappendを指定すればok
See the Pen navbar prepend by msickpaler (@msickpaler) on CodePen.
breakpoint
めちゃくちゃ便利。
公式:Display Breakpoints
以下はサイドバーの例で
- md 以上の大きさで常時表示
- sm 以下でトグル式
- xs 以下でトグル式かつ下から表示
が切り替えられます。
See the Pen toggle by display size by msickpaler (@msickpaler) on CodePen.
- 投稿日:2020-11-27T14:21:25+09:00
【Nuxt.js】Nuxt実践編:パンくずリストを作ろう
? この記事はWP専用です
https://wp.me/pc9NHC-S8前置き
今回はパンくずリストを作成します?
すごくシンプルに、
コンポーネント作成のコツを
簡単に理解できるので
ぜひやってみてください✨?構成
アトミックデザイン
⬇️アトミックデザインや
分け方についてはこちら他にもいくつか書いているので
ブログ内で検索してみてください?パンくずリストはナビの役割なので
templatesに入れています??また、パンくずリストは
ヘッダーに入れたりするのが基本ですが、
今回は表示ができれば良いので
index.vueでimportしてもらえればOKです?♀️filecomponents/ --| templates/ ----| navs ------| NavBread.vue pages/ --| index.vue使用するもの
CSS
NavBread.vuefontsize: 12px; color: rgba(0, 134, 231, 0.8);paddingは大体で良いです?
⬇️横並びはFlexboxにしましょう!
【Nuxt.js】Nuxt実践編:Flexboxを使おう!template
ABOUTページを開いている状態で、
TOPへのリンクをしてください?また、画像はSVGを使用してみましょう!
できる方はSVGコンポーネントを作成しましょう?♀️
https://iconmonstr.com/arrow-25-svg/Let's try!
まずは答えを見ずにやってみましょう♪
答え
? 続きはWPでご覧ください?
https://wp.me/pc9NHC-S8
- 投稿日:2020-11-27T13:59:58+09:00
【Nuxt.js】Nuxt実践編:Flexboxを使おう!
? この記事はWP専用です
https://wp.me/pc9NHC-TP前置き
CSSでよく使う
flexプロパティを使ってみましょう?
横並びや中央揃えが
簡単にできるものですね?時と場合によりますが
floatより便利で高頻度で使います?⬇️こんな感じで使います❣️
index.vuedisplay: flex; justify-content: space-between; align-items: center;MDN: CSS フレックスボックスレイアウト
FlexboxとはFlexible Box Layout Moduleのことで、
その名の通りフレキシブルで簡単にレイアウトが組めちゃう素敵ボックスです。
日本語対応!CSS Flexboxのチートシートを作ったので配布します今までNuxtメインで
肝心のHTML,CSSを
あまりやっていなかったので
少しずつやっていきます??♀️作る物
前置きにあった画像の
カード部分です?ネイルデザインの
カードをイメージしてます?❤️
四角◾️には画像が入ります。
ネイルの名前と画像、
紹介文とタグ、
ネイリストの他の作品も一覧で見る?
といった感じにしています。⬇️リンク先
ボタンを押すとネイリストのネイル一覧
同じくカードを押すしてもネイル一覧
タグを押すとタグに該当するデザインの一覧構成
では構成を考えていきましょう??
まずはディレクトリ 、コンポーネントから。? 続きはWPでご覧ください?
https://wp.me/pc9NHC-TP
- 投稿日:2020-11-27T13:34:33+09:00
vue.js 小数点が省略されたが、表示させたい!(例えば、10->10.0で表示したい)
jsは整数の場合、小数が自動的に省略されたことがついに気づきました。
例えば、10ではなく、10.0で画面で表示したい場合、
postmanでPrettyだと、10で表示しています。「あれ?」と思って、Rawで確認すると、10.0になっています。vue.jsでどうやって10.0で表示できるの?
色々調べて、下記のコードでできた!// 負でない整数場合、小数一桁「0]を補足する var getFloatStr = function (num) { if (!/\./.test(num)) { num += '.0' } num = num.match(/\d+\.\d{1}/)[0] // console.log(num) return num }コードの全文
<template> <b-card header="結果" bg-variant="light" class="text-center" style="margin-bottom:10px;"> <b-card-text> <div> <input style="display:none" type="text" v-model="childrenMessage"> <element-table ref="table" :data="data" :columns="columns" /> </div> </b-card-text> </b-card> </template> <script> export default { props: ['message'], data () { return { childrenMessage: '', columns: [ [ { title: '順位', field: 'ranking' }, { title: '点数', field: 'score' }, { title: '名前', field: 'name' }, { title: 'メモ', field: 'memo' } ] ], data: [] } }, created () { this.childrenMessage = this.message }, watch: { message (val) { const result = this.message const arrResult = [] const objResult = {} // 負でない整数場合、小数一桁「0]を補足する var getFloatStr = function (num) { if (!/\./.test(num)) { num += '.0' } num = num.match(/\d+\.\d{1}/)[0] // console.log(num) return num } for (var i = 0; i < result.length; i++) { objResult['ranking'] = result[i]['ranking'] objResult['score'] = getFloatStr(JSON.stringify(result['score'])) objResult['name'] = result[i]['name'] objResult['memo'] = result[i]['memo'] arrResult.push(objResult) } this.data = arrResult } } } </script>
- 投稿日:2020-11-27T12:33:21+09:00
Vue で script で算出した数値・文字列を CSS で利用したい
後で修正します。ポイントは CSS変数をDOMに動的に当てる ところです。
ここに気づけずけっこうハマりました。。。<template> <div class="test" :style="styles"> <input v-model="color" /> </div> </template> <script lang="ts"> import Vue from 'vue'; export default Vue.extend({ data() { return { color: 'black', }; }, computed: { styles() { return { '--color': this.color, }; }, }, }); </script> <style lang="scss" scoped> $size: 10px; .test { --color: black; // ここは必ず指定 color: var(--color); font-size: $font-size; // もちろん SCSS の変数とも併用できます。 } </style>Options API だけでなく、 Class API でも動作します。もちろん、 Nuxt でも OK です。
安全性のために、 以下の2点は必ず実施してください。
- デフォルト値の設定(万が一 computed が壊れた等して値が飛んでこなかったら事故に繋がります)
- SASS系なら対象のスコープを限りなく狭めて使う(想定外の影響を避けてください)
- 投稿日:2020-11-27T12:29:44+09:00
【Nuxt.js】Nuxt番外編: アトミックデザインにおけるフォルダの分け方と サンプル集
? この記事はWP専用です
https://wp.me/pc9NHC-MQ前置き
コンポーネントの分類の仕方についてと
少しですがサンプルコード集です??この要素はどこ❓
molecules❓
それともorganisms❓
なんて時にチェックしてください✅?フォルダ分けはアトミックデザインを推奨しています。
Atomic Designとはサンプルコードもあるので
コンポーネントの命名や
中身の構成などの参考にも
お役立てください❤️コードを書き始める前のチェックリストを
見ておくと尚良いと思います✨?分け方
アトミックデザインに基づく分け方
アトミックデザイン は、
要素の大きさや機能ごとに
ファイルを分けるやり方です✨?それに乗っ取って分けていますが、
確実な正解・ルールは存在しないので
あくまでも私たちの分け方として
参考にしてくださいね♪それぞれ、
どの階層のコンポーネントを
読み込んでもOKです?♀️atoms
UIの最小要素。
button, icon, inputなど。タイトルのh1と、
サブタイトルのpでセットの場合なんかも
1つのまとまりなのでatomsへ?molecules
atomsを2, 3つ貼り付けたような物?
ul > li のliや
formに入れるlabelつきのinputなど。organismがformやulなどの
まとまりなので
それを分解した要素です?InputDefault.vueを
atomで作っていた場合はimportし、
作っていない場合は
FormItemInput.vueで
直接inputを使ってもOKです⭕️organisms
formやulなど、
ある程度のまとまり。
modalの中身もココ?templates
modalやnav, Header, Footer
sectionなどの大きなまとまり?atoms
? 続きはWPでご覧ください?
https://wp.me/pc9NHC-MQ
- 投稿日:2020-11-27T12:16:15+09:00
【Nuxt.js】Vue Router基礎編:params, queryを使ってページ遷移
? この記事はWP専用です
https://wp.me/pc9NHC-eI前置き
とっても便利なparams, queryについてご紹介?
同じコンポーネントを見せたいけど、
カテゴリごとにURLだけを変えたい…
一覧ページからソートして表示させたい…
そんな時に便利です♪params, queryについて
いくつかに分けて書きます✍️
router-linkが分かれば簡単です?
まだ不安な方のためにも
複数の書き方で記載しました?params, queryの違い
まずはURLを見るのが
分かりやすいと思います?localhost:3000/param/param?query=123
パスパラメーター(param)
?より前の部分、省略できない
クエリパラメーター(query)
?以降の部分、省略できる
directoryとの関係①
localhost:3000/project123
projectごとにURLを変更
表示ページは同じでコンポーネントで表示分けfilepages/ --| _id/ -----| index.vuedirectoryとの関係②
localhost:3000/events?today=true
events/index.vueの中で
today=trueでソートをかけて表示filepages/ --| events/ -----| index.vueeventsは絶対省略できないですね。
pages/events/index.vueに
行けなくなってしまいます。?today=trueは省略しても
ソートが外れるだけなので
ページはきちんと表示されます♪メリット
? 続きはWPでご覧ください?
https://wp.me/pc9NHC-eI
- 投稿日:2020-11-27T09:55:35+09:00
Nuxt.jsのhead内にSEOに必要なmeta情報を追加する
Nuxt.jsでSEOに必要なmetaタグの情報を入れていく方法を紹介します。
metaタグとは?
Webサイトのページ情報を検索エンジンに伝えるtagのことです。
metaタグを入力することでこのページはこんな情報を持っていますよということを伝えることができます。
※今回SEO対策が必要なのでSSRを想定しています。想定されるHTML
今回は下記のようなHTMLを出力することを目標とします。
- 基本的なmeta要素 + titleタグ
- OGPに必要なタグ
- TwitterやFacebookなどSNSに必要なタグ
これらについて解説していきます。
<!DOCTYPE html> <html lang="ja" prefix="og: http://ogp.me/ns#"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 基本属性 --> <title>タイトル</title> <meta name="description" content="ディスクリプション"> <meta name="keywords" content="キーワード"> <!-- OGPタグ --> <meta property="og:site_name" content="サイト名" > <meta property="og:type" content="サイトのタイプ"> <meta property="og:url" content="ページURL"> <meta property="og:title" content="ページタイトル"> <meta property="og:description" content="ディスクリプション"> <meta property="og:image" content="OGP画像URL"> <!-- SNS用 --> <meta property="fb:app_id" content="App-ID"> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:site" content="@Twitter"> </head> <body> -------- 省略 -------- </body> </html>メタタグの使い方について知りたい方はこちらの記事をどうぞ
metaタグの使い方
OGPを設定しよう!SNSでシェアされやすい設定方法とは?SSRモードに設定
新規作成なら
SPA
かSSR/SSG
の選択ができるのでSSR/SSG
を選択。すでにNuxtを作成済みなら
universal(SSR)モード
に設定してください。
SPAモード
ではページごとのmeta反映されません。(させる設定もありますがここでは割愛させていただきます。)nuxt.config.jsmodule.exports = { mode: 'universal', ... }nuxt.config.jsにmeta要素を追加
Nuxtでは全体に使うmeta要素をnuxt.config.jsのhead内に記述します。
※1 faviconやCDNの読み込みなどもこちらから行えますが今回はSEOに必要な要素だけ記述しています。
※2 meta要素が重複する場合、先頭にhid
を入れておかないとエラーになります。nuxt.config.jsexport default { head: { htmlAttrs: { lang: 'ja', prefix: 'og: http://ogp.me/ns#' }, titleTemplate: '%s - ' + 'タイトル', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: 'サイトの説明' || '' }, { hid: 'keywords', name: 'keywords', content: 'キーワード1,キーワード2,キーワード3' }, { hid: 'og:site_name', property: 'og:site_name', content: 'サイト名' }, { hid: 'og:type', property: 'og:type', content: 'サイトのタイプ' }, { hid: 'og:url', property: 'og:url', content: 'サイトURL' }, { hid: 'og:title', property: 'og:title', content: 'サイトタイトル' }, { hid: 'og:description', property: 'og:description', content: 'サイトの説明' }, { hid: 'og:image', property: 'og:image', content: 'サイトURL' }, { hid: 'fb:app_id', property: 'fb:app_id', content: 'App-ID' }, { hid: 'twitter:card', name: 'twitter:card', content: 'summary_large_image' }, { hid: 'twitter:site', name: 'twitter:site', content: '@Twitter' } ], }, }
htmlAttrs
で言語設定、prefix
でOGPを使いますよと宣言します。
titleTemplate
で全ページに「ページ名 - タイトル」を出力させます。%s
の部分がそれぞれのページで設定したタイトルが表示されます。Topページの設定
headタグの中の要素は下記のように記述します。
titleTemplate
をnull
することでnuxt.config.js
で設定したものを反映させずにすみます。
そしてtitle
にTopページのタイトルを入力をすることでtitleタグに表示することができます。
※これを設定しておかないと「タイトル名 - タイトル名」のようになり重複してしまいます。pages/index.vue<template> <main> <h1>サイトタイトル</h1> </main> </template> <script> export default { head: { titleTemplate: null, title: 'サイトタイトル' } } </script>各ページごとの設定
Topページ以外の書き方です。
nuxt.config.jsで設定したtitleTemplateの機能を使います。
head内のtitle,metaに内容を追加することで反映されます。pages/about.vue<template> <main> <h1>各ページのタイトル</h1> </main> </template> <script> export default { head: { return { title: 'ページ名', meta: [ { hid: 'description', name: 'description', 'ページの説明' }, { hid: 'keyword', name: 'keyword', 'ページのキーワード' }, { hid: 'og:type', property: 'og:type', 'article' }, { hid: 'og:title', property: 'og:title', content: 'ページ名' }, { hid: 'og:description', property: 'og:description', content: 'ページの説明' }, { hid: 'og:url', property: 'og:url', content: 'https://hogehoge.com/about' }, { hid: 'og:image', property: 'og:image', content: 'https://hogehoge.com/img/ogp/about.jpg' }, ], } } } </script>dataに情報をまとめる
dataに情報をまとめることでogp用のタグのtitleやdescriptionなどを使い回せることができます。
pages/about.vue<script> export default { data () { return { meta: { title: 'ページ名', keyword: 'キーワード' description: 'ページの説明', type: 'article', url: 'https://hogehoge.com/about', image: 'https://hogehoge.com/img/ogp/about.png', }, } }, head: { return { title: this.meta.title, meta: [ { hid: 'description', name: 'description', this.meta.description }, { hid: 'keyword', name: 'keyword', this.meta.keyword }, { hid: 'og:type', property: 'og:type', this.meta.type }, { hid: 'og:title', property: 'og:title', content: this.meta.title }, { hid: 'og:description', property: 'og:description', content: this.meta.description }, { hid: 'og:url', property: 'og:url', content: this.meta.url }, { hid: 'og:image', property: 'og:image', content: this.meta.image }, ], } } } </script>Mixinを作成し共通化する
下層ページに毎回同じことを書くのであればMixin化をすることで使い回せることができます。
assetsフォルダ内にmixinsフォルダを作成
assetsフォルダにmixinsフォルダを作成します。そのなかにmeta.jsファイルを作ります。
先程作ったhead内のソースをそのままもってきます。assets/mixins/meta.jsexport default { head: { return { title: this.meta.title, meta: [ { hid: 'description', name: 'description', this.meta.description }, { hid: 'keyword', name: 'keyword', this.meta.keyword }, { hid: 'og:type', property: 'og:type', this.meta.type }, { hid: 'og:title', property: 'og:title', content: this.meta.title }, { hid: 'og:description', property: 'og:description', content: this.meta.description }, { hid: 'og:url', property: 'og:url', content: this.meta.url }, { hid: 'og:image', property: 'og:image', content: this.meta.image }, ], } } }下層ページでの使い方
import Meta from '~/assets/mixins/meta'
をscriptのあとに追加し、
export default
内にmixins: [Meta]
を追加します。
head ()
は削除します、pages/about.vue<template> <main> <h1>各ページのタイトル</h1> </main> </template> <script> import Meta from '~/assets/mixins/meta' export default { mixins: [Meta], data () { return { meta: { title: 'ページ名', keyword: 'キーワード' description: 'ページの説明', type: 'article', url: 'https://hogehoge.com/about', image: 'https://hogehoge.com/img/ogp/about.png', }, } } } </script>Nuxtでのmixinの使い方にかんしてはこちらの記事を参照
https://note.com/aliz/n/nb87adb4d4810出力されるHTL
genarate
したときにこんな感じ出力されます。index.html<head> <title>ページタイトル</title> <meta data-n-head="ssr" charset="utf-8"> <meta data-n-head="ssr" name="viewport" content="width=device-width,initial-scale=1"> <meta data-n-head="ssr" data-hid="description" name="description" content="ページの説明"> <meta data-n-head="ssr" data-hid="keywords" name="keywords" content="キーワード"> <meta data-n-head="ssr" data-hid="og:type" property="og:type" content="airticle"> <meta data-n-head="ssr" data-hid="og:url" property="og:url" content="https://hogehoge.com/about"> <meta data-n-head="ssr" data-hid="og:title" property="og:title" content="ページタイトル"> <meta data-n-head="ssr" data-hid="og:description" property="og:description" content="ページの説明"> <meta data-n-head="ssr" data-hid="og:image" property="og:image" content="https://hogehoge.com/img/ogp/about.png"> <meta data-n-head="ssr" data-hid="twitter:card" name="twitter:card" content="summary_large_image"> <meta data-n-head="ssr" data-hid="twitter:site" name="twitter:site" content="@ACALL_JP"> <!-- 省略 --> </head>以上でNuxt上でhead内にseoで必要なmeta情報を追加する方法でした。
- 投稿日:2020-11-27T01:37:20+09:00
VeturをインストールしてもEmmetが動作しない時の対処法
こんばんは
アロハな男、やすのりです!今日は、Vue.jsでプログラミングしていく上で、必須級とも言われている
Vetur
という拡張機能の.vueファイルでのEmmet動作
がうまくいかず、解決するまでに時間がかかったので備忘録も兼ねて書いていこうと思います。まず、結論から述べますと...
結論
拡張機能の設定画面で
Emmet
と検索して、下記画像のチェックボックスにチェックを入れると、TabボタンでのEmmet記法が有効化されます!!
そもそもEmmet記法って?
Emmet記法とは、HTMLやCSSをコーディングしていく際にタグやプロパティの一部だけを入力するだけで、タグやプロパティを生成する為の記法です。
具体例をあげると、
例:
div#test
Tabキーを押すと →<div id='test'></div>
こんなふうにHTMLタグを作成できたり、
例:
w100
Tabキーを押すと →width: 100px;
CSSのプロパティの記述が簡単にできたりします。
ただ、これは通常の
.htmlファイル
等だとTabキーを押さなくても、下記画像の様に変換先の候補が表示されていて、該当の候補を選択することで同じことが実現できていました。ですが、こと
.vueファイル
では通常ではこの動作が適用されていませんでしたので使うことができませんでした。Vetur
そこで登場するのが、冒頭でも紹介した
Vetur
という拡張機能です。
↓英語になりますが、こちらにVetur
の設定方法や拡張機能の説明が載っています。
https://vuejs.github.io/vetur/VeturをVSCodeにインストールすることにより、拡張機能の中の1つとして
.vueファイル内でのEmmet記法動作
があります。よし、それならこれをインストールすれば万事解決っ!!とはならず...
この様にinputタグを作成しようとしてみても候補はおろか、Tabキーを押しても何も起きない状況でした...『何か設定が必要なのかな...でも、いろんな人の記述を見てみてもVeturをインストールするだけで大丈夫って書いてあるし...』と八方塞がりな状態でした。
そんな中、下記のQiita記事を発見することができました!!
【高速コーディング】Emmetを使ってみよう!この記事のおかげで設定の中のチェックボックスにチェックを入れることを知ることができました。
しかし
結果として、.vueファイルでもEmmet記法が使える様になりましたが、この様な設定をしないといけないとはVetur関連の記事を読んでも書いてはいませんでしたし、元々.htmlではEmmet記法を使用できていました...
これは私の環境下だけでの事象なのかどうなのか...ゆくゆくは原因を突き止めたいですね。
もし、私と同じ様な状況になった人は設定を今一度確認してみてください。
- 投稿日:2020-11-27T00:55:56+09:00
【Vue/Nuxt】Vercelへのリリースで環境変数を読み込ませた
VercelのEnvironment UIでの環境変数の設定は割愛します。
Vercelの操作はビビるくらい簡単なので、説明するより触った方が良いです。
また、VercelにリリースしたNuxt.jsのプロジェクトで環境変数を読み込ませるには、
nuxt.config.js
にenvを設定すれば良かっただけの話でした。nuxt.config.jsrequire('dotenv').config() export default { modules: [ "@nuxtjs/dotenv", ], dotenv: { path: process.cwd() }, env: { API_KEY: process.env.API_KEY, API_URL: process.env.API_URL, }, }