見出し画像

Nuxt.js×Vuetify×Railsで検索機能の実装

上記の記事を参考に作成していこうと思います。

あくまで参考になれば程度ですのでコピペしても同じものは作成できないと思います。適宣コードは変えてください。

作成環境

"nuxt": "^2.15.7",
"vue-text-highlight": "^2.0.10",
"@nuxtjs/vuetify": "^1.12.1",

完成デモ動画

画像6

完成版ソースコード

<template>
 <layout-main #layout-main><!--eslint-disable-line-->
   <v-card>
     <v-app-bar
       flat
       color="rgba(0, 0, 0, 0)"
     >
       <v-btn
         icon
         large
         class="mr-5"
         @click="pageBack"
       >
         <v-icon>mdi-arrow-left</v-icon>
       </v-btn>
       <v-toolbar-title>
         検索
       </v-toolbar-title>
     </v-app-bar>
     <v-divider />
     <v-form>
       <v-container>
         <v-row
           class="pt-7 pl-5 pr-5"
         >
           <v-text-field
             v-model="keyword"
             outlined
             rounded
             label="検索ワードを入力"
             append-outer-icon="mdi-magnify"
             @click:append-outer="search"
           >
           </v-text-field>
         </v-row>
       </v-container>
     </v-form>
     <v-divider />
     <v-tabs
       v-model="tab"
       color="primary accent-10"
       grow
     >
       <v-tab>投稿</v-tab>
       <v-tab>ユーザー</v-tab>
     </v-tabs>
     <v-tabs-items v-model="tab">
       <v-tab-item>
         <div v-if="posts.length > 0">
           <v-card-text class="ml-2">投稿検索({{ posts.length }})件</v-card-text>
         </div>
         <comment-card
           v-for="post in posts"
           :key="post.id"
           :content-id="post.id"
           :keyword="keyword"
         />
       </v-tab-item>
       <v-tab-item>
         <div v-if="users.length > 0">
           <v-card-text class="ml-2">ユーザー検索({{ users.length}})件</v-card-text>
         </div>
         <user-follow-card
           v-for="user in users"
           :key="user.id"
           :user="user"
           :followingUsers="followingUsers"
           :keyword="keyword"
         />
       </v-tab-item>
     </v-tabs-items>
   </v-card>
 </layout-main>
</template>
<script>
import { mapGetters } from 'vuex'
import layoutMain from '../../components/layout/loggedIn/layoutMain.vue'
import commentCard from '../../components/post/commentCard.vue'
import userFollowCard from '../../components/user/userFollowCard.vue'
export default {
 components: {
   layoutMain,
   commentCard,
   userFollowCard
 },
 data () {
   return {
     tab: null,
     keyword: '',
     loading: false,
     posts: [],
     users: [],
     followingUsers: []
   }
 },
 computed: {
   ...mapGetters({
     currentUserId: 'auth/currentUserId'
   })
 },
 mounted () {
   setTimeout(() => {
     this.fetchFolowingUser()
   }, 100)
 },
 methods: {
   search () {
     this.loading = true
     const url = 'api/v1/search'
     this.$axios.get(url, { params: { keyword: this.keyword } })
       .then((res) => {
         this.posts = res.data.posts
         this.users = res.data.users
       })
       .catch((err) => {
         console.log(err)
       })
   },
   fetchFolowingUser () {
     const url = `api/v1/users/${this.currentUserId}/following_users`
     this.$axios.get(url)
       .then((res) => {
         this.followingUsers = res.data.following_users
       })
       .catch((err) => {
         console.log(err)
       })
   },
   pageBack () {
     this.$router.go(-1)
   }
 }
}
</script>
​

フォームの作成

vuetifyのv-formを参考に作成していきます。

pagesでぃれくとりにsearches/index.vueを作成します。

画像10

画像1

      <v-form>
       <v-container>
         <v-row
           class="pt-7 pl-5 pr-5"
         >
           <v-text-field
             v-model="keyword"
             outlined
             rounded
             label="検索ワードを入力"
             append-outer-icon="mdi-magnify"
             @click:append-outer="search"
           >
           </v-text-field>
         </v-row>
       </v-container>
     </v-form>

画像14

formのテキストフィールドとdataのkeywordをバインドさせます。

railsのコントローラー作成

docker compose run --rm api rails g controller searches

画像2

画像3

ルートの設定

get 'search' => "searches#search"

画像7

サーチメソッドを作成

今回はUserモデルとPostモデルを検索したかったためその2つのモデルにメソッドを追加します。

画像8

サーチコントローラの記述

画像9

dataオブジェクトの中にpostsとしてpostモデルの検索結果と、usersとしてuserモデルの検索結果を格納します。

Nuxt側の記述

画像11

dataにpostsとusersを用意し

formのボタンのクリックをされた時にv-on:click(@click)でsearchメソッドを発火させます。

画像13

画像12

画像5

ここまでで検索機能は完成しましたが、検索ワードにハイライトを付けたかったためハイライトを付けるプラグインを導入していきます。

検索ワードをハイライトするライブラリ「Vue Text Highlight」を導入します。

https://mebee.info/2020/05/09/post-8134/

何個か読むとどう導入していくかわかると思います。

つまずいた部分としてはVue Text Highlightはプレーンなテキストしかハイライトしてくれないということです。

どういうことかというと

vuetifyの<v-○○○>要素や、<component/>としたコンポーネント内のテキストには反映されないということです。

そのためコンポーネントをまたいでテキストにハイライトを付けい場合は

子コンポーネントのテキスト欄に<text-highlight/>コンポーネントをつけ、keywordというデータを親コンポーネントからpropsで受け渡します。

画像14

そうすることで子コンポーネントのテキストデータにもハイライトがつくことになります。

これで完成デモのような検索機能を作成することができました。











いいなと思ったら応援しよう!