vue网易云歌单案例

本文档详细介绍了如何使用Vue.js和Vant组件库构建一个网易云歌单应用,包括初始化项目、配置路由、引入导航栏和tabbar、设置路由模式、实现首页推荐歌单、搜索功能、防抖技术以及移动适配等关键步骤。

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

一、Vant组件的使用(注意版本号)

1、yarn add axios vant@2.12.24 vue-router@3.5.3

2、自动按需引入

yarn add babel-plugin-import -D

3、babel.config.js

  plugins: [
    ['import', {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    }, 'vant']
  ]

4、main.js里引入需要使用的组件

5、重启后即可使用并看到效果

二、初始化项目

三、配置路由

1. 安装 : yarn add vue-router@3.5.3

2. 准备工作 3 个  创建router/index.vue

//1. 引入

import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)

//2.创建路由实例

const router = new VueRouter()

//3. 挂载

export default router

3. 具体步骤 3 个

//1.入口

//2.规则

routes: [
    { path: '/', redirect: '/layout' },
    {
      path: '/layout',
      component: Layout,
      children: [
        { path: 'home', component: Home },
        { path: 'search', component: Search },
      ],
    },
    { path: '/play', component: Play },
  ],

//3.出口

<router-view> <router-view/>

四、引入导航栏和tabbar

1、navbar

-main.js

import { NavBar } from 'vant';

Vue.use(NavBar);

-layout引入样式

<van-nav-bar title="标题" />

2、tabbar

-main.js

import { Tabbar, TabbarItem } from 'vant';

Vue.use(Tabbar);
Vue.use(TabbarItem);

-layout引入样式

<van-tabbar>
  <van-tabbar-item icon="home-o">首页</van-tabbar-item>
  <van-tabbar-item icon="search">搜索</van-tabbar-item>
</van-tabbar>

 五、设置路由模式

<van-tabbar router>
  <van-tabbar-item to="/layout/home" icon="home-o">首页</van-tabbar-item>
  <van-tabbar-item to="/layout/search" icon="search">搜索</van-tabbar-item>
</van-tabbar>

修改重定向

{ path: '/', redirect:'/layout/home' },

使用meta储存源代码修改标题

{
    path: 'search', meta: {
        title: '搜索'
    }, component: Search
},
<van-nav-bar :title="$route.meta.title" />

六、首页推荐歌单

布局

1、yarn add less less-loader@5.0.0

2、渲染ui页面

import {  Cell, Grid, GridItem, Image } from 'vant'
Vue.use(Cell)
Vue.use(Grid)
Vue.use(Image)
Vue.use(GridItem)

<!-- 推荐歌单 -->
    <van-cell class="title" title="推荐歌单" />
    <van-grid :border="false" :column-num="3">
      <van-grid-item>
        <van-image
        width="111"
        height="100"
        src=""
        />
        <p class="music-name van-multi-ellipsis--l2">
          12312312
        </p>
      </van-grid-item>
    </van-grid>
<style scoped lang="less">
.home-container {
  .title {
    background-color: #c71d24;
    color: #fff;
  }

  .music-name {
    font-size: 12px;
    text-align: left;
    line-height: 20px;
    width: 100%;
    padding: 0 5px;
    box-sizing: border-box;
    height: 37px;
  }

  /deep/.van-grid-item__content {
    padding: 10px 0px;
  }
}
</style>

获取歌单

request.js

import axios from "axios";
const request=axios.create({
    baseURL:'http://localhost:3000'
})

export default request

api/music.js//按需导出

import request from "@/utils/request";
export const recommendMusic=(params)=>{
    return request({
        method:'GET',
        url:'/personalized',
        params
    })
}

Home\index.vue

import { recommendMusic } from "@/api/music";
export default {
  async created() {
    // request({
    //   url: "/personalized",
    // }).then((res) => {
    //   console.log(res.data);
    // });
    // recommendMusic().then(res=>{
    //   console.log(res.data);
    // })
    let res = await recommendMusic({
      limit:6//限制获取的数据条数为6
    });
    console.log(res.data);
  },
};

获取新音乐

main.js引入icon

import { Icon } from 'vant';

Vue.use(Icon);

api/music.js

export const newMusic=(params)=>{
    return request({
        method:'GET',
        url:'/personalized/newsong',
        params,
    })
}

Home\index.vue

import { recommendMusic, newMusic } from "@/api/music";
let res1 = await newMusic();
this.newMusicList = res1.data.result;

遍历渲染

七、搜索


import { Search, Tag, Icon } from 'vant'
Vue.use(Icon)
Vue.use(Tag)
Vue.use(Search) 

<template>
  <div>
    <van-search
      shape="round"
      placeholder="请输入搜索关键词"
    />
    <!-- 热门搜索 -->
    <van-cell title="热门搜索" />
      <div style="padding: 10px 16px;">
        <van-tag color="red" size="large" plain round type="primary">
          123
        </van-tag>
      </div>
  </div>
</template>
<script>
export default {}
</script>

热搜列表

import { Search, Tag } from 'vant'

Vue.use(Tag)
Vue.use(Search) 
<van-cell class="title" title="最佳匹配" />
<van-cell label="12" title="1221">
    <template>
      <van-icon color="#000" name="play-circle-o" size="28" />
    </template>
  </van-cell>

api/search.js

import request from "@/utils/request";

export const hotSearch = (params) => {
    return request({
        method: 'GET',
        url: '/search/hot',
        params
    })
}
import { hotSearch, requestCloud } from "@/api/search";
  async created() {
    let res = await hotSearch();
    this.hotSearchList = res.data.result.hots;
  },

遍历渲染

最佳匹配

api/search.js

export const requestCloud=(params)=>{
    return request({
        method:'GET',
        url:'/cloudsearch',
        params
    })
} 

Search.vue

import { List } from 'vant'
Vue.use(List)
  data() {
    return {
      value: "vueeeeee",
      hotSearchList: [],
      list: [],
      loading: false, // 是否在加载中  n次
      finished: false, // 是否加载完成 1次
      page:0,
    };
  },

改造methods

--将定时器改造

  methods: {
    async onLoad() {
      this.page++;
      // 异步更新数据
      // setTimeout 仅做示例,真实场景中一般为 ajax 请求
      let res = await bestMatch({
        keywords: this.value,
        limit: 20,
        offset: (this.page - 1) * 20,
      });

      if (res.data.result.songs == undefined) {
        this.finished = true;
        this.loading = false;
        return;
      }
      this.list = [...this.list, ...res.data.result.songs];
      console.log(this.list);

      this.loading = false;
    },
  },

封装函数

async getCloudList() {
  return await requestCloud({
    keywords: this.value,
    limit: 20,
    offset: (this.page - 1) * 20,
  });
},

Search/onload函数

let res = await this.getCloudList();

八、点击热歌标签(可复用)

@click="hotTag(item.first)"
    // 点击热歌标签
    async hotTag(val) {
      // 给输入框赋值
      this.value=val
      // 处理小细节
      this.page=1
      this.finished=true
      // 请求数据
      let res= await this.getCloudList()
      // 覆盖之前的数据
      this.list=res.data.result.songs
      // loading=>false
      this.loading=false
    },

热门搜索和最佳匹配交替显示

v-if="list.length==0"
v-else

设置点击事件

    async inputFn() {
      console.log(this.value);
      this.page=1
      this.finished=false
      if(this.value.trim()==''){
        this.list=[]
        return
      }
      let res=await this.getCloudList()
      if(res.data.result.songs==undefined){
        this.list=[]
        return
      }
      this.list = res.data.result.songs;
      this.loading=false
    },

九、防抖

方案一:

inputFn() {
  clearTimeout(this.setTimeId)
  this.setTimeId = setTimeout(() => {
    this.inputFn1();
  }, 500);
},

方案二:lodash

yarn add lodash

import _ from 'lodash' 
  async created() {
    let res = await hotSearch();
    this.hotSearchList = res.data.result.hots;
    this.inputFn=_.debounce(this.inputFn,500)
  },

十、设置layout布局

<van-nav-bar fixed :title="$route.meta.title" />
    <!-- 二级出口 -->
    <div class="mian">
      <router-view></router-view>
    </div>
.mian{
  padding-top: 45px;
}

十一、songItem 设置播放

<SongItem 
v-for="item in list" 
:key="item.id" 
:name="item.name" 
:id='item.id' 
:author='item.ar[0].name'
></SongItem>
<template>
  <div>
    <van-cell :label="author + ' ' + name" :title="name" />
    <div>
      <van-icon @click="playFn" color="#000" name="play-circle-o" size="28" />
    </div>
  </div>
</template>
  methods: {
    playFn() {
        this.$router.push({
            path:'/play',
            query:{
                id:this.id
            }
        })
    },
  },
};

十二、移动适配

yarn add postcss postcss-pxtorem@5.1.1

postcss.config.js

module.exports = {
    plugins: {
      'postcss-pxtorem': {
        // 能够把所有元素的px单位转成Rem
        // rootValue: 转换px的基准值。
        // 例如一个元素宽是75px,则换成rem之后就是2rem。
        rootValue: 37.5,
        propList: ['*']
      }
    }
  }
import '@/mobile/flexible'

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值