webサービスの詳細はこちらの記事参照ください。「レファレンス協同データベースの記事をランダムに表示するWEBサービスをvue.jsで作りました。」
やったこと
元はトップページ1枚全て(上下のheaderとfooterは除く)Home.vueという1つのコンポーネントで作成していました。このほか、記事詳細画面用のDetail.vueがあります。
今回行ったのはHome.vueから機能ごとにA・B・C、計3つのコンポーネントへ分離することです。
トップで使用していたHome.vueは647行から210行まで減りました。
大変だったこと。
一番時間がかかったA.検索機能の分割について備忘録も兼ねて書きます。(※まだ知識が浅いところが多いので、間違いもあるかもしれません。お気づきの点ありましたらコメントいただけるとありがたいです。)
検索機能は実質3つ用意されています。
1.検索ボックス
この記事では深くは突っ込みません。直接入力or上部レコメンドのクリック→検索ボックスへ入力の2パターンあります。
2.ランダムに表示ボタン
この記事では深くは突っ込みません。
3.記事詳細画面のキーワードタグをクリックして遷移
これが問題です。
1は検索ボックスエリアのwatchによる監視で2パターンとも対処。2のランダム表示ボタンも親コンポーネントが同一なので検索の実行は簡単。
しかし、3は別の画面からの遷移です。
記事詳細画面がkeywordをパラメーターとして投げて⇒受け取り⇒検索を実行、と3つのコンポーネントをまたぐ処理です。検索ボックスにキーワードを反映するのは1と同様なので、同じく検索ボックスの監視ではうまくいくと思っていたら検索実行の可否決定で少し詰まりました。
まず、パラメーターとして投げて⇒受け取るところまでは以下の実装。
リンク元のタグ。
<a v-bind:href="'https://testreftika.web.app/keyword/' + keyword">{{keyword}}</a>
ルーター
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/keyword/:keyword', ←新たに追加
name:'keyword',
component: Home
},
省略
}
リンク先ではurlのチェックを行い/keyword/とマッチした場合はパラメーターを取得し、検索ボックスへ入力します。
if (location.pathname.match(/\/keyword\/./)) {
this.keyword = this.$route.params.keyword
}
この後、Aコンポーネントで検索を実行します。
ここで、初めは「created:functionの処理として、keywordがある場合は検索を実行」という方法をとりました。しかし、戻るボタンでトップページに遷移してきたときにも検索を実行してしまうためよくありません。
そこで別の方法として、Bコンポーネントの検索結果データがあるかどうかによって判断することにしました。そのために、もともとコンポーネントのdataで管理していた検索結果をstoreに移動。コンポーネントのdataはバッファとして利用することにしました。
こうすることで、キーワードの有無ではなく、storeにデータがあるかないかによって検索を実行の可否を決定することができます。storeはpageリフレッシュ時とurlが変わった際に消えてしまうので、詳細ページからの遷移時には新たに検索を実行してくれるからです。(と理解しています。)