zoukankan      html  css  js  c++  java
  • 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
      }
    }
  • 相关阅读:
    Mysql数据查询
    Mysql数据类型
    desc和show
    Mysql权限管理
    深入理解inode和硬链接和软连接和挂载点
    Linux用户和组
    VIM文本编辑器
    Linux文件操作
    MySQL基础
    八大排序
  • 原文地址:https://www.cnblogs.com/catbrother/p/9179504.html
Copyright © 2011-2022 走看看