其他分享
首页 > 其他分享> > vue+vant音乐播放器(andriod)项目

vue+vant音乐播放器(andriod)项目

作者:互联网

新建项目

在适合的目录下打开终端输入vue create music_player,回车

选择Default([Vue 2] babel,eslint)

等待项目构建完成

项目构建成功

 

安装路由

用vscode打开项目所在文件夹

新建终端输入命令npm install vue-router@3.5.2 --save

在src目录下新建文件夹router,并在其下新建文件index.js

在新建的文件index.js中写入路由模板代码,成为路由配置文件

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = []

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

 在main.js中引入路由配置文件

import Vue from 'vue'
import App from './App.vue'
//引入路由
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

 在App.vue文件中清除多余代码,并写入全局路由组件

<template>
  <div>
    <!-- 全局组件 -->
    <router-view></router-view>
  </div>
</template>

<script>
  export default {
    
  }
</script>

<style scoped>
/* 全局设置样式 */
html,body,#app{
  height: 100%;
}
</style>

 

安装vant组件库

在终端中输入npm install vant@latest-v2 -S

 

在终端中输入npm install qs --save

在src目录下新建文件夹plugins,并在其下新建文件vant.js

并写入代码

import Vue from 'vue'
import Vant, { Locale } from 'vant'
import 'vant/lib/index.css'

Vue.use(Vant)

 

在main.js中引入vant.js

import Vue from 'vue'
import App from './App.vue'
//引入路由
import router from './router'
//引入vant.js文件
import './plugins/vant.js'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

 

安装axios

在终端中输入npm install axios --save

在src目录下新建文件夹http,并新建文件axios.js

并写入代码

import axios from 'axios'

let baseUrl='https://my-run-music-api.vercel.app'
/**
  get方式请求
*/
export function get(addurl, data) {
  return axios({
    method: 'get',
    url:baseUrl+addurl,
    params:data, // get 请求时带的参数
  })
}

export default axios

 

 

配置路由

在src下新建文件夹views,并新建文件Login.vue和Manage.vue

在新建的views目录下新建文件夹Home和Me

在新建的Home目录下新建文件home.vue和about.vue

在Me目录下新建文件me.vue

在src/router/index.js中写入代码

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
  // 路由重定向 用户一次进入程序的时候   进入登录页面
  {
    path:'/',
    redirect:'/login'
    // redirect:'/manage/home'
  },
  // 登录页面的路由
  {
    path:'/login',
    name:'Login',
    component:()=>import('../views/Login.vue')
  },
  // 管理页面的路由
  {
    path:'/manage',
    name:'Manage',
    component:()=>import('../views/Manage.vue'),
    // 配置子路由
    children:[
      // 首页
      {
        path:'home',
        component:()=>import('../views/Home/home.vue')
      },
      // 我的页面
      {
        path:'me',
        component:()=>import('../views/Me/me.vue')
      },
      // 关于页面
      {
        path:'about',
        component:()=>import('../views/Home/about.vue')
      }

    ]
  }
]

const router = new VueRouter({
  // mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

 一些问题的解决方案

在 vue eslint 报错 error “Component name “*****“ should always be multi-word”

在vue.config.js文件中加入代码lintOnSave:false

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave:false
})

 Vue中出现“**** is defined but never used”

在packagejson文件的rules里加入规则"no-unused-vars":"off"

{
  "name": "music_player",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "axios": "^0.27.2",
    "core-js": "^3.8.3",
    "qs": "^6.11.0",
    "vant": "^2.12.48",
    "vue": "^2.6.14",
    "vue-router": "^3.5.2"
  },
  "devDependencies": {
    "@babel/core": "^7.12.16",
    "@babel/eslint-parser": "^7.12.16",
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-eslint": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "eslint": "^7.32.0",
    "eslint-plugin-vue": "^8.0.3",
    "vue-template-compiler": "^2.6.14"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "@babel/eslint-parser"
    },
    "rules": {
      "no-unused-vars": "off"
    }
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

 

编写登录页面

调整页面整体样式

<template>
    <div class="login">

    </div>
</template>

<script>
    export default {
        
    }
</script>

<style scoped>
/* 调整页面样式 */
/* 设置页面的整体样式 */
.login {
  width: 100%;
  height: 100vh;
  /* 调整渐变色 */
  background-image: linear-gradient(#70e1f5, #e5e5be, #e4e5e6);
  overflow: hidden;
}
</style>

好看的渐变色获取网站https://uigradients.com/#Sylvia

App的名称或主题图片

往class="login"的div里添加代码

<div class="login">
    <!-- 登录页面的头部 -->
    <div class="header">
      <!-- App的名称或主题图片 -->
      <div class="title">
        <img src="" alt="" />
        <h1>XX音乐</h1>
      </div>
    </div>
  </div>

 设置头部区域的样式

/* 设置头部区域的样式 */
.header {
  width: 100%;
  /* 声明为绝对定位布局 */
  position: absolute;
  top: 60px;
  text-align: center;
}
.header .title h1 {
  color: #8a8a8a;
  display: inline;
  vertical-align: top;
}
.header .title img {
  width: 45px;
}

 获取矢量图标的网站https://www.iconfont.cn/

 

在src下新建文件夹img,下载所需要的图标

在空出的图片img的src中填入图片路径../img/ttleMusic.png

<template>
  <div class="login">
    <!-- 登录页面的头部 -->
    <div class="header">
      <!-- App的名称或主题图片 -->
      <div class="title">
        <img src="../img/titleMusic.png" alt="图片加载失败" />
        <h1>XX音乐</h1>
      </div>
    </div>
  </div>
</template>

<script>
export default {};
</script>

<style scoped>
/* 调整页面样式 */
/* 设置页面的整体样式 */
.login {
  width: 100%;
  height: 100vh;
  /* 调整渐变色 */
  background-image: linear-gradient(#70e1f5, #e5e5be, #e4e5e6);
  overflow: hidden;
}
/* 设置头部区域的样式 */
.header {
  width: 100%;
  /* 声明为绝对定位布局 */
  position: absolute;
  top: 60px;
  text-align: center;
}
.header .title h1 {
  color: #8a8a8a;
  display: inline;
  vertical-align: top;
}
.header .title img {
  width: 45px;
}
</style>

 大logo

继续在class="login"的div里写入代码

<!--  大logo -->
    <div class="logo">
      <img src="../img/themeMusic.png" alt="图片加载失败" />
      <p>听我想听</p>
    </div>

 设置样式

/* 设置主题中心区域的样式 */
.logo {
  width: 100%;
  /* 声明为绝对定位布局 */
  position: absolute;
  top: 60px;
  text-align: center;
  top: 150px;
  color: #1afa29;
}
.logo p {
  font-size: 30px;
  font-family: "Times New Roman", Times, serif;
}

 登录表单的区域

 <!-- 登录表单的区域 -->
    <div class="loginArea">
      <van-form @submit="onSubmit">
        <van-field
          v-model="username"
          name="用户名"
          label="用户名"
          placeholder="用户名"
          :rules="[{ required: true, message: '请填写用户名' }]"
        />
        <van-field
          v-model="password"
          type="password"
          name="密码"
          label="密码"
          placeholder="密码"
          :rules="[{ required: true, message: '请填写密码' }]"
        />
        <div style="margin: 16px">
          <van-button round block type="info" native-type="submit"
            >提交</van-button
          >
        </div>
      </van-form>
    </div>

 设置样式

/* 设置登录表单区域的样式 */
.loginArea {
  width: 90%;
  /* 通过外边距的形式 */
  margin: 460px auto;
  /* 设置圆角 */
  border-radius: 15px;
}
.loginArea .van-form .van-cell {
  /* 设置圆角 */
  border-radius: 15px;
  /* 设置背景色通明 */
  background-color: rgba(255, 255, 255, 0.2);
  height: 50px;
}
.loginArea .van-form .van-button {
  background-image: linear-gradient(to right, #74ebd5, #acb6e5);
}

 编写js代码

export default {
  data() {
    return {
      // 用户名
      username: "",
      // 密码
      password: "",
    };
  },
  methods: {
    // 登录事件
    onSubmit() {
      // 设置对应的参数
      let userInfo = {
        // 用户名
        username: this.username,
        // 密码
        password: this.password,
      };
      console.log(userInfo);
      sessionStorage.setItem('userInfo',userInfo.username)
      this.$router.push("/manage/home");
    },
  },
};

 路由管理页面

在src/views/Manage.vue文件中写入代码

<template>
  <div class="manage">
    <!-- 声明渲染组件routerView -->
    <router-view></router-view>
    <!-- 创建tabbar结构 -->
    <van-tabbar v-model="active">
      <!-- 首页 -->
      <van-tabbar-item icon="home-o" to="/manage/home">首页</van-tabbar-item>
      <!-- 我的 -->
      <van-tabbar-item icon="friends-o" to="/manage/me">我的</van-tabbar-item>
    </van-tabbar>
  </div>
</template>

<script>
export default {
  data() {
    return {
      active: 0,
    };
  },
};
</script>

<style scoped>
</style>

 

自定义播放器组件

在src/components目录下新建文件MusicPlayer.vue

 

<template>
  <div>
    <div class="music-container" id="music-container">
      <!-- 音乐信息 -->
      <div class="music-info">
        <!-- 音乐标题 -->
        <h4 id="title">{{ songName }}</h4>
        <!-- 音乐播放进度条 -->
        <div class="progress-container" id="progress-container">
          <div class="progress" id="progress"></div>
        </div>
      </div>

      <!-- 默认第一首音乐 -->
      <audio :src="songUrl" id="audio"></audio>

      <!-- 音乐封面 -->
      <div class="img-container">
        <img :src="songImg" alt="加载中" id="music-cover" />
      </div>
      <!-- 播放控制 -->
      <div class="navigation">
        <button id="prev" class="action-btn" @click="prevSong">
          <i class="fas fa-backward"></i>
        </button>
        <button id="play" class="action-btn action-btn-big" @click="playBtn">
          <i class="fas fa-play"></i>
        </button>
        <button id="next" class="action-btn" @click="nextSong">
          <i class="fas fa-forward"></i>
        </button>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    songList: [],
  },
  data() {
    return {
      //songList: [
      //  {
      //    songId: "5257138", //512085302
      //    songName: "屋顶",
      //    songImg:
      //      "https://p1.music.126.net/81BsxxhomJ4aJZYvEbyPkw==/109951165671182684.jpg",
      //    songUrl: "https://music.163.com/song/media/outer/url?id=5257138.mp3",
      //  },
      //],
      songId: "",
      songName: "",
      songImg: "",
      songUrl: "",
      songIndex: 0,
    };
  },
  // 自动调用
  created() {
    this.reload();
  },
  methods: {
    // 更新播放歌曲
    reload() {
      // console.log(this.songIndex + 1 + " in " + this.songList.length+':'+this.songList[this.songIndex].songUrl);

      this.songId = this.songList[this.songIndex].songId;
      this.songImg = this.songList[this.songIndex].songImg;
      this.songName = this.songList[this.songIndex].songName;
      this.songUrl = this.songList[this.songIndex].songUrl;
    },
    // 播放歌曲
    playSong() {
      let audio = this.$el.querySelector("#audio");
      let musicContainer = this.$el.querySelector("#music-container");
      let playBtn = this.$el.querySelector("#play");

      musicContainer.classList.add("play");
      playBtn.querySelector("i.fas").classList.remove("fa-play");
      playBtn.querySelector("i.fas").classList.add("fa-pause");

      audio.play();
    },
    // 播放器按钮
    playBtn() {
      let musicContainer = this.$el.querySelector("#music-container");
      musicContainer.classList.contains("play")
        ? this.pauseSong()
        : this.playSong();
    },

    // 停止播放
    pauseSong() {
      let audio = this.$el.querySelector("#audio");
      let musicContainer = this.$el.querySelector("#music-container");
      let playBtn = this.$el.querySelector("#play");

      musicContainer.classList.remove("play");
      playBtn.querySelector("i.fas").classList.add("fa-play");
      playBtn.querySelector("i.fas").classList.remove("fa-pause");

      audio.pause();
    },

    // 上一首
    prevSong() {
      this.songIndex--;
      if (this.songIndex < 0) {
        this.songIndex = this.songList.length - 1;
      }
      // 加载歌曲信息并播放
      this.reload();
      this.pauseSong();
    },
    // 下一首
    nextSong() {
      this.songIndex++;
      if (this.songIndex > this.songList.length - 1) {
        this.songIndex = 0;
      }
      this.reload();
      this.pauseSong();
      return this.songIndex;
    },
    // 结束
  },
  mounted() {
    const audio = document.getElementById("audio");
    const progress = document.getElementById("progress");
    const progressContainer = document.getElementById("progress-container");

    // 进度条更新
    function updateProgress(e) {
      // 对象解构操作
      const { duration, currentTime } = e.target;
      const progressPercent = (currentTime / duration) * 100;
      // 进度条
      progress.style.width = `${progressPercent}%`;
    }
    // 设置进度条
    function setProgress(e) {
      // progressContainer代理视图宽度
      const width = this.clientWidth;
      // 鼠标点击时处于progressContainer里的水平偏移量
      const clickX = e.offsetX;

      // audio.duration: 音频长度
      const duration = audio.duration;

      // audio.currentTime: 音频播放位置
      audio.currentTime = (clickX / width) * duration;
    }
    // 事件监听

    // 3.播放器进度条相关
    // 3.1 设置播放进度
    progressContainer.onclick = setProgress;
    // 3.2 进度条更新
    audio.ontimeupdate = updateProgress;
  },
};
</script>

<style scoped>
@import "../../public/style.css";
@import "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css";
</style>

 在public目录下新建文件style.css

@import url('https://fonts.googleapis.com/css?family=Lato&display=swap');

.music-container {
    background-image: linear-gradient(#ff6e7f, #bfe9ff);
    border-radius: 15px;
    display: flex;
    position: fixed;
    margin: 0;
    left: 50%;
    transform: translate(-50%,0);
    z-index: 5;
}

.img-container {
    position: relative;
    width: 110px;
}

.img-container::after {
    content: "";
    background-color: #fff;
    border-radius: 50%;
    position: absolute;
    bottom: 100%;
    left: 50%;
    width: 15px;
    height: 15px;
    /* 旋转 */
    transform: translate(-50%, 50%);
}

.img-container img {
    border-radius: 50%;
    height: 110px;
    width: inherit;
    object-fit: cover;
    position: absolute;
    bottom: 0;
    left: 0;
    /* 封面360°旋转,默认不动 */
    animation: rotate 3s linear infinite;
    animation-play-state: paused;
}

/* 定义旋转动画 */
@keyframes rotate {
    from {
        transform: rotate(0);
    }

    to {
        transform: rotate(360deg);
    }
}

.navigation {
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1;
}

.action-btn {
    /* 取消默认样式 */
    border: 0;
    background-color: rgba(247, 247, 247, 0.1);
    /* ----- */
    color:#ff6e7f; 
    font-size: 20px;
    cursor: pointer;
    padding: 10px;
    margin: 0 20px;
}

.action-btn:focus {
    /* 取消默认样式 */
    outline: 0;
}

.action-btn.action-btn-big {
    font-size: 30px;
}

.music-info {
    position: absolute;
    top: 0;
    left: 20px;
    /* 父元素宽度-40px */
    width: calc(100% - 200px);
    background-color: rgba(255, 255, 255, 0.5);
    border-radius: 15px 15px 0 0;
    padding: 10px 10px 10px 150px;
    /* 没播放时默认隐藏 */
    opacity: 0;
    transform: translateY(0%);
    transition: transform 0.3s ease-in, opacity 0.3s ease-in;
    z-index: 0;
}

.music-info h4 {
    /* 取消默认边距 */
    margin: 0;
}

.music-container.play .music-info {
    opacity: 1;
    transform: translateY(-100%);
}


.progress-container {
    background-color: #fff;
    border-radius: 5px;
    cursor: pointer;
    margin: 10px 0;
    height: 4px;
    width: 100%;
}

.progress {
    background-color: #0decfc;
    border-radius: 5px;
    height: 100%;
    /* 一开始进度条长度为0 */
    width: 0%;
    transition: width 0.1s linear;

}

 

编写主页

<template>
  <div class="home">
    <!-- 搜索框 -->
    <van-sticky>
      <div class="search">
        <van-search
          shape="round"
          background="linear-gradient(to right,#ff6e7f, #bfe9ff)"
          placeholder="请输入搜索关键词"
          @click="gotoAboutPage"
        />
      </div>
    </van-sticky>
    <!-- 轮播图 -->
    <div class="swiper">
      <van-swipe
        class="my-swipe"
        :autoplay="1500"
        indicator-color="white"
        :height="200"
      >
        <van-swipe-item v-for="(item, index) in swiperPic" :key="index">
          <img :src="item.pic" alt="无法加载图片" width="100%" :v-lazy="item.pic" />
        </van-swipe-item>
      </van-swipe>
    </div>
    <!-- 歌单宫格 -->
    <div class="songGrid">
      <van-grid :border="true" :column-num="5" square>
        <van-grid-item v-for="(item, index) in songGrid" :key="index">
          <van-image
            :src="item.iconUrl"
            style="
              width: 30px;
              background-image: linear-gradient(#ed4264, #ffedbc);
              border-radius: 50px;
            "
          />
          <div style="font-size: 10px; height: 0px">{{ item.name }}</div>
        </van-grid-item>
      </van-grid>
    </div>
    <!-- 歌单 -->
    <div class="songList">
      <van-swipe-cell class="goodList" v-if="show">
        <div class="text">推荐歌曲</div>
        <van-card
          v-for="(item, index) in songList"
          :key="index"
          :title="item.songName"
          :v-lazy="item.songImg"
          :thumb="item.songImg"
          class="goods-card"
          @click="playSong(index)"
        />
      </van-swipe-cell>
      <!-- 未加载 -->
      <div class="noLoad" v-else>
        <van-empty image="network" description="网络错误" />
      </div>
      <div class="space">
        <van-card style="background-color: rgba(247, 247, 247, 0)" />
      </div>
      <div class="space">
        <van-card style="background-color: rgba(247, 247, 247, 0)" />
      </div>
    </div>
    <!-- 音频播放器 -->
    <div class="musicArea">
      <MusicPlayer
        :songList="songList"
        v-if="show"
        ref="playSong"
        class="music-player"
      ></MusicPlayer>
    </div>
  </div>
</template>

<script>
import MusicPlayer from "../../components/MusicPlayer.vue";
import { get } from "../../http/axios";
export default {
  data() {
    return {
      // 轮播图
      swiperPic: [],
      // 宫格
      songGrid: [],
      // 歌曲列表
      songList: [],
      show: false,
    };
  },
  components: { MusicPlayer },
  created() {
    this.getSongListData();
    this.getSwiperData();
    this.getSongGridData();
    this.addSong();
  },
  methods: {
    addSong() {
      // 获取到路由传参传递过来的activeKey 给data中的对应的变量进行赋值
      // console.log(this.$route.query.songId);
      if (this.$route.query.songId)
        this.songList.push({
          songId: this.$route.query.songId,
          songName: this.$route.query.songName,
          songImg: this.$route.query.songImg,
          songUrl: this.$route.query.songUrl,
        });
    },
    // 点击事件播放歌曲
    playSong(index) {
      // console.log(index);
      for (; this.$refs.playSong.nextSong() != index; ) {}
    },
    // 获取歌曲列表数据
    async getSongListData() {
      // 发送网络请求
      let res = await get("/personalized/newsong");
      // console.log(res.data.result);
      // 向data中的变量进行赋值
      for (let index in res.data.result) {
        if (index < 10)
          this.songList.push({
            songId: res.data.result[index].id,
            songName: res.data.result[index].name,
            songImg: res.data.result[index].picUrl,
            songUrl:
              "https://music.163.com/song/media/outer/url?id=" +
              res.data.result[index].id +
              ".mp3",
          });
      }
      this.show = true;
    },
    // 获取轮播图数据
    async getSwiperData() {
      // 1.发送网络请求 获取对应的数据
      let res = await get("/homepage/block/page");
      this.swiperPic = res.data.data.blocks[0].extInfo.banners;
    },
    // 获取宫格数据
    async getSongGridData() {
      // 发送网络请求获取对应的数据
      let res = await get("/homepage/dragon/ball");
      // console.log(res.data.data);
      // 向data中的变量进行赋值
      this.songGrid = res.data.data;
    },
    // 点击搜索框跳转到关于页面
    gotoAboutPage() {
      this.$router.push("/manage/about");
    },
    /**
     *
     */
  },
};
</script>

<style scoped>
/* 整体样式 */
.home {
  background-image: linear-gradient(to right, #ff6e7f, #bfe9ff);
}
/* 分区样式 */
.swiper,
.songList,
.songGrid {
  margin: 15px;
}
.my-swipe,
.songList .goodList {
  border-radius: 15px;
}
/* 轮播图样式 */
.my-swipe {
  height: 120px;
}
.my-swipe .van-swipe-item {
  color: #fff;
  font-size: 20px;
  line-height: 150px;
  text-align: center;
  background-color: #39a9ed;
}
/* 歌单宫格样式 */
.songGrid {
  /* height: 110px; */
  padding: 5px;
  background-color: rgba(247, 247, 247, 0.4);
  border-radius: 15px;
}
.songGrid /deep/ .van-grid-item__content {
  background-color: rgba(255, 255, 255, 0);
}
/* 歌单样式 */
.songList .goodList .goods-card,
.songList .text {
  margin: 0;
  padding: 10px;
  background-color: rgba(247, 247, 247, 0.4);
}
.songList .goodList .text {
  font-size: 30px;
  font-family: Cambria, Cochin, Georgia, Times, "Times New Roman", serif;
}
.songList .goodList .goods-card .van-card__header {
  height: 60px;
}
.songList .goodList .goods-card .van-card__title {
  font-size: 20px;
  height: 30px;
}
.songList .goodList .goods-card .van-card__thumb {
  width: 60px;
  height: 60px;
}
.songList .goodList .goods-card .delete-button {
  height: 100%;
}
/* 音乐播放器 */
.musicArea {
  width: 100%;
  height: 100px;
  position: fixed;
  bottom: 0px;
}
</style>

 

编写我的页面

<template>
  <div class="mine">
    <!-- 顶部的背景 -->
    <div class="bg"></div>
    <!-- 顶部用户信息 -->
    <div class="userInfo">
      <!-- 用户头像 -->
      <div class="userFace">
        <img src="../../img/head.jpg" alt="" />
      </div>
      <!-- 用户名 -->
      <div class="userName">
        {{ userInfo.username }}
      </div>
    </div>
    <!-- 操作列表 指示列表 -->
    <div class="cellArea">
      <!-- title 标题 icon-是左侧图标 name-右侧图标 -->
      <van-cell title="设置" icon="setting-o">
        <!-- 使用 right-icon 插槽来自定义右侧图标 -->
        <template #right-icon>
          <van-icon name="arrow" class="search-icon" />
        </template>
      </van-cell>
      <van-cell title="联系我们" icon="service-o">
        <!-- 使用 right-icon 插槽来自定义右侧图标 -->
        <template #right-icon>
          <van-icon name="arrow" class="search-icon" />
        </template>
      </van-cell>
      <van-cell title="关于我们" icon="service-o">
        <!-- 使用 right-icon 插槽来自定义右侧图标 -->
        <template #right-icon>
          <van-icon name="arrow" class="search-icon" />
        </template>
      </van-cell>
    </div>
    <!-- 退出按钮 -->
    <div class="logoutBtn" @click="logoutHandler">退出登录</div>
  </div>
</template>

<script>
import { Dialog } from "vant";
export default {
  data() {
    return {
      // 用户信息
      userInfo:{
          username:"马保国"
      }
    };
  },
  created() {
      this.getUserInfo()
  },
  methods: {
      getUserInfo(){
        this.userInfo.username=sessionStorage.getItem('userInfo') 
      },
    // 退出登录
    logoutHandler() {
      // 做一个提示
      Dialog.confirm({
        message: "是否确认退出登录?",
        theme: "round-button",
      })
        .then(() => {
          // 点击确认按钮 执行退出登录
          // 清除掉本地保存的token  执行退出的网络操作
        //   delToken();
          // 跳转回到登录页面
          this.$router.push("/login");
        })
        .catch(() => {
          // on cancel
        });
    },
  },
};
</script>

<style scoped>
/* 设置顶部的背景样式 */
.mine .bg {
  /* 设置渐变色 */
  background-image: linear-gradient(to right, #ff6e7f, #bfe9ff);
  height: 200px;
  /* 设置底部左右两侧的弧度为一个圆形 */
  border-bottom-left-radius: 50%;
  border-bottom-right-radius: 50%;
}
/* 用户区域样式 */
.mine .userInfo {
  background-color: #fff;
  width: 80%;
  height: 160px;
  /* 开启绝对定位 */
  position: absolute;
  top: 100px;
  left: 50%;
  margin-left: -40%;
  /* 透明度 */
  opacity: 0.8;
  /* 阴影 */
  box-shadow: 0 0 10px #ccc;
  border-radius: 10px;
}
/* 用户区域头像样式 */
.userInfo .userFace {
  width: 100px;
  height: 100px;
  /* 要设置一个元素为圆形 */
  border-radius: 50%;
  /* margin: 0 auto; */
  position: absolute;
  left: 50%;
  /* 形变 平移 */
  transform: translate(-50%, -50%);
}
/* 用户区域头像的图片样式 */
.userInfo .userFace img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
}
/* 用户名的样式 */
.userInfo .userName {
  /* background-color: green; */
  text-align: center;
  margin-top: 70px;
  font-size: 28px;
}
/* 设置操作列表区域的样式 */
.mine .cellArea {
  margin: 120px auto;
  width: 95%;
  box-shadow: 4px 4px 4px 0 rgba(248, 123, 140, 0.3);
  border-radius: 10px;
}
/* van-cell的样式 */
.search-icon {
  font-size: 16px;
  line-height: inherit;
}
/* 退出按钮的样式 */
.logoutBtn {
  width: 50%;
  /* 设置渐变色 */
  background-image: linear-gradient(to right, #ff6e7f, #bfe9ff);
  text-align: center;
  color: #fff;
  /* 设置行高 */
  line-height: 35px;
  border-radius: 20px;
  margin: 0 auto;
  cursor: pointer;
}
</style>

编写搜索页面

<template>
  <div class="about">
    <!-- 搜索框 -->
    <van-sticky>
      <div class="search">
        <van-search
          shape="round"
          background="linear-gradient(to right,#ff6e7f, #bfe9ff)"
          v-model="value"
          clearable
          placeholder="请输入搜索关键词"
          @input="getSearchData"
        >
          <template #left-icon>
            <van-icon name="arrow-left" @click="onCancel"/>
          </template>
        </van-search>
      </div>
    </van-sticky>

    <!-- 歌单 -->
    <div class="songList">
      <!-- 已输入 -->
      <div class="input" v-if="showList">
        <van-swipe-cell class="goodList">
          <div class="text">单曲</div>
          <van-card
            v-for="(item, index) in songList"
            :key="index"
            :title="item.songName"
            :desc="item.songDesc"
            class="goods-card"
            @click="playSong(index)"
          />
        </van-swipe-cell>
      </div>
      <!-- 未输入 -->
      <div class="noInput" v-else>
        <van-empty image="search" />
      </div>
      <div class="space">
        <van-card style="background-color: rgba(247, 247, 247, 0)" />
      </div>
    </div>
  </div>
</template>

<script>
import { get } from "../../http/axios";
export default {
  data() {
    return {
      value: "",
      songList: [],
      showList: false,
    };
  },
  methods: {
    // 取消并返回
    onCancel() {
      this.$router.go(-1);
    },
    // 通过搜索获取歌曲
    async getSearchData() {
      this.songList = [];
      this.showList = false;
      let data = {
        keywords: this.value,
      };
      let res = await get("/search", data);
      this.songList = [];
      for (let index in res.data.result.songs) {
        this.getSongDetailById(res.data.result.songs[index].id);
      }
      // });
    },
    // 通过歌曲id获取歌曲详情
    async getSongDetailById(Id) {
      let data = {
        ids: Id,
      };
      let res = await get("/song/detail", data);
      this.songList.push({
        songId: res.data.songs[0].id,
        songName: res.data.songs[0].name,
        songDesc: res.data.songs[0].ar[0].name,
        songImg: res.data.songs[0].al.picUrl,
        songUrl:
          "https://music.163.com/song/media/outer/url?id=" +
          res.data.songs[0].id +
          ".mp3",
      });
      this.showList = true;
      // });
    },
    // 播放歌曲并跳转
    playSong(index) {
      // 跳转页面 并 传参
      this.$router.push({
        // 页面的路径
        path: "/manage/home",
        // 传递的参数
        query: {
          songId: this.songList[index].songId,
          songName: this.songList[index].songName,
          songImg: this.songList[index].songImg,
          songUrl: this.songList[index].songUrl,
        },
      });
    },
  },
};
</script>

<style scoped>
/* 整体样式 */
.about {
  background-image: linear-gradient(to right, #ff6e7f, #bfe9ff);
}
/* 歌单样式 */
.songList {
  margin: 15px;
}
.songList .goodList {
  border-radius: 15px;
}
.songList .goodList .goods-card,
.songList .text {
  margin: 0;
  padding: 10px;
  background-color: rgba(247, 247, 247, 0.4);
}
.songList .goodList .text {
  font-size: 30px;
  font-family: Cambria, Cochin, Georgia, Times, "Times New Roman", serif;
}
.songList .goodList .goods-card .van-card__header {
  height: 60px;
}
.songList .goodList .goods-card .van-card__title {
  padding: 2px 0;
  font-size: 20px;
  height: 30px;
}
.songList .goodList .goods-card .delete-button {
  height: 100%;
}
/* 未输入 */
.songList .noInput .van-empty {
  height: 650px;
}
</style>

 

标签:vue,vant,height,width,andriod,import,data,songList
来源: https://www.cnblogs.com/linlinmailbox/p/16471454.html