본문 바로가기

Vue/bookStore

10 . 검색과 자동완성

코로나와 기사시험 필기 준비로 인해 블로그 작성을 하지 못했다..

4월 24일에 필기시험이 끝났는데 실기는 7월 말이라고 한다. ( 기다리기도 힘들다.. )

이제 시험도 끝났고 다시 bookStore 만들기를 진행하겠다.

이번 글에서는 자동완성 기능의 동작 방법을 간단하게 설명한다.

 

 

 

자동완성 기능

 

vuetify에서 제공하는 v-autocomplete도 있지만 검색어가 남지 않는다던가

데이터 바인딩, 디자인 등 원하는대로 구현하기 힘들어서 직접 만들었다.

( 그리고 bookStore 페이지를 조금 꾸며줬다. 이게 제일 힘들었음... )

 

텍스트 필드에 입력 값을 vue watch에서 감지하여 계속 서버와 통신한다. 자세한 내용은 아래에.

 

 

Vue - template


<v-col cols="10" md="5" class="pa-0 ma-0 pt-1" v-click-outside="onClickOutside">
    
    // 여기는 검색어를 입력하는 곳
    <v-text-field
        v-model="inputMsg"
        filled
        outlined
        rounded
        dense
        @focus="autoSearchList = true"
    >
    </v-text-field>


	// 여기는 자동완성된 결과를 보여주는 곳
    <transition name="top-slide" mode="in-out">
      <div class="justify-center align-center flex-column d-flex">
        <v-list class="pa-0 ma-0 search-list" v-show="autoSearchList" light>
          <v-list-item-group>
            
            // 마우스 오버 시 효과를 주기위한 v-hover
            <v-hover v-slot="{ hover }"
                     v-for="(item,index) in completeData"
                     :key="index" 
             >   
             
              // 자동완성 결과값들의 리스트
              <v-list-item
                  class="pa-3 pl-5 top-list"
                  :class="{ 'on-hover': hover }"
                  @click="inputMsg=item.bookTitle"
             >
                
                //내용들
                <v-card
                    class="search-list-img"
                    elevation="1"
                    tile
                >
                  <img
                      :src="item.bookThumb"
                      alt="bookThumb"
                      height="100%"
                      @click="detailView(item.bid)"
                  >
                </v-card>
                
                <v-list-item-content class="pl-8">
                  <v-list-item-title>
                    <span class="search-list-title" @click="detailView(item.bid)"> {{item.bookTitle}} </span>
                  </v-list-item-title>
                  <v-list-item-subtitle class="pt-2">
                    <span class="search-list-subtitle"> {{ item.bookAuthor }} | {{item.bookPublisher}}</span>
                  </v-list-item-subtitle>
                </v-list-item-content>

              </v-list-item>
            </v-hover>

          </v-list-item-group>
        </v-list>
      </div>
    </transition>
</v-col>

 

  •  input (v-text-field) 에 포커스가 잡히면 자동완성된 리스트를 보여주는 구역이 보이게된다 ( show = true )
  •  v-hover로 자동완성 리스트에 마우스를 올리면 구역을 구분하기 쉽게 디자인
  •  책 제목과 이미지를 누르면 -> 해당 책 상세보기로 바로 이동한다
  •  그 외 구역을 클릭하면 검색바에 책 이름이 들어간다 @Click

 

 

Vue - Script


data: () => ({
	
    ...
    
 }),
  
  watch: {
    inputMsg(val) {
      if (!val) {
        this.completeData=[]
      }
      this.fetchEntriesDebounced()
    },
  },
  
  directives: {
    clickOutside: vClickOutside.directive
  },

  methods: {
    //DB에 불필요한 데이터 입력 방지위해 입력 기다리기
    fetchEntriesDebounced() {
      this.completeData = null;
    
      clearTimeout(this._timerId)
      // 0.5초 동안 동작이 없으면 completeSearch 함수 호출
      this._timerId = setTimeout(() => {
        // maybe : this.fetch_data()
        this.completeSearch()
      }, 500)
    },
    
    //자동완성 기능
    completeSearch(){
      let str = this.inputMsg
      str = str.trim()                                             //양끝 공백 제거
      str = str.replace(/\s/g,'+')            //스페이스바 +로 치환
      const reg = /[^가-힣ㄱ-ㅎㅏ-ㅣa-zA-Z0-9|+]/.test(str);         //특문검사 정규식
      if(!reg && str !== ""){
        this.$axios.get("book/complete/" + str)
            .then(response => {
              this.completeData = response.data
            }).catch(error => {
          console.log(error.response);
        })
      }
    },
    //자동검색 리스트에서 바깥부분 클릭시 리스트 닫음
    onClickOutside () {
      this.autoSearchList = false
    },
  }

Watch를 사용하여 값이 들어올때마다 Springboot와 통신한다

 

 

inputMsg : 입력값 ( template 의 v-text-field의 model )

completeData : 자동완성 값이 담기는 List

 

1. Watch를 사용하여 inputMsg의 값이 변하면 (값이 들어오면) fethEntriesDebounced() 함수를 호출한다

2. fethEntriesDebounced() 에서 0.5초간 입력을 기다려서 불필요한 데이터가 전송되지 않게 한다.

3. CompleteSearch() 에서 정규표현식을 이용하여 inputMsg 를 검사하고 데이터를 보낸다.

(띄어쓰기는 +로 치환)

 

 

 

Springboot


스프링에서는 get방식으로 받은 검색어를 Repository로 보내서 검색한다.

검색어의 공백부분은 +부분으로 치환된 상태이다.

(ex) 불편한 편의점 = 불편한+편의점

 

1. 정규표현식 regexp를 사용하기 위해 service에서 검색어의 "+"부분을 "|"로 치환한다.

public List<BookMainInterface> getBookListByComplete(String searchTitle) {
        searchTitle = searchTitle.replace('+','|');
        return bookRepository.searchByRegExp(searchTitle,"N");
}

 

2. 정규표현식 regexp을 Jpa에서 사용하여 데이터를 검색하기 위해 nativeQuery를 사용했다.

@Query(value = "select b.bid, b.bookThumb ,b.bookTitle ,b.bookKeyword, b.bookAuthor, b.bookPublisher From Book b where (b.bookKeyword REGEXP :searchKeyword) and b.isDel=:isDel ", nativeQuery = true)
    List<BookMainInterface> searchByRegExpKeyword(@Param("searchKeyword") String searchKeyword, @Param("isDel") String isDel);

 

3. 검색을 담당하는 쿼리에서는 replace로 컬럼이름의 공백부분을 제거하여 띄어쓰기가 없어도 검색이 가능하다.

4. 검색은 책 제목과 키워드를 같이 조회한다. 따라서 키워드로 검색이 가능하다.

'Vue > bookStore' 카테고리의 다른 글

BookStore 프로필 업로드 새로고침 현상 수정  (0) 2022.08.12
로그인 변경점과 문제점 해결  (0) 2022.07.28
9. 도서 위시리스트  (0) 2022.03.30
8. 도서 위시리스트 (Spring boot)  (0) 2022.03.22
7. 도서 리스트 1  (0) 2022.03.14