1. 程式人生 > >vue-music 關於Search(搜索頁面)-- 搜索歷史

vue-music 關於Search(搜索頁面)-- 搜索歷史

hist 頁面 tar length 點擊 scree query {} content

搜索歷史展示每一次搜索過,並選中的關鍵字,保存數據到數組。搜索歷史數據是需要在多個組件中共享的,所以保存在vuex 中 searchHistory 數組中,保存觸發在搜索列表點擊選中之後派發事件到search.vue 中,search.vue 監聽事件並提交actions改變共享數組,改變vuex 中共享數據之前需要存到本地緩存 Localstorage 中,在本地存儲 中判斷如果當期歷史搜索數據在數據中已經有則提前插入到第一位,沒有則添加到數組中存儲

在common 中 創建cache.js 裏面寫所有相關存儲的邏輯代碼。使用goog-storage 庫 方便調用localstorage 相關api

保存本地搜索歷史首先獲取訪問本地存儲中的key 如果已經有值則賦值,沒有則賦值為空數組,插入新數據前先與當前歷史數據列表比較有沒有相同數據,有則且在第一個位置原樣返回該數據,有且大於第一個位置則刪除該數據,然後再插入,並且插入大於最大限制條數的時候,刪除數組的最後一個元素。最後調用storage.set(key,val) 存到本地緩存中。並且 在action 中提交到vuex數據中

cache.js

import storage from ‘good-storage‘

const SEARCH_KEY = ‘__search__‘
const SEARCH_MAX_LEN = 15

// 檢索函數,判斷新增的是否存在
function insertArray(arr, val, compare, maxLen) { const index = arr.findIndex(compare) if (index === 0) { return } if (index > 0) { arr.splice(index, 1) } arr.unshift(val) if (maxLen && arr.length > maxLen) { arr.pop() } } export function saveSearch(query) { let searches
= storage.get(SEARCH_KEY, []) insertArray(searches, query, (item) => { return item === query }, SEARCH_MAX_LEN) storage.set(SEARCH_KEY, searches) return searches } export function loadSearch() { return storage.get(SEARCH_KEY, []) }

actions.js

export const saveSearchHistory = function({commit},query){
  commit(types.SET_SEARCH_HISTORY,saveSearch(query));
} 

state.js

import {loadSearch} from ‘common/js/cache.js‘;

const state = {
    singer:{},
    playing:false,
    fullScreen:false,
    playList:[],
    sequenceList:[],
    mode:playMode.sequence,
    currentIndex:-1,
    disc:{},
    topList:{},
    searchHistory:loadSearch()    //默認值從本地存儲中獲取
}
export default state

將獲取來的vuex數據遍歷到歷史數據列表組件上search-list 組件

<template>
  <div class="search-list" v-show="searches.length">
    <ul>
      <li :key="item" class="search-item" @click="selectItem(item)" v-for="item in searches">
        <span class="text">{{item}}</span>
        <span class="icon" @click.stop="deleteOne(item)">
          <i class="icon-delete"></i>
        </span>
      </li>
    </ul>
  </div>
</template>

<script type="text/ecmascript-6">
  export default {
    props: {
      searches: {
        type: Array,
        default: []
      }
    },
    methods: {
      selectItem(item) {
        this.$emit(‘select‘, item)
      },
      deleteOne(item) {
        this.$emit(‘delete‘, item)
      }
    }
  }
</script>

組件上派發一個選中本條歷史數據和刪除本條歷史數據的方法,選中本條可以引用addQuery 方法將本條數據再次填在input 搜索框中。刪除本條調用action 方法

function deleteFromArray(arr, compare) {
  const index = arr.findIndex(compare)
  if (index > -1) {
    arr.splice(index, 1)
  }
}

// 刪除後的數組存到本地
export function deleteSearch(query) {
  let searches = storage.get(SEARCH_KEY, [])
  deleteFromArray(searches, (item) => {
    return item === query
  })
  storage.set(SEARCH_KEY, searches)
  return searches
}

------------------ actions.js -----

export const deleteSearchHistory = function({commit},query){
  commit(types.SET_SEARCH_HISTORY,deleteSearch(query));
}

點擊清除所有歷史數據方法和刪除本條的邏輯一樣,需要提交actions 清除本地緩存數據,並返回一個空數組賦值給vuex 數據,然後組件通過mapActions 調用該方法清空歷史數據

// 清除數據
export function clearSearch() {
  storage.remove(SEARCH_KEY)
  return []
}

// 提交空數組
export const clearSearchHistory = function({commit}){
  commit(types.SET_SEARCH_HISTORY,clearSearch());
}

search.vue 引入mapActions ,代理調用clearSearchHistory 方法

import {mapActions,mapGetters} from ‘vuex‘

...mapActions([
  ‘saveSearchHistory‘,
  ‘deleteSearchHistory‘,
  ‘clearSearchHistory‘
])

// 綁定派發事件   
deleteAll(){
  this.clearSearchHistory();
},

//!註意這裏可以直接將代理的方法直接綁定到監聽事件中,可省略再次寫方法名

// 之前是
<span class="clear" @click="deleteAll">

// 可改為
<span class="clear" @click="clearSearchHistory">

優化體驗,點擊清空所以數據的時候彈窗確認刪除才刪除

建立confirm 組件,向外派發點擊確認按鈕時的事件,這裏就直接把確認的派發事件寫成 clearSearchHistory 。取消的話影藏自身就行

// confirm 組件<template>
  <transition name="confirm-fade">
    <div class="confirm" v-show="showFlag" @click.stop>
      <div class="confirm-wrapper">
        <div class="confirm-content">
          <p class="text">{{text}}</p>
          <div class="operate">
            <div @click="cancel" class="operate-btn left">{{cancelBtnText}}</div>
            <div @click="confirm" class="operate-btn">{{confirmBtnText}}</div>
          </div>
        </div>
      </div>
    </div>
  </transition>
</template>

<script type="text/ecmascript-6">
  export default {
    props: {
      text: {
        type: String,
        default: ‘‘
      },
      confirmBtnText: {
        type: String,
        default: ‘確定‘
      },
      cancelBtnText: {
        type: String,
        default: ‘取消‘
      }
    },
    data() {
      return {
        showFlag: false    // 內部變量控制其顯示影藏
      }
    },
    methods: {
      show() {
        this.showFlag = true
      },
      hide() {
        this.showFlag = false
      },
      cancel() {
        this.hide()
        this.$emit(‘cancel‘)
      },
      confirm() {
        this.hide()
        this.$emit(‘confirm‘)
      }
    }
  }
</script>

vue-music 關於Search(搜索頁面)-- 搜索歷史