一、搜索模塊組件集成
清除src\pages\search\search.vue頁面之前的測試代碼,修改爲:
<template>
<div>
<SearchBar
:focus="searchFocus"
@onChange="onChange"
/>
<TagGroup
header-text="熱門搜索"
btn-text="換一批"
:value="hotSearch"
@onBtnClick="changeHotSearch"
@onTagClick="showBookDetail"
v-if="hotSearch.length > 0 && !showList"
/>
<TagGroup
header-text="歷史搜索"
btn-text="清空"
:value="historySearch"
@onBtnClick="clearHistorySearch"
@onTagClick="searchKeyWord"
v-if="historySearch.length > 0 && !showList"
/>
<SearchList
:data="searchList"
v-if="showList"
/>
</div>
</template>
<script>
import SearchBar from '../../components/home/SearchBar'
import SearchList from '../../components/search/SearchList'
export default {
components: {SearchList, SearchBar},
computed: {
showList() {
const keys = Object.keys(this.searchList)
return keys.length > 0
}
},
data() {
return {
hotSearch: [],
historySearch: [],
searchList: {},
searchFocus: true
}
},
methods: {
changeHotSearch() {
console.log('change hot search')
},
showBookDetail() {
console.log('showBookDetail')
},
clearHistorySearch() {
console.log('clearHistorySearch')
},
searchKeyWord() {
console.log('searchKeyWord')
},
onChange(keyword) {
console.log(keyword)
}
}
}
</script>
<style lang="scss" scoped>
</style>
這裏的顯示與否取決於內容是否爲空:
- 數組:Array.length > 0
- 對象:Object.keys.length > 0
二、搜索模塊API對接
src\api\index.js中新增搜索接口調用方法
export function search(params) {
return get(`${API_URL}/book/search`, params)
}
修改src\components\search\SearchList.vue:
<template>
<div class="search-list-wrapper">
<SearchItem
icon="apps-o"
:title="category"
sub-title="Category"
@onClick="showList(category.title, 'category')"
v-if="category"
/>
<SearchItem
icon="user-o"
:title="author"
sub-title="Author"
@onClick="showList(author.title, 'author')"
v-if="author"
/>
<SearchItem
icon="newspaper-o"
:title="publisher"
sub-title="Publisher"
@onClick="showList(publisher.title, 'publisher')"
v-if="publisher"
/>
<SearchTable :data="data.book" @onClick="onBookClick"/>
</div>
</template>
<script>
import SearchItem from './SearchItem'
import SearchTable from './SearchTable'
export default {
components: {SearchTable, SearchItem},
props: {
data: Object
},
computed: {
category() {
if (this.data && this.data.category && this.data.category.length > 0) {
return this.data.category[0].categoryText
} else {
return null
}
},
author() {
if (this.data && this.data.author && this.data.author.length > 0) {
return this.data.author[0].author
} else {
return null
}
},
publisher() {
if (this.data && this.data.publisher && this.data.publisher.length > 0) {
return this.data.publisher[0].publisher
} else {
return null
}
}
},
methods: {
showList(text, key) {
console.log(text, key)
},
onBookClick(book) {
console.log(book)
}
}
}
</script>
<style lang="scss" scoped>
</style>
修改src\components\search\SearchItem.vue的部分樣式:
.search-item-info {
width: 80%;
...
.search-item-title {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
...
}
...
修改src\pages\search\search.vue:
- 修改onChange方法並新增onSearch方法
onChange(keyword) {
if (!keyword || keyword.trim().length === 0) {
this.searchList = {}
return
}
this.onSearch(keyword)
},
onSearch(keyword) {
search({
keyword, openId: this.openId
}).then(res => {
this.searchList = res.data.data
})
}
- 新增data:
openId: ''
並通過本地緩存獲取:
mounted() {
this.openId = getStorageSync('openId')
},
預覽:
三、熱門搜索API對接
在src\pages\search\search.vue爲SearchBar新增onClear,用來在點擊清除按鈕時進行數據清除:
<SearchBar
:focus="searchFocus"
@onChange="onChange"
@onClear="onClear"
/>
onClear() {
this.searchList = {}
}
src\api\index.js中新增熱門搜索接口調用方法
export function hotSearch(params) {
return get(`${API_URL}/book/hot-search`, params)
}
修改src\pages\index\index.vue中跳轉搜索頁面的事件,使在跳轉搜索頁面時攜帶參數hotSearch:
onSearchBarClick() {
this.$router.push({
path: '/pages/search/main',
query: {
hotSearch: this.hotSearch
}
})
},
在src\pages\search\search.vue
頁面加載時調用hotSearch
接口方法,並拿到首頁傳來的hotSearch
賦給搜索頁面新增的data
:hotSearchKeyword
:
data() {
return {
hotSearch: [],
historySearch: [],
hotSearchKeyword: '',
searchList: {},
searchFocus: true,
openId: ''
}
},
mounted() {
this.openId = getStorageSync('openId')
hotSearch().then(res => {
this.hotSearch = res.data.data
})
this.hotSearchKeyword = this.$route.query.hotSearch
},
在計算屬性中創建hotSearchArray方法來獲取熱門搜索標題,並在中調用
hotSearchArray() {
const _hotSearch = []
this.hotSearch.forEach(obj => _hotSearch.push(obj.title))
return _hotSearch
}
修改src\components\base\TagGroup.vue的樣式
<style lang="scss" scoped>
.tag-group-wrapper {
...
width: 100%;
padding-bottom: 10px;
...
.tag-goup {
width: 100%;
box-sizing: border-box;
...
.tag-group-inner {
max-width: 100%;
box-sizing: border-box;
...
}
}
}
</style>
修改src\components\base\Tag.vue的樣式:
<style lang="scss" scoped>
.tag-wrapper {
width: 100%;
box-sizing: border-box;
...
.tag {
width: 100%;
...
}
}
</style>
這樣熱門搜索就可以正常顯示了
修改showBookDetail方法
showBookDetail(text, index) {
console.log('showBookDetail', index, text)
},
四、歷史搜索和熱搜更新功能開發
在src\pages\search\search.vue中新增onConfirm方法:
onConfirm(keyword) {
// 1.判斷是否有搜索關鍵詞
if (!keyword || keyword.trim().length === 0) {
// 如果沒有,則獲取熱門搜索詞,通過熱門搜索詞發起請求
keyword = this.hotSearchKeyword
this.$refs.searchBar.setValue(keyword)
} else {
// 如果有,使用搜索關鍵詞發起請求
}
this.onSearch(keyword)
// 2.將搜索結果寫入歷史搜索
if (!this.historySearch.includes(keyword)) {
this.historySearch.push(keyword)
// 將歷史搜索寫入緩存
setStorageSync(KEY_HISTORY_SEARCH, this.historySearch)
}
// 3.將搜索框失去焦點
this.searchFocus = false
}
清空歷史記錄:
clearHistorySearch() {
this.historySearch = []
setStorageSync(KEY_HISTORY_SEARCH, [])
},
在搜索頁面加載時從緩存中拿到歷史搜索記錄:
mounted() {
this.openId = getStorageSync('openId')
hotSearch().then(res => {
// 從接口中拿到熱門搜索關鍵詞內容,並賦值本頁面
this.hotSearch = res.data.data
})
// 將首頁傳來的參數(熱門搜索關鍵詞)賦給本頁面的熱門搜索關鍵詞,完成參數傳遞
this.hotSearchKeyword = this.$route.query.hotSearch
// 若緩存中有歷史搜索記錄,頁面渲染完畢就拿到,否則置空
this.historySearch = getStorageSync(KEY_HISTORY_SEARCH) || []
},
爲了方便,可以定義一個historySearch常量,然後在需要的地方引用:
const KEY_HISTORY_SEARCH = 'historySearch'
換一批其實也就是重新從hotSearch接口拿一遍數據:
hotSearch().then(res => {
// 從接口中拿到熱門搜索關鍵詞內容,並賦值本頁面
this.hotSearch = res.data.data
})
點擊歷史搜索的tag觸發searchKeyWord事件:
searchKeyWord(text) {
this.$refs.searchBar.setValue(text)
this.onSearch(text)
},
預覽:
五、觸底自動刷新功能開發
頁面滑動時搜索框失去焦點(調用的是一個頁面的生命週期函數):
onPageScroll() {
if (this.searchFocus) {
this.searchFocus = false
}
},
新增data
:page: 1
,在onSearch給search接口傳參時傳入:
onSearch(keyword) {
search({
keyword, openId: this.openId, page: this.page
}).then(res => {
this.searchList = res.data.data
})
},
在src\api\wechat.js中新增
export function showToast(title) {
mpvue.showToast({
title,
duration: 2000
})
}
到達頁面底部觸發頁面周期函數onReachBottom:
onReachBottom() {
if (this.showList) {
// 再加載20條數據,即一頁數據
this.page++
// 拿到搜索關鍵詞
const searchWord = this.$refs.searchBar.getValue()
// 這時就不能直接調用onSearch方法,否則整個頁面都會加載新的一頁數據來替換掉原有頁數據
search({
keyword: searchWord,
openId: this.openId,
page: this.page
}).then(res => {
// 通過解構的方式拿到數據
const { book } = res.data.data
if (book && book.length > 0) {
// 這裏使用拓展運算符可以把book數組裏面的元素散着push進去而不是整個數組push進去
this.searchList.book.push(...book)
} else {
showToast('沒有更多數據了')
}
})
}
},
記得要在關鍵詞改變時初始化page爲1
onChange(keyword) {
...
this.page = 1
this.searchFocus = true // 爲了防止焦點丟失,建議加上
...
},
在mounted中也是如此:
mounted() {
...
this.page = 1
...
},