vue-music 关于Search(搜索页面)--上拉加载

  

建立搜索框组件页面,searchBox,组件接受一个可以自定义传入的placeholder 属性。input v-model 双向绑定数据关联到query 中, 在created中监听 query 变量将改变的新值派发给外部父组件,在search.vue 组件中将其引入

<div class="search-box">
    <i class="icon-search"></i>
    <input type="text" class="box" :placeholder="placeholder" v-model="query">
    <i class="icon-dismiss" v-show="query" @click="clear"></i>
</div>

 

export default {
  props:{
    placeholder:{
      type:String,
      default:'搜索歌曲、歌手'
    }
  },
  data(){
    return {
      query:''
    }
  },
  created(){
    this.$watch('query',(newQuery) => {
      this.$emit('query',newQuery);
    })
  },
  methods:{
    clear(){
      this.query = '';
    },
    setQuery(query){    // 创建主动设置input 变量值,赋值给父级data中
      this.query = query;
    }
  }
}

 

search.vue

热门搜索模块,通过search.js 的getHotKey 函数异步获取数据,并渲染,给每个item 上绑定addQuery(item.k) 将其值赋值给input 的value 值,通过调用 this.$refs.searchBox.setQuery(query)

<li class="item" v-for="item in hotKey" @click="addQuery(item.k)"><span>{{item.k}}</span></li>

methods:{
    addQuery(query){
        this.$refs.searchBox.setQuery(query);
    },
    onQueryChange(query){    //监听派发过来的query 属性,报存到父级的data 变量中,可以用于判断用户是否有输入搜索值做相应的业务逻辑
        this.query = query;
    },
    _getHotKey(){
        getHotKey().then((res) => {
            if(res.code === ERR_OK){
                this.hotKey = res.data.hotkey.slice(0,10);
            }
        })
    }
},

 

当搜索框有关键词的时候,就应该发出请求 搜索对应的歌曲或者歌手。请求数据格式返回 包含两个字段,song 为搜索歌曲数据,zhida 为搜索关键字为歌手的数据,上拉加载后面再说,首先要把获取的数据格式化成想要的数据格式

通过_genResult 方法判断如果搜索结果中有zhida字段并且有zhida.singerid 则说明搜索关键字为歌手,将其push到新数组中,判断是否有相关歌曲song 字段 ,再把歌曲列表追加到新数组中并返回

创建suggest.vue 组件展示搜索结果列表,如果列表项是歌手前面的图标根据返回的结果来判断替换相应图标。歌手名称和歌曲名称同理

<scroll class="suggest" :data="result" :pullup="pullup" @scrollToEnd="searchMore" ref="suggest">
  <ul class="suggest-list">
    <li class="suggest-item" v-for="item in result">
      <div class="icon">
        <i :class="getIconCls(item)"></i>
      </div>
      <div class="name">
        <p class="text" v-html="getDisplayName(item)"></p>
      </div>
    </li>
  <loading v-show="hasMore" title=""></loading>
  <div class="under-line" v-show="!hasMore">到我底线了</div>
  </ul>
</scroll>

引入sceoll 组件,开启上拉加载事件 :pullup:'true'

if(this.pullup){
  this.scroll.on('scrollEnd',()=>{
    if(this.scroll.y <= (this.scroll.maxScrollY + 50)){    //当滚动距离离底部50 像素的时候,派发事件,父级监听此事件做再次请求数据接口
      this.$emit('scrollToEnd')
    }
  })
}

 

监听派发上拉加载事件 @scrollToEnd="searchMore"  

在首次加载数据的时候设置 监测还有没有数据的标志位 hasMore = true 在成功获取前20条数据的时候调用监测函数 this.checkMore(res.data);  checkMore根据传来的请求值判断 当前页数乘以每页数量 加上 每页加载数量 如果大于等于数据的总数量,则表示下一页已无数据,设置标志位为false ,在上拉加载函数 searchMore 中 首先判断标志位,如果有数据,页码加一,再请求数据接口,将结果 concat追加到result 数据中。注意这里再一次请求的时候,将showSinger 参数设置为false,表示第二页请求不再显示歌手

import {search} from "api/search.js";
import {ERR_OK} from "api/config.js";
import {createSong} from "common/js/song.js";
import Scroll from 'base/scroll/scroll.vue'
import Loading from 'base/loading/loading.vue'

const TYPE_SINGER = 'singer';
const perpage = 20;
export default {
  props:{
    query:{
      type:String,
      default:''
    },
    showSinger:{
      type:Boolean,
      default:true
    }
  },
  data(){
    return {
      page:1,
      result:[],
      pullup:true,
      hasMore:true
    }
  },
  methods:{
    search(){
      this.page = 1;
      this.hasMore = true;
      this.$refs.suggest.scrollTo(0,0);
      search(this.query,this.page,this.showSinger,perpage).then((res) => {
        if(res.code === ERR_OK){
          this.result= this._genResult(res.data);
          this.checkMore(res.data);
        }
      })
    },
    searchMore(){
      if(!this.hasMore){
        return;
      }
      this.page++;
      search(this.query,this.page,false,perpage).then((res) => {
        if(res.code === ERR_OK){
          this.result= this.result.concat(this._genResult(res.data));
          console.log(this.result)
          this.checkMore(res.data);
        }
      })
    },
    checkMore(data){
      let song = data.song;
      if(!song.list.length || (song.curnum + song.curpage * perpage) >= song.totalnum){
        this.hasMore = false;
      }
    },
    getIconCls(item){
      if(item.type === TYPE_SINGER){
        return 'icon-mine'
      }else{
        return 'icon-music'
      }
    },
    getDisplayName(item){
      if(item.type === TYPE_SINGER){
        return item.singername;
      }else{
        return `${item.name} - ${item.singer}`
      }
      
    }, 
    _genResult(data){
      let ret = [];
      if(data.zhida && data.zhida.singerid){
        ret.push({...data.zhida,...{type:TYPE_SINGER}})
      }
      if(data.song){
        ret = ret.concat(this._normalizeSongs(data.song.list));
      }
      return ret;
    },
    _normalizeSongs(list){
      let ret = [];
      list.forEach((musicData) => {
        if(musicData.songid && musicData.albumid){
          ret.push(createSong(musicData))
        }
      })
      return ret;
    }
  },
  watch:{
    query(){
      this.search();
    }
  },
  components:{
    Scroll,
    Loading
  }
}

 

posted @ 2017-11-29 17:01  ankle  阅读(1911)  评论(0编辑  收藏  举报