• 技术文章 >微信小程序 >小程序开发

    那些年,微信小程序仿网易云音乐有关实时搜索功能

    coldplay.xixicoldplay.xixi2020-09-14 13:20:25转载1395

    相关学习推荐:微信小程序教程

    前言

    前段时间我的小伙伴已经将网易云音乐小程序的音乐播放功能详细的介绍出来了,作为前端小白学习了一段时间,最近也比较忙,没有及时将实时搜索这块内容及时写出来跟大家分享(其实代码和功能之前就写的差不多了),那么今天就给大家讲一讲个人在里面的一些细节和优化吧。

    搜索功能很常见,很多地方都能用到,希望能够给大家分享到有用的东西,同时,有不足的地方,也希望各位大佬指出,给出一些修改的意见,小白在此感谢了!

    实时搜索功能里面我们也需要用到API接口,从input框输入值到搜索建议,再到搜索结果,最后到跳转歌曲播放,不再只是接那么简单,传值很关键,同时不同功能下不同容器框的隐藏与显示,还有一些搜索当中涉及的细节内容和优化。让我们一起来看看吧!

    界面预览

    界面分析

    头部搜索栏中:左边返回箭头,中间输入框,右边歌手排行榜页面跳转;至于清除按钮呢我们隐藏了起来,只有在输入输入值之后才会出现。

    往下时历史记录,像每个搜搜的记录值这里都是一小块一小块等隔距离分布,搜索值有多长,这小块就有多长,这里用到的是display: flex;flex-wrap: wrap;,对这个界面样式感兴趣的小伙伴可以待会看看全部代码。

    接下来是热搜榜,这里没有太多讲究,就是发起接口请求数据,把数据埋进去显示出来就行了。

    搜索建议会在输入结束后才会出现,并且是很立体的一块覆盖在整个页面上,用box-shadow: 1px 1px 5px #888888达到立体效果,z-index起到覆盖的效果。

    搜索结果会在点击搜索建议中的某一条或者点击搜索历史或者热搜才出现,同时界面上其他所有的容器快都会隐藏起来,这里其实就是一个容器框的隐藏与出现的小细节了,待会在功能中我们会详细讲到。这里我们先讲一下组件(容器)如何进行隐藏与显示,以免下面的功能中看到这几项内容蒙圈

    几个容器的头部展示

    <!-- 点击×可以清空正在输入 -->
    <image class="{{showClean ? 'header_view_hide' : 'clean-pic'}}" src="../../image/search_delete.png" bindtap="clearInput" />复制代码
    <!-- 搜索建议 -->
    <view class="{{showSongResult ? 'search_suggest' : 'header_view_hide'}}">复制代码
    <!-- 搜索结果 -->
    <view class="{{showSearchResult ? 'header_view_hide' : 'search_result_songs'}}">复制代码
    <!-- 搜索历史 -->
    <view class="{{showView?'option':'header_view_hide'}}">复制代码
    <!-- 热搜榜 -->
    <view class="{{showView?'option':'header_view_hide'}}">复制代码

    解析:这里只放了这几块容器的头部的内容,在data数据源中分别放了showClean,showSongResult,showSearchResult,showView, 为true 则这几块容器默认为:(冒号)前面的样式,为false则默认为:(冒号)后面的样式;header_view_hide样式设置为display: none;,即隐藏不显示;所以当在某一个方法中可以去改变showClean,showSongResult,showSearchResult,showViewtrue还是false可以让这几块容器分别为显示或是隐藏。

    接口封装

    接口封装在上一篇我的小伙伴已经讲的十分清晰了,我们这里不再多去讲解了,同样现在用到的功能也不只是光调接口请求数据那么简单了,我们需要传值给接口,让接口收到值后再给我们返回相应的数据;在搜索界面我们用到的是搜索建议以及搜索结果的接口。热搜榜我们暂时只使用最基础的wx.request直接获取数据

    api.js

    const API = {
        getSearchSuggest: (data) => request(GET, `/search/suggest`, data),  // 搜索建议接口
        getSearchResult: (data) => request(GET, `/search`, data),  // 搜索结果接口
    }复制代码

    实时搜索功能:

    1.数据源分析

    一个搜索功能我们设计到的数据会有很多,可以细列一下:输入的值inputValue,在输入时获取;热搜榜数据hots,热搜接口获取;搜索关键词searchKey,本身就是输入框的值,用来传递给搜索建议作为搜索关键词;searchSuggest,搜索建议接口拿到搜索关键词后返回的的数据(搜索建议);搜索结果searchResult,当点击搜索建议中的某一条,该值将填入搜索框,此时搜索关键词searchKey将变为该值又传递给搜索结果接口,并返回数据放入searchResult;最后是搜索历史history,每当进行一次搜索,将原本输入框的值放到history数据源中。关于其他数据源涉及到组件隐藏与展示,即每一块的容器框在何种情况下隐藏,何种情况下显示。

    数据源展示

    data: {
        inputValue: null,//输入框输入的值
        history: [], //搜索历史存放数组
        searchSuggest: [], //搜索建议
        showView: true,//组件的显示与隐藏
        showSongResult: true,
        searchResult: [],//搜索结果
        searchKey: [],
        showSearchResult: true,
        showClean: true,
        hots: [] //热门搜索
     }复制代码

    2.获取热搜榜

    这里我们直接在页面的初始数据中调用接口,直接获取到数据使用

    onLoad: function (options) {
        wx.request({
          url: 'http://neteasecloudmusicapi.zhaoboy.com/search/hot/detail',
          header: { "Content-Type": "application/json" },
          success: (res) => {  // console.log(res)
            this.setData({
              hots: res.data.result.hots })
          }
        })
      },复制代码

    3.获取input文本

    前面已将讲过,搜索建议和结果的接口并没有直接的获取方式,需要我们进行传值,所以首先我们需要获取到输入框的值

    input框内容分析

    <input focus='true' type="text" class="weui-search-bar__input" placeholder="大家都在搜 " placeholder-style="color:#eaeaea" value='{{inputValue}}' bindinput="getSearchKey" bindblur="routeSearchResPage" bindconfirm="searchOver" />复制代码

    小程序中关于input输入框的相关属性大家可以去详细了解一下;placeholder为输入框为空时占位符,即还没输入前输入框显示的内容,placeholder-style可以去设置placeholder的样式;value是输入框的初始内容,即自己在输入框输入的内容,我们在这里直接将输入的内容value直接作为了data数据源中inputValue的内容;bindinput是在键盘输入时触发,即我们一进行打字,就能触发我们的自定义事件getSearchKey,并且会返还相应数据;bindblur在输入框失去焦点时触发,进行搜索功能时,需要在搜索框输值,此时焦点一直在输入框,当点击输入框以外的地方即输入框失去焦点,同时触发routeSearchResPage事件,还会返回相应的数据,在下面功能中会讲到;bindconfirm在点击完成按钮时触发,这里绑定一个searchOver,用来隐藏组件(容器块),再次触发搜索功能,在下面的功能中也会讲到。

    获取input文本

    getSearchKey: function (e) {
        // console.log(e.detail) //打印出输入框的值
        if (e.detail.cursor != this.data.cursor) { //实时获取输入框的值
          this.setData({
            showSongResult: true,
            searchKey: e.detail.value })
          this.searchSuggest();
        }
        if (e.detail.value) { // 当input框有值时,才显示清除按钮'x'
          this.setData({
            showClean: false  // 出现清除按钮 })
        }
        if(e.detail.cursor === 0){
          this.setData({  // 当输入框没有值时,即没有输入时,隐藏搜索建议界面,返回到最开始的状态
            showSongResult: false })
          return
        }
      }复制代码

    bindinput本身是会返回数据,在代码运行时,可以打印出来先看看; e.detail.value即为输入框的值,将它赋值给searchKey; 查看打印数据e:

    解析:

    疑惑的小伙伴可以将代码运行,打印出以上设计的几个数据进行分析

    ①当此时输入框的值和bindinput返回的输入框的值时一样的,就将输入框的值赋给搜索关键词searchKey,此时显示搜索建议栏(showSongResult写在wxml当中,用来控制该容器是否展示,可以看到最后面发的整个界面的wxml中的详情);同时searchSuggest事件(方法)生效。

    ②当输入框没值时,清除按钮x是不会显示的,只有当输入框有值是才会出现清除按钮x

    ③当输入框没有值时,隐藏搜索建议栏,其实本身我们最开始进入这个页面时,输入框是没值的,搜索建议栏也是不展示的,为没进行输入就没有数据;但是当我们输入内容后,出现搜索建议,此时我们点击清除按钮,输入框的内容没了,但是搜索建议还停留在之前的状态,所以这里我们优化一下,让showSongResultfalse,即一清空输入框内容,隐藏掉搜索建议栏。另外我们为什么要return呢?这里还有一个bug,当清除输入框内容后,再输入发现已经不再具备搜索功能了,所以需要return回到初始的状态,就能重新进行输入并且搜索。同时当输入框为空时进行搜索功能还会报错,这也是一个bug,所以有了return即使空值搜索也会立马回到初始状态,解决了空值搜索报错的bug

    4.搜索框其他功能

    5.搜索建议

     searchSuggest() {
        $api. getSearchSuggest({ keywords: this.data.searchKey, type: 'mobile' }).then(res => {
          //请求成功 
          // console.log(res);  // 打印出返回数据进行查看
          if(res.statusCode === 200){
            this.setData({
              searchSuggest: res.data.result.allMatch  // 将返回数据里的歌名传给搜索建议
            })
           }
        })
        .catch(err => {  // 请求失败
          console.log('错误')   })
      }复制代码

    解析:开始我们将接口进行了封装,在上一篇讲播放的文章中我的小伙伴已经把接口跟封装讲的很仔细了,这里我们就不在讲这个了,就分析我们的接口。searchKey作为搜索关键词需要传递给接口,在前面的getSearchKey方法中,我们已经讲输入框的内容传给了searchKey作为它的值;所以此时我们拿到有值的searchKey传递给接口,让接口返回相关数据,返回的数据中的res.data.result.allMatch就是从搜索关键词返回的搜索建议里的所有歌名,在将这些数据放到searchSuggest数据源中,这样在wxml埋好的空就能拿到数据,将搜索建议栏显示出。

    6.搜索结果

    7.搜索历史

    8.歌曲跳转播放播放

    9.search功能源码分享

    wxml

    <nav-bar></nav-bar>
    <view class="wrapper">
        <!-- 上部整个搜索框 -->
        <view class="weui-search-bar">
            <!-- 返回箭头按钮 -->
            <view class="weui-search-bar__cancel-btn" bindtap="back">
                <image class="return-pic" src="../../image/search_return.png" bindtap="cancel" />
            </view>
            <!-- 搜索栏 -->
            <view class="weui-search-bar__form">
                <view class="weui-search-bar__box">
                    <input focus='true' type="text" class="weui-search-bar__input" placeholder="大家都在搜 " placeholder-style="color:#eaeaea" value='{{inputValue}}' bindinput="getSearchKey" bindblur="routeSearchResPage" bindconfirm="searchOver" />
                </view>
                <!-- 点击×可以清空正在输入 -->
                <view class="clean-bar">
                    <image class="{{showClean ? 'header_view_hide' : 'clean-pic'}}" src="../../image/search_delete.png" bindtap="clearInput" />
                </view>
            </view>
            <!-- 跳转歌手分类界面 -->
            <view class="songer">
                <image class="songer-pic" src="../../image/search_songner.png" bindtap="singerPage" />
            </view>
        </view>
        <!-- 搜索建议 -->
        <view class="{{showSongResult ? 'search_suggest' : 'header_view_hide'}}">
            <view wx:for="{{searchSuggest}}" wx:key="index" class='search_result' data-value='{{item.keyword}} ' bindtap='fill_value'>
                <image class="search-pic" src="../../image/search_search.png"></image>
                <view class="search_suggest_name">{{item.keyword}}</view>
            </view>
        </view>
        <!-- 搜索结果 -->
        <view class="{{showSearchResult ? 'header_view_hide' : 'search_result_songs'}}">
            <view class="search-title">
                <text class="songTitle">单曲</text>
                <view class="openBox">
                    <image class="openTap" src="../../image/search_openTap.png" />
                    <text class="openDes">播放全部</text>
                </view>
            </view>
            <view wx:for="{{searchResult}}" wx:key="index" class='search_result_song_item' data-id="{{item.id}}" bindtap='handlePlayAudio'>
                <view class='search_result_song_song_name'>{{item.name}}</view>
                <view class='search_result_song_song_art-album'>
                    {{item.artists[0].name}} - {{item.album.name}}
                </view>
                <image class="broadcast" src="../../image/search_nav-open.png" />
                <image class="navigation" src="../../image/mine_lan.png" />
            </view>
        </view>
        <!-- 搜索历史 -->
        <view class="{{showView?'option':'header_view_hide'}}">
            <view class="history">
                <view class="history-wrapper">
                    <text class="history-name">历史记录</text>
                    <image bindtap="clearHistory" class="history-delete" src="../../image/search_del.png" />
                </view>
                <view class="allhistory">
                    <view class="allhistorybox" wx:for="{{history}}" wx:key="index" data-value='{{item}}' data-index="{{index}}" bindtap="fill_value">
                        <text class="historyname">{{item}}</text>
                    </view>
                </view>
            </view>
        </view>
        <!-- 热搜榜 -->
        <view class="{{showView?'option':'header_view_hide'}}">
            <view class="ranking">
                <text class="ranking-name">热搜榜</text>
            </view>
            <view class="rankingList">
                <view class="rankingList-box" wx:for="{{hots}}" wx:key="index">
                    <view wx:if="{{index <= 2}}">
                        <text class="rankingList-num" style="color:red">{{index+1}}</text>
                        <view class="song">
                            <text class="rankigList-songname" style="color:black;font-weight:600" data-value="{{item.first}}" bindtap='fill_value'>
                                {{item.first}}
                            </text>
                            <block wx:for="{{detail}}" wx:key="index">
                                <text class="rankigList-hotsong" style="color:red">{{item.hot}}</text>
                            </block>
                        </view>
                    </view>
                    <view wx:if="{{index > 2}}">
                        <text class="rankingList-num">{{index+1}}</text>
                        <view class="othersong">
                            <text class="rankigList-songname" data-value="{{item.first}}" bindtap='fill_value'>
                                {{item.first}}
                            </text>
                        </view>
                    </view>
                </view>
            </view>
        </view>
    </view>复制代码

    wxss

      /* pages/search/search.wxss */
    .weui-search-bar{
        position:relative;
        /* padding:8px; */
        display:flex;
        box-sizing:border-box;
        /* background-color:#EDEDED; */
        -webkit-text-size-adjust:100%;
        align-items:center
    }
    .weui-icon-search{
        margin-right:8px;font-size:14px;vertical-align:top;margin-top:.64em;
        height:1em;line-height:1em
    }
    .weui-icon-search_in-box{
        position:absolute;left:12px;top:50%;margin-top:-8px
    }
    .weui-search-bar__text{
        display:inline-block;font-size:14px;vertical-align:top
    }
    .weui-search-bar__form{
        position:relative;
        /* flex:auto;
        border-radius:4px;
        background:#FFFFFF */
        border-bottom: 1px solid #000;
        margin-left: 30rpx;
        width: 400rpx;
        padding-right: 80rpx;
    }
    .weui-search-bar__box{
        position:relative;
        padding-right: 80rpx;
        box-sizing:border-box;
        z-index:1;
    }
    .weui-search-bar__input{
        height:32px;line-height:32px;font-size:14px;caret-color:#07C160
    }
    .weui-icon-clear{
        position:absolute;top:0;right:0;bottom:0;padding:0 12px;font-size:0
    }
    .weui-icon-clear:after{
        content:"";height:100%;vertical-align:middle;display:inline-block;width:0;overflow:hidden
    }
    .weui-search-bar__label{
        position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;border-radius:4px;
        text-align:center;color:rgba(0,0,0,0.5);background:#FFFFFF;line-height:32px
    }
    .weui-search-bar__cancel-btn{
        margin-left:8px;line-height:32px;color:#576B95;white-space:nowrap
    }
    .clean-bar {
        /* width: 20rpx;
        height: 20rpx; */
    }
    .clean-pic {
        width: 20rpx;
        height: 20rpx;
        float: right;
        position: absolute;
         margin-top: -30rpx; 
         margin-left: 450rpx;
    }
    .return-pic {
        width: 60rpx;
        height: 60rpx;
        margin-left: 20rpx;
    }
    .songer-pic{
        width: 60rpx;
        height: 60rpx;
        margin-left: 40rpx;
    }
    .wrapper {
        width: 100%;
        height: 100%;
        position: relative;
        z-index: 1;
    }
    .poster {
        width: 670rpx;
        height: 100rpx;
        margin-top: 40rpx;
        margin-left: 40rpx;
    }
    .postername {
        font-size: 15rpx;
        position: absolute;
        margin-top: 10rpx;
        margin-left: 10rpx;
    }
    .poster-outside {
        border-radius: 10rpx;
        background-color: slategrey;
    }
    .poster-pic0 {
        width: 80rpx;
        height: 80rpx;
        margin-top: 10rpx;
    }
    .test-title {
        position: absolute;
        font-size: 30rpx;
        line-height: 100rpx;
        margin-left: 20rpx;
        color: red;
    }
    .test-age {
        position: absolute;
        font-size: 30rpx;
        line-height: 100rpx;
        margin-left: 80rpx;
    }
    .test-red {
        position: absolute;
        font-size: 30rpx;
        line-height: 100rpx;
        margin-left: 270rpx;
        color: red;
    }
    .test-black {
        position: absolute;
        font-size: 30rpx;
        line-height: 100rpx;
        margin-left: 400rpx;
    }
    .poster-pic1 {
        width: 80rpx;
        height: 80rpx;
        margin-left: 510rpx;
    }
    .history {
        margin: 50rpx 0 0 40rpx;
    }
    .history-name {
        font-size: 28rpx;
        font-weight: 550;
    }
    .history-delete {
        width: 50rpx;
        height: 50rpx;
        position: absolute;
        margin-left: 510rpx;
    }
    .allhistory {
        display: flex;
        flex-wrap: wrap;
    }
    .allhistorybox {
        margin: 30rpx 20rpx 0 0;
        background-color: dimgray;
        border-radius: 10rpx;
    }
    .historyname {
        font-size: 28rpx;
        margin: 20rpx 20rpx 20rpx 20rpx;
    }
    .ranking {
        margin-left: 40rpx;
        margin-top: 100rpx;
    }
    .ranking-name {
        font-size: 28rpx;
        color: black;
        font-weight: 550;
    }
    .rankingList {
        margin-left: 50rpx;
        margin-top: 30rpx;
    }
    .rankingList-box {
        width: 100%;
        height: 80rpx;
        margin: 0 0 30rpx 0;
    }
    .rankingList-num {
        line-height: 80rpx;
        align-content: center;
    }
    .song {
        margin: -100rpx 0 0 30rpx;
        display: flex;
        flex-wrap: wrap;
    }
    .othersong {
        margin-top: -100rpx;
        margin-left: 70rpx;
    }
    .rankigList-songname {
        font-size: 30rpx;
        margin-left: 40rpx;
    }
    .rankigList-hotsong {
        font-size: 25rpx;
        font-weight: 550;
        margin-top: 45rpx;
        margin-left: 20rpx;
    }
    .rankigList-hotnum {
        float: right;
        position: absolute;
        line-height: 80rpx;
        margin-left: 600rpx;
        font-size: 20rpx;
        color: darkgrey;
    }
    .rankingList-songdes {
        font-size: 22rpx;
        color: darkgrey;
        position: absolute;
        margin-left: 60rpx;
        margin-top: -30rpx;
    }
    .search_suggest{
        width:570rpx;
        margin-left: 40rpx;
        position: absolute;
        z-index: 2;
        background: #fff;
        box-shadow: 1px 1px 5px #888888;
        margin-top: 20rpx;
    }
    .header_view_hide{
        display: none;
      }
    .search-pic {
          width: 50rpx;
          height: 50rpx;
         margin-top: 25rpx;
         margin-left: 20rpx;
    }
    .search-title {
        color: #000;
        margin-left: 15rpx;
        margin-bottom: 30rpx;
    }
    .songTitle {
        font-size: 30rpx;
        font-weight: 700;
    }
    .openBox {
        float: right;
        border-radius: 30rpx;
        margin-right: 30rpx;
        border-radius: 30rpx;
        border-bottom: 1px solid #eaeaea;
    }
    .openTap {
        width: 30rpx;
        height: 30rpx;
        position: absolute;
        margin: 6rpx 10rpx 0rpx 20rpx;
    }
    .openDes {
        font-size: 25rpx;
        color: rgba(0,0,0,0.5);
        margin-right: 20rpx;
        margin-left: 58rpx;
    }
    .broadcast {
        width: 20px;
        height: 20px;
        display: inline-block;
        overflow: hidden;
        float: right;
        margin-top: -70rpx;
        margin-left: -120rpx;
        margin-right: 80rpx;
    }
    .navigation {
        width: 20px;
        height: 20px;
        display: inline-block;
        overflow: hidden;
        float: right;
        margin-top: -70rpx;
        margin-right: 20rpx;
    }
      .search_result{
        /* display: block;
        font-size: 14px;
        color: #000000;
        padding: 15rpx;
        margin: 15rpx; */
        /* border-bottom: 1px solid #eaeaea; */
        /* float: right; */
        /* margin-left: -450rpx; */
        width: 570rpx;    
        height: 100rpx;
        border-bottom: 1px solid #eaeaea;
      }
      .search_suggest_name {
        display: block;
        float: right;
        position: absolute;
        margin-left: 85rpx;
        margin-top: -46rpx;
        font-size: 14px;
        color: darkgrey;
        /* padding: 15rpx;
        margin: 15rpx; */
      }
      .search_result_songs{
        margin-top: 10rpx;
        width: 100%;
        height: 100%;
        margin-left: 15rpx;
      }
      .search_result_song_item{
         display: block;
         margin: 15rpx;
         border-bottom: 1px solid #EDEEF0;
      }
      .search_result_song_song_name{
        font-size: 15px;
        color: #000000;
        margin-bottom: 15rpx;
      }
      .search_result_song_song_art-album{
        font-size: 11px;
        color: #000000;
        font-weight:lighter;
        margin-bottom: 5rpx;
      }复制代码

    js

    // pages/search/search.js
    // const API = require('../../utils/req')
    const $api = require('../../utils/api.js').API;
    const app = getApp();
    Page({
      data: {
        inputValue: null,//输入框输入的值
        history: [], //搜索历史存放数组
        searchSuggest: [], //搜索建议
        showView: true,//组件的显示与隐藏
        showSongResult: true,
        searchResult: [],//搜索结果
        searchKey: [],
        showSearchResult: true,
        showClean: true,
        hots: [], //热门搜索
        detail: [
          {
            hot: 'HOT'
          }
        ],
      },
      onLoad: function (options) {
        wx.request({
          url: 'http://neteasecloudmusicapi.zhaoboy.com/search/hot/detail',
          data: {
          },
          header: {
            "Content-Type": "application/json"
          },
          success: (res) => {
            // console.log(res)
            this.setData({
              hots: res.data.result.hots
            })
          }
        })
      },
      // 点x将输入框的内容清空
      clearInput: function (e) {
        // console.log(e)
        this.setData({
          inputValue: '',
          showSongResult: false,
          showClean: true // 隐藏清除按钮
        })
      },
      //实现直接返回返回上一页的功能,退出搜索界面
      back: function () {
        wx: wx.navigateBack({
          delta: 0
        });
      },
      // 跳转到歌手排行界面
      singerPage: function () {
        // console.log('a')
        wx.navigateTo({
          url: `../singer/singer`
        })
      },
      //获取input文本并且实时搜索
      getSearchKey: function (e) {
        if(e.detail.cursor === 0){
          this.setData({
            showSongResult: false
          })
          return
        }
        // console.log(e.detail) //打印出输入框的值
        if (e.detail.cursor != this.data.cursor) { //实时获取输入框的值
          this.setData({
            showSongResult: true,
            searchKey: e.detail.value
          })
          this.searchSuggest();
        }
        if (e.detail.value) { // 当input框有值时,才显示清除按钮'x'
          this.setData({
            showClean: false  // 出现清除按钮
          })
        }
      },
      // 搜索建议
      searchSuggest() {
        $api. getSearchSuggest({ keywords: this.data.searchKey, type: 'mobile' }).then(res => {
          //请求成功 
          // console.log(res);
          if(res.statusCode === 200){
            this.setData({
              searchSuggest: res.data.result.allMatch 
            })
           }
        })
        .catch(err => {
          //请求失败
          console.log('错误')
        })
      },
      // 搜索结果
      searchResult: function () {
        // console.log(this.data.searchKey)
        $api.getSearchResult({ keywords: this.data.searchKey, type: 1, limit: 100, offset: 2 }).then(res => {
          // 请求成功
          if (res.statusCode === 200) {
            // console.log(res)
            this.setData({
              searchResult: res.data.result.songs,
              showSearchResult: false,
              showView: false,
            });
          }
        })
        .catch(ree => {
          //请求失败
        })
      },
      handlePlayAudio: function (e) { //event 对象,自带,点击事件后触发,event有type,target,timeStamp,currentTarget属性
        // console.log(e)
        const musicId = e.currentTarget.dataset.id; //获取到event里面的歌曲id赋值给musicId
        wx.navigateTo({                                 //获取到musicId带着完整url后跳转到play页面
          url: `../play/play?musicId=${musicId}`
        })
      },
      // input失去焦点函数
      routeSearchResPage: function (e) {
        // console.log(e)
        // console.log(e.detail.value)
        // console.log(this.data.searchKey)
        // console.log(this.data.searchKey.length)  
        if (this.data.searchKey.length > 0) {  // 当搜索框有值的情况下才把搜索值存放到历史中,避免将空值存入历史记录
          let history = wx.getStorageSync("history") || [];
          // console.log(history);
          history = history.filter(item => item !== this.data.searchKey)  // 历史去重
          history.unshift(this.data.searchKey)
          wx.setStorageSync("history", history);
        }  
      },
      // 清空page对象data的history数组 重置缓存为[](空)
      clearHistory: function () {
        const that = this;
        wx.showModal({
          content: '确认清空全部历史记录',
          cancelColor: '#DE655C',
          confirmColor: '#DE655C',
          success(res) {
            if (res.confirm) {
              that.setData({
                history: []
              })
              wx.setStorageSync("history", []) //把空数组给history,即清空历史记录
            } else if (res.cancel) {
            }
          }
        })
      },
        // 搜索结果完成后(再次点击输入框)
      searchOver: function () {
        this.searchSuggest();  // 执行搜索结果
        this.searchResult()
      },
      // 点击热门搜索值或搜索历史,填入搜索框
      fill_value: function (e) {
        console.log(e)
        // console.log(this.data.history)
        // console.log(e.currentTarget.dataset.value)
        this.setData({
          searchKey: e.currentTarget.dataset.value,//点击=把值给searchKey,让他去搜索
          inputValue: e.currentTarget.dataset.value,//在输入框显示内容
          showSongResult: false, //给false值,隐藏搜索建议页面
          showClean: false // 显示 清除按钮
        })
        this.searchResult(); //执行搜索功能
      },
      /**
       * 生命周期函数--监听页面显示
       */
      //每次显示变动就去获取缓存,给history,并for出来。
      onShow: function () {
        // console.log('a')
        this.setData({
          history: wx.getStorageSync("history") || []
        })
      },
    })复制代码

    api.js

    const app = getApp();
    // method(HTTP 请求方法),网易云API提供get和post两种请求方式
    const GET = 'GET';
    const POST = 'POST';
    // 定义全局常量baseUrl用来存储前缀
    const baseURL = 'http://neteasecloudmusicapi.zhaoboy.com';
    function request(method, url, data) {
      return new Promise(function (resolve, reject) {
        let header = {
          'content-type': 'application/json',
          'cookie': app.globalData.login_token
        };
        wx.request({
          url: baseURL + url,
          method: method,
          data: method === POST ? JSON.stringify(data) : data,
          header: header,
          success(res) {
            //请求成功
            //判断状态码---errCode状态根据后端定义来判断
            if (res.data.code == 200) {  //请求成功
              resolve(res);
            } else {
              //其他异常
              reject('运行时错误,请稍后再试');
            }
          },
          fail(err) {
            //请求失败
            reject(err)
          }
        })
      })
    }
    const API = {
      getSearchSuggest: (data) => request(GET, `/search/suggest`, data),  // 搜索建议接口
      getSearchResult: (data) => request(GET, `/search`, data),  // 搜索结果接口
    };
    module.exports = {
      API: API
    }复制代码

    总结

    其实一点一点的捋清楚会发现也不是很难操作,首先思路要清晰,知道每一个功能是什么作用,同时在调试是时候去发现一些bug,再去对代码进行优化。关于搜索这个功能用处广泛,希望本次的分享能给大家带来一点用处。

    相关学习推荐:微信公众号开发教程javascript视频教程

    以上就是那些年,微信小程序仿网易云音乐有关实时搜索功能的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:juejin,如有侵犯,请联系admin@php.cn删除
    上一篇:那些年,看看微信小程序仿网易云音乐的相关播放 下一篇:详解使用 taro-deploy 自动化构建发布 taro 小程序
    大前端线上培训班

    相关文章推荐

    • 微信小程序传图识字怎么取字• 在微信小程序中实现virtual-list的方法详解• 了解微信小程序 Taro 的自动埋点• 那些年,看看微信小程序仿网易云音乐的相关播放

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网