1.搜索框组件:
1 <template> 2 <div class="search-list" > 3 <el-input v-model="query" :placeholder="placeholder"></el-input> 4 <span v-show="query" @click.prevent="clear" class="el-icon-error"></span> 5 </div> 6 </template> 7 8 <script> 9 export default { 10 name: "search-list", 11 props:{ 12 placeholder:{ 13 type:String, 14 default:'搜索歌曲、歌手' 15 } 16 }, 17 data(){ 18 return { 19 query:'', 20 } 21 }, 22 methods:{ 23 clear(){ 24 console.log('qu') 25 this.query='' 26 }, 27 setQuery(query){ 28 console.log(query) 29 this.query = query 30 } 31 }, 32 created(){ 33 this.$watch('query',(newQuery)=>{//当搜索值发生变化的时候,将搜索值传递出去 34 this.$emit('query',newQuery ) 35 }) 36 } 37 } 38 </script>
2.搜索页面组件:
1 <template> 2 <div class="search"> 3 <search-list ref="searchBox" @query="onQueryChange"></search-list> 4 <div class="hot-search"> 5 <div class="hot-title">热门搜索</div> 6 <ul class="hot-list"> 7 <li @click.stop.prevent="addQuery(item.k)" class="host-span" v-for="(item) of hotKey ">{{item.k}}</li> 8 </ul> 9 </div> 10 <div class="search-list-box"> 11 <!--suggest需要传入query--> 12 <suggest :query="query"></suggest> 13 </div> 14 </div> 15 </template> 16 17 <script> 18 import SearchList from '@/base/search-list/search-list.vue' 19 import {getHotKey} from "../../api/search"; 20 import {ERR_OK} from '@/api/config' 21 import Suggest from '@/components/suggest/suggest' 22 23 export default { 24 name: "search", 25 components:{ 26 SearchList, 27 Suggest, 28 }, 29 data(){ 30 return { 31 hotKey: [], 32 query: '',//是根据search-list里面的监听的query来变化的;所以在这里面监听search-list派发过来的query时间 } 33 } 34 }, 35 created() { 36 this._getHotKey() 37 }, 38 methods:{ 39 onQueryChange(query){ 40 this.query = query 41 }, 42 _getHotKey() { 43 getHotKey().then((res) => { 44 if (res.code === ERR_OK) { 45 this.hotKey = res.data.hotkey.slice(0, 10) 46 console.log(this.hotKey) 47 } 48 }) 49 }, 50 addQuery(query){ 51 this.$refs.searchBox.setQuery(query) 52 } 53 } 54 55 } 56 </script>
3.搜索列表显示组件
1 <template> 2 <div class="suggest"> 3 <ul> 4 <li v-for="(item,index) of result"> 5 <div class="icon"> 6 <i :class="getIconCls"></i> 7 </div> 8 <div class="name"> 9 <p class="text" v-html="getDisplayName(item)"></p> 10 </div> 11 </li> 12 </ul> 13 </div> 14 </template> 15 16 <script> 17 import {search} from '@/api/search' 18 import {ERR_OK} from '@/api/config' 19 import {filterSinger} from '@/common/js/song' 20 const TYPE_SINGER = 'singer'//定义常量 21 22 export default { 23 name: "suggest", 24 data(){ 25 return { 26 result:[], 27 page:1,//第几页 28 } 29 }, 30 props:{ 31 query:{ 32 type:String, 33 defauult:'' 34 }, 35 showSinger:{//是否显示歌手 36 type:Boolean, 37 default:true 38 } 39 }, 40 watch:{ 41 query(){//当搜素关键词发生变化时候调用search方法; 42 search(this.query,this.page,this.showSinger).then((res)=>{//song代表歌曲,zhida代表歌手信息;前面的icon不同;p代表页码数;catzhida:要不要检索歌手; 43 if(res.code === ERR_OK){ 44 console.log(res) 45 this.result = this._genResult(res)//得到的搜索列表 46 } 47 }) 48 } 49 }, 50 methods:{ 51 getIconCls(item){//显示图标 52 if(item.type === TYPE_SINGER){ 53 return 'icon-mine' 54 }else{ 55 return "icon-music" 56 } 57 }, 58 getDisplayName(item){//显示名字 59 if(item.type === TYPE_SINGER){ 60 return item.singername 61 }else{ 62 return `${item.songname} - ${filterSinger(item.singer)}` 63 } 64 }, 65 _genResult(data) { 66 let ret = [] 67 if (data.zhida && data.zhida.singerid) {//歌手push到返回值李 68 ret.push({...data.zhida, ...{type: TYPE_SINGER}})//用来区分后面列表显示是歌手;将两个添加到一个对象上 69 } 70 if (data.song) { 71 //ret = 72 ret = ret.concat(this._normalizeSongs(data.song.list)) 73 } 74 return ret 75 }, 76 _normalizeSongs(list) { 77 let ret = [] 78 list.forEach((musicData) => { 79 if (musicData.songid && musicData.albummid) { 80 ret.push(createSong(musicData)) 81 } 82 }) 83 return ret 84 }, 85 } 86 } 87 </script>
搜索逻辑:
1.suggest.vue是根据搜索关键词来从后台请求数据并展示数据,因此需要props搜索词query;
2.suggest.vue监听搜索词query,当query发生变化的时候发送search请求,并渲染列表
3.父组件search.vue将:query="query",把词传递过来。
4.搜索框search-list.vue监听query并派发query事件,并把query传递出去;
5.search.vue接听query事件,并将收到的query参数传递给suggest.vue。