首先是 酷狗搜索的API 请求,在proxyTable中 代理 该地址
在请求API的js文件中,有搜索热门词请求,搜索词条请求
import axios from 'axios';
let commonParams = {
inCharset: 'utf-8',
outCharset: 'utf-8'
}
export function getKugouHotKeywords() {//热门关键词
const url = 'KugouHotKeywordsAPI/v3/search/hot?format=json&plat=0&count=30'
const data = Object.assign({}, commonParams, {
})
return axios.get(url, {
params: data
}).then((res) => { //成功的回调
return Promise.resolve(res.data.data.info)
})
}
export function getKugousearchList(keyword,page) {//搜索列表
const url = `KugouHotKeywordsAPI/v3/search/song?format=json&keyword=${keyword}&page=${page}&pagesize=20&showtype=1`
const data = Object.assign({}, commonParams, {
})
return axios.get(url, {
params: data
}).then((res) => { //成功的回调
return Promise.resolve(res.data.data)
})
}
search.vue 文件
search-box.vue 文件
<template>
<div class="searchBox">
<el-input
class="box"
:placeholder="placeholder"
prefix-icon="el-icon-search"
v-model="inputValue"
clearable
></el-input>
<div class="hotDiv" v-show="kugouSearchList.length==0">
<div class="title">热门搜索</div>
<ul class="hotUl">
<li
@click="selectKeyword(item.keyword)"
class="hotLi"
v-for="(item,index) in hotKeywords"
:key="index"
>{{item.keyword}}</li>
</ul>
</div>
<!-- <button @click="searchMore">获取更多</button> -->
<!-- 搜索回来的歌曲列表 -->
<suggest :searchList="kugouSearchList" @searchMore="searchMore" @selectItem = "selectItem"></suggest>
</div>
</template>
<script>
import { getKugouHotKeywords, getKugousearchList } from "../../api/kugouSearch";
import {mapActions} from "vuex"
import suggest from "../../components/suggest/suggest";
export default {
props: {
placeholder: {
type: String,
default: "搜索歌曲、歌手"
}
},
created() {
this.$watch("inputValue", newVal => {
this.$emit("inputValue", newVal);
});
this._getKugouHotKeywords(); //获取热门关键词
},
data() {
return {
inputValue: "", //输入框的值
hotKeywords: [], //热门关键词
kugouSearchList: [], //搜索列表
currentPage: 1, //搜索默认显示第一页
totalPage: 0, //搜索结果的页数
// isSearch: false //是否有搜索结果
};
},
methods: {
//获取搜索热门词
async _getKugouHotKeywords() {
this.hotKeywords = await getKugouHotKeywords();
},
selectKeyword(keyword) {
this.inputValue = keyword;
},
//搜索歌曲
async getSearchList(keyword, page) {
if (keyword.trim() != "") {
// loading遮罩層
this.openFullScreen();
//不为空发起请求
let data = await getKugousearchList(keyword, page);
this.kugouSearchList.push(...data.info);
this.totalPage = Math.ceil(Number(data.total) / 20);
} else {
this.kugouSearchList = [];
}
},
//loading更多歌曲
searchMore() {
this.currentPage++; //页数+1
if (this.currentPage <= this.totalPage) {
this.getSearchList(this.inputValue, this.currentPage);
}
},
// loading全屏遮罩层
openFullScreen() {
this.fullscreenLoading = true;
setTimeout(() => {
this.fullscreenLoading = false;
}, 2000);
},
openFullScreen() {
const loading = this.$loading({
lock: true,
text: "Loading",
spinner: "el-icon-loading",
background: "rgba(0,0,0, 0.8)",
});
setTimeout(() => {
loading.close();
}, 500);
},
//向state的播放列表等一系列数据中新增点击的搜索歌曲
...mapActions([
'insertSong'
]),
//点击搜索的歌曲
selectItem(item){
this.insertSong(item);
}
},
watch: {
inputValue(newVal) {
this.currentPage = 1; //搜索显示第一页的结果
this.kugouSearchList = [];//重置
this.getSearchList(newVal, this.currentPage); //获取搜索数据
}
},
components: {
suggest
}
};
</script>
<style lang="less" scoped>
在Action中定义点击搜索歌曲后将歌曲插入播放列表的函数(封装了多个数据的改变)
Action.js文件
//用于将搜索的歌曲添加到播放列表中,修改相应的数据
export const insertSong = function ({
commit,
state
}, song) {
let playList = state.playList;
let sequenceList = state.sequenceList;
let currentIndex = state.currentIndex;
/////////////////////////////////////////////修改播放列表
// 记录当前歌曲
let currentSong = playList[currentIndex];
//查找当前列表是否已存在待插入的歌曲,并返回索引
let fpIndex = findIndex(playList, song);
//插入歌曲,索引+1
currentIndex++;
playList.splice(currentIndex, 0, song);
//索引大于-1,已存在,删除原来的歌曲
if (fpIndex > -1) {
//当前插入的序号大于被删除歌曲的序号
if (currentIndex > fpIndex) {
playList.splice(fpIndex, 1);
currentIndex--;
} else { //反之
playList.splice(fpIndex + 1, 1);
}
}
/////////////////////////////////////////////修改顺序列表
//找到当前歌曲在顺序列表的索引,+1,表示插入歌曲在顺序列表中应该处于的位置
let currentSIndex = findIndex(sequenceList, currentSong) + 1;
let fsIndex = findIndex(sequenceList, song);
sequenceList.splice(currentSIndex, 0, song);
if (fsIndex > -1) {
if (currentSIndex > fsIndex) {
sequenceList.splice(fsIndex, 1);
} else {
sequenceList.splice(fsIndex + 1, 1);
}
}
//上述不需要修改currentIndex,因为currentIndex是表示在playList中的索引位置,而我们在顺序列表中只需要将歌曲正确插入即可(保证歌曲唯一)
//提交修改
commit("set_sequenceList", sequenceList);
commit("set_playList", playList);
commit("set_currentIndex", currentIndex);
//提交打开播放器操作
commit("set_fullScreen", true);
commit("set_playing", true); //处于播放状态
}
//判断搜索的歌曲是否已经存在于播放列表中
function findIndex(list, song) {
return list.findIndex(item => {
return item.id === song.id
})
}
suggest.vue组件
<template>
<scroll class="suggest" :data="searchList" :pullup="true" @scrollToEnd="searchMore">
<ul class="suggest-list" :style="setPaddingBottom">
<li
v-show="searchList.length>0"
class="suggest-item"
v-for="(item,index) in searchList"
:key="index"
@click="selectItem(item)"
>
<div class="icon">
<i class="el-icon-video-play"></i>
</div>
<div class="name">
<p class="text">{{item.filename}}</p>
</div>
</li>
</ul>
</scroll>
</template>
<script>
import scroll from "../base/scroll";
import { mapGetters } from "vuex";
export default {
props: {
searchList: {
type: Array,
default: () => {}
}
},
components: {
scroll
},
methods: {
searchMore() {
this.$emit("searchMore");
},
selectItem(item){
this.$emit('selectItem',item);
}
},
watch: {
fullScreen: function(newVal) {
newVal == true
? (this.setPaddingBottom = "")
: (this.setPaddingBottom = "padding-bottom:3.5rem");
}
},
computed: {
...mapGetters(["playList", "fullScreen"]),
setPaddingBottom: {
get: function() {
if (this.playList) {
if (this.playList.length) {
return this.fullScreen ? "" : "padding-bottom:3.5rem";
}
} else {
return "";
}
},
set: function(newValue) {}
}
}
};
</script>
<style lang="less" scoped>
此时能够显示搜索歌曲,并点击播放,但是还无法实现上拉加载
效果图:
给scroll组件添加一个pullup的props属性,默认不带上拉加载效果
在即将滚动到底部时,抛出scrollToEnd函数
在suggest中接收scrollToEnd
并抛出searchMore函数,在search-box中接收,实现上拉加载
效果图:
节流函数throttle优化搜索请求
滑动搜索歌曲,搜索框失焦,隐藏移动端的输入键盘
在scroll组件添加属性
suggset接收并继续向上抛出事件
在search-box组件中,将输入框取消焦点
搜索历史
在state中定义数据searchHistoty数组存储搜索的内容
getters
mumations
//搜索历史数据
set_searchHistory(state, searchHistory) {
//已存在该搜索条目,将其先弹出,然后推入
if (state.searchHistory.length > 0 && state.searchHistory.includes(searchHistory)) {
for (let i = 0; i < state.searchHistory.length; i++) {
if (state.searchHistory[i] == searchHistory) {
state.searchHistory.splice(i, 1)
}
}
state.searchHistory.push(searchHistory);
return;
}
//超过7条数据,弹出
if (state.searchHistory.length > 6) {
state.searchHistory.reverse(); //反转数组
state.searchHistory.pop();
state.searchHistory.reverse(); //反转数组
}
state.searchHistory.push(searchHistory);
},
//删除历史数据
delete_searchHistory(state, value) {
for (let i = 0; i < state.searchHistory.length; i++) {
if (state.searchHistory[i] == value) {
state.searchHistory.splice(i, 1); //删除数据
}
}
},
//清空历史数据
deleteAll_searchHistory(state) {
state.searchHistory = [];
}
}
定义searchHistoryList.vue文件
在search-box组件中引入
效果图: