搜索历史展示每一次搜索过,并选中的关键字,保存数据到数组。搜索历史数据是需要在多个组件中共享的,所以保存在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>