012_Vue音乐播放器(search.vue 搜索 组件)

本文介绍酷狗音乐搜索API的调用方法,包括热门关键词获取、歌曲搜索列表展示,以及如何在前端应用中集成这些功能,实现搜索、上拉加载更多歌曲和播放。同时,探讨了搜索请求的优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先是 酷狗搜索的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组件中引入

效果图:

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值