├── public ├── favicon.ico └── index.html ├── src ├── assets │ ├── cry.png │ ├── logo.png │ └── img │ │ ├── latest.png │ │ ├── ranking.png │ │ ├── singer.png │ │ ├── recommend.png │ │ ├── songMenu.png │ │ ├── singerDetail.png │ │ └── songMenuDetail.png ├── css │ ├── theme │ │ └── fonts │ │ │ ├── element-icons.ttf │ │ │ └── element-icons.woff │ └── common.css ├── App.vue ├── main.js ├── axios │ └── axios.js ├── components │ ├── songOutline │ │ ├── singerOutline.vue │ │ ├── highOutline.vue │ │ ├── musicOutline.vue │ │ ├── albumOutline.vue │ │ └── songOutline.vue │ ├── commentsTable │ │ └── commentsTable.vue │ ├── songTable │ │ ├── songmenu.vue │ │ ├── song.vue │ │ ├── songs.vue │ │ └── songTable.vue │ ├── lyric │ │ ├── lyric.vue │ │ └── playlist │ │ │ ├── lyrics.vue │ │ │ └── playlist.vue │ ├── Login │ │ └── phoneLogin.vue │ ├── musicPlayer │ │ └── musicPlayer.vue │ └── register │ │ └── register.vue ├── views │ ├── songMenu │ │ ├── highquality │ │ │ └── highquality.vue │ │ ├── songMenu.vue │ │ └── detail │ │ │ └── detail.vue │ ├── ranking │ │ └── ranking.vue │ ├── search │ │ └── search.vue │ ├── latest │ │ └── latest.vue │ ├── recommend │ │ └── recommend.vue │ ├── singer │ │ ├── singer.vue │ │ └── singerInformation │ │ │ └── singerInformation.vue │ ├── mv │ │ ├── videos.vue │ │ └── mv.vue │ ├── album │ │ └── album.vue │ ├── myMusic │ │ └── myMusic.vue │ └── index.vue ├── elementUi │ └── element.js ├── router │ └── index.js └── store │ └── index.js ├── .editorconfig ├── babel.config.js ├── .gitignore ├── SECURITY.md ├── package.json └── README.md /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhysah/xhymusic/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/cry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhysah/xhymusic/HEAD/src/assets/cry.png -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhysah/xhymusic/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/img/latest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhysah/xhymusic/HEAD/src/assets/img/latest.png -------------------------------------------------------------------------------- /src/assets/img/ranking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhysah/xhymusic/HEAD/src/assets/img/ranking.png -------------------------------------------------------------------------------- /src/assets/img/singer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhysah/xhymusic/HEAD/src/assets/img/singer.png -------------------------------------------------------------------------------- /src/assets/img/recommend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhysah/xhymusic/HEAD/src/assets/img/recommend.png -------------------------------------------------------------------------------- /src/assets/img/songMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhysah/xhymusic/HEAD/src/assets/img/songMenu.png -------------------------------------------------------------------------------- /src/assets/img/singerDetail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhysah/xhymusic/HEAD/src/assets/img/singerDetail.png -------------------------------------------------------------------------------- /src/assets/img/songMenuDetail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhysah/xhymusic/HEAD/src/assets/img/songMenuDetail.png -------------------------------------------------------------------------------- /src/css/theme/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhysah/xhymusic/HEAD/src/css/theme/fonts/element-icons.ttf -------------------------------------------------------------------------------- /src/css/theme/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhysah/xhymusic/HEAD/src/css/theme/fonts/element-icons.woff -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ], 5 | plugins: [ 6 | [ 7 | 'component', 8 | { 9 | libraryName: 'element-ui', 10 | styleLibraryName: 'theme-chalk' 11 | } 12 | ] 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | import axios from 'axios' 6 | import './elementUi/element' 7 | import './css/common.css' 8 | import './axios/axios' 9 | Vue.prototype.$http = axios 10 | Vue.config.productionTip = false 11 | 12 | new Vue({ 13 | router, 14 | store, 15 | render: h => h(App) 16 | }).$mount('#app') 17 | -------------------------------------------------------------------------------- /src/axios/axios.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | axios.defaults.baseURL = 'http://localhost:3000' 4 | axios.defaults.withCredentials = true// 跨域请求 5 | // axios.interceptors.request.use(config => { 6 | // // const token = window.localStorage.getItem('token') 7 | // // return config 8 | // }) 9 | axios.interceptors.response.use(config => { 10 | if (config.status === 200) { 11 | return config.data 12 | } else { 13 | return Promise.reject(config) 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /src/css/common.css: -------------------------------------------------------------------------------- 1 | body{ 2 | margin: 0; 3 | padding: 0; 4 | width: 100%; 5 | height: 100%; 6 | background-color: black; 7 | color: white; 8 | min-height: 660px; 9 | min-width: 1200px; 10 | } 11 | .line{ 12 | border: 1px solid #ff0000 13 | } 14 | img{ 15 | width:100%; 16 | height:100%; 17 | cursor: pointer; 18 | } 19 | .flex{ 20 | display: flex; 21 | justify-content: space-between; 22 | flex-wrap: wrap; 23 | } 24 | li{ 25 | list-style: none; 26 | margin: 3px 0; 27 | } 28 | audio{ 29 | width: 100% 30 | } 31 | .simLine{ 32 | border: .5px solid #888888 33 | } 34 | .grid-5{ 35 | display: grid; 36 | grid-template-columns: 20% 20% 20% 20% 20%; 37 | justify-items: center; 38 | } 39 | .grid-4{ 40 | display: grid; 41 | grid-template-columns: 25% 25% 25% 25%; 42 | justify-items: center; 43 | } 44 | .grid-2{ 45 | display: grid; 46 | grid-template-columns: 50% 50%; 47 | justify-items: center; 48 | } 49 | .grid-3{ 50 | display: grid; 51 | grid-template-columns: 33.3% 33.3% 33.3%; 52 | justify-items: center; 53 | } 54 | .el-main{ 55 | padding: 10px; 56 | } 57 | -------------------------------------------------------------------------------- /src/components/songOutline /singerOutline.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 37 | 38 | 58 | -------------------------------------------------------------------------------- /src/views/songMenu/highquality/highquality.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 44 | 45 | 49 | -------------------------------------------------------------------------------- /src/elementUi/element.js: -------------------------------------------------------------------------------- 1 | import '../css/theme/index.css' 2 | import Vue from 'vue' 3 | import { 4 | Form, 5 | FormItem, 6 | Input, 7 | Card, 8 | Button, 9 | Row, 10 | Message, 11 | Carousel, 12 | CarouselItem, 13 | Link, 14 | Image, 15 | Pagination, 16 | Menu, 17 | MenuItem, 18 | Container, 19 | Aside, 20 | Main, 21 | Table, 22 | TableColumn, 23 | Dialog, 24 | Col, 25 | Divider, 26 | Tabs, 27 | TabPane, 28 | Popover, 29 | Progress, 30 | Collapse, 31 | CollapseItem, 32 | MessageBox, 33 | Loading, 34 | Header 35 | } from 'element-ui' 36 | 37 | Vue.use(Loading.directive) 38 | Vue.use(Form) 39 | Vue.use(FormItem) 40 | Vue.use(Input) 41 | Vue.use(Card) 42 | Vue.use(Button) 43 | Vue.use(Row) 44 | Vue.use(Carousel) 45 | Vue.use(CarouselItem) 46 | Vue.use(Link) 47 | Vue.use(Image) 48 | Vue.use(Pagination) 49 | Vue.use(Menu) 50 | Vue.use(MenuItem) 51 | Vue.use(Container) 52 | Vue.use(Aside) 53 | Vue.use(Main) 54 | Vue.use(Table) 55 | Vue.use(TableColumn) 56 | Vue.use(Dialog) 57 | Vue.use(Col) 58 | Vue.use(Divider) 59 | Vue.use(Tabs) 60 | Vue.use(TabPane) 61 | Vue.use(Popover) 62 | Vue.use(Progress) 63 | Vue.use(Collapse) 64 | Vue.use(CollapseItem) 65 | Vue.use(Header) 66 | Vue.prototype.$confirm = MessageBox.confirm 67 | Vue.prototype.$message = Message 68 | Vue.prototype.$loading = Loading.service 69 | -------------------------------------------------------------------------------- /src/components/songOutline /highOutline.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 32 | 33 | 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xhymusic", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.19.2", 12 | "core-js": "^3.6.4", 13 | "element-ui": "^2.13.1", 14 | "vue": "^2.6.11", 15 | "vue-router": "^3.0.7", 16 | "vuex": "^3.1.3" 17 | }, 18 | "devDependencies": { 19 | "@vue/cli-plugin-babel": "~4.3.0", 20 | "@vue/cli-plugin-eslint": "~4.3.0", 21 | "@vue/cli-plugin-router": "~4.3.0", 22 | "@vue/cli-plugin-vuex": "~4.3.0", 23 | "@vue/cli-service": "~4.3.0", 24 | "@vue/eslint-config-standard": "^5.1.2", 25 | "babel-eslint": "^10.1.0", 26 | "babel-plugin-component": "^1.1.1", 27 | "eslint": "^6.7.2", 28 | "eslint-plugin-import": "^2.20.2", 29 | "eslint-plugin-node": "^11.1.0", 30 | "eslint-plugin-promise": "^4.2.1", 31 | "eslint-plugin-standard": "^4.0.0", 32 | "eslint-plugin-vue": "^6.2.2", 33 | "stylus": "^0.54.7", 34 | "stylus-loader": "^3.0.2", 35 | "vue-template-compiler": "^2.6.11" 36 | }, 37 | "eslintConfig": { 38 | "root": true, 39 | "env": { 40 | "node": true 41 | }, 42 | "extends": [ 43 | "plugin:vue/essential", 44 | "@vue/standard" 45 | ], 46 | "parserOptions": { 47 | "parser": "babel-eslint" 48 | }, 49 | "rules": {} 50 | }, 51 | "browserslist": [ 52 | "> 1%", 53 | "last 2 versions", 54 | "not dead" 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /src/components/commentsTable/commentsTable.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 40 | 41 | 70 | -------------------------------------------------------------------------------- /src/components/songTable/songmenu.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 42 | 43 | 74 | -------------------------------------------------------------------------------- /src/components/songOutline /musicOutline.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 43 | 44 | 76 | -------------------------------------------------------------------------------- /src/components/songOutline /albumOutline.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 56 | 57 | 87 | -------------------------------------------------------------------------------- /src/components/lyric/lyric.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 62 | 63 | 79 | -------------------------------------------------------------------------------- /src/components/lyric/playlist/lyrics.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 76 | 77 | 87 | -------------------------------------------------------------------------------- /src/components/songOutline /songOutline.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 55 | 56 | 96 | -------------------------------------------------------------------------------- /src/components/lyric/playlist/playlist.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 74 | 75 | 102 | -------------------------------------------------------------------------------- /src/views/ranking/ranking.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 103 | 104 | 106 | -------------------------------------------------------------------------------- /src/components/songTable/song.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 75 | 76 | 108 | -------------------------------------------------------------------------------- /src/components/Login/phoneLogin.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 78 | 79 | 100 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | const index = () => import('../views/index') 4 | const recommend = () => import('../views/recommend/recommend') 5 | const ranking = () => import('../views/ranking/ranking') 6 | const songMenu = () => import('../views/songMenu/songMenu') 7 | const singer = () => import('../views/singer/singer') 8 | const detail = () => import('../views/songMenu/detail/detail') 9 | const singerInformation = () => import('../views/singer/singerInformation/singerInformation') 10 | const search = () => import('../views/search/search') 11 | const album = () => import('../views/album/album') 12 | const mv = () => import('../views/mv/mv') 13 | const videos = () => import('../views/mv/videos') 14 | const latest = () => import('../views/latest/latest') 15 | const highQuality = () => import('../views/songMenu/highquality/highquality') 16 | const myMusic = () => import('../views/myMusic/myMusic') 17 | 18 | Vue.use(VueRouter) 19 | 20 | const routes = [ 21 | { 22 | path: '/', 23 | component: index, 24 | children: [ 25 | { 26 | path: '/', 27 | redirect: '/recommend' 28 | }, 29 | { 30 | path: '/recommend', 31 | name: 'recommend', 32 | component: recommend 33 | }, 34 | { 35 | path: '/ranking', 36 | name: 'ranking', 37 | component: ranking 38 | }, 39 | { 40 | path: '/songMenu', 41 | name: 'songMenu', 42 | component: songMenu 43 | }, 44 | { 45 | path: '/singer', 46 | name: 'singer', 47 | component: singer 48 | }, 49 | { 50 | path: '/search', 51 | name: 'search', 52 | component: search 53 | }, 54 | { 55 | path: '/artist/:sid', 56 | name: 'singerInformation', 57 | component: singerInformation 58 | }, 59 | { 60 | path: '/songMenuDetail', 61 | name: 'songMenuDetail', 62 | component: detail 63 | }, 64 | { 65 | path: '/album', 66 | name: 'album', 67 | component: album 68 | }, 69 | { 70 | path: '/latest', 71 | name: 'latest', 72 | component: latest 73 | }, 74 | { 75 | path: '/highQuality', 76 | name: 'highQuality', 77 | component: highQuality 78 | }, 79 | { 80 | path: '/myMusic', 81 | name: 'myMusic', 82 | component: myMusic 83 | } 84 | ] 85 | }, 86 | { 87 | path: '/mv', 88 | name: 'mv', 89 | component: mv 90 | }, 91 | { 92 | path: '/videos', 93 | name: 'videos', 94 | component: videos 95 | } 96 | ] 97 | 98 | const router = new VueRouter({ 99 | mode: 'history', 100 | base: process.env.BASE_URL, 101 | routes 102 | }) 103 | // router.afterEach((to, from) => { 104 | // console.log(to.name) 105 | // console.log(Vue.$store.state.active) 106 | // this.$store.commit('editActiveName', to.name) 107 | // }) 108 | // router.beforeEach((to, from, next) => { 109 | // if (window.localStorage.getItem('token')) { 110 | // store.commit('getLoginIf', true) 111 | // next() 112 | // } else { 113 | // store.commit('getLoginIf', false) 114 | // next() 115 | // } 116 | // }) 117 | export default router 118 | -------------------------------------------------------------------------------- /src/views/search/search.vue: -------------------------------------------------------------------------------- 1 | 74 | 75 | 166 | 167 | 184 | -------------------------------------------------------------------------------- /src/views/latest/latest.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 142 | 143 | 200 | -------------------------------------------------------------------------------- /src/views/recommend/recommend.vue: -------------------------------------------------------------------------------- 1 | 76 | 77 | 187 | 188 | 204 | -------------------------------------------------------------------------------- /src/components/songTable/songs.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 149 | 150 | 207 | -------------------------------------------------------------------------------- /src/components/songTable/songTable.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 159 | 160 | 216 | -------------------------------------------------------------------------------- /src/components/musicPlayer/musicPlayer.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 178 | 179 | 225 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 模仿网易云音乐pc端 2 | ## 项目搭建 3 | - ### 基本项目 4 | **安装脚手架**:npm install -g @vue/cli 5 | **创建一个新项目**: vue create my-project(自己想取的项目名称) 6 | 1.Please pick a preset?(选择手动的,可以自己想要的配置)-------manully 7 | 2.Check the features needed for your project(询问项目需求):我选择的如下图 8 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200516185345802.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoeXh4aHducw==,size_16,color_FFFFFF,t_70) 9 | 2. Use history mode for router(路由模式是否使用history)? -------yes 10 | 3. Pick a CSS pre-processor(询问项目的css预处理器):--------Stylus 11 | 4. Pick a linter / formatter config(询问项目的格式校验方式):------Standard 12 | 5. Pick additional lint features:(询问项目是什么时候校验格式)------lint on save(保存时就校验,哈哈哈哈,因为我不知道怎么写代码是规范的,需要他实时约束我) 13 | 6. Where do you prefer placing config for Babel, ESLint, etc.?(询问项目的配置文件放在那里)-----In dedicated config files 14 | 7. Save this as a preset for future projects? (是否保存该配置,若是,你以后创建新项目的时候,就会看见这个配置)----no 15 | 然后vue-cli就开始自己下载了,等待他 16 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200516185345739.png) 17 | - ### 引入项目中使用的东西------axios,element-Ul 18 | **1.axios** 19 | 下载npm install axios --save,运行时也会使用,所有要保存在你的运行时依赖中 20 | 在src/main.js中:导入import axios from ‘axios’, 21 | 挂载到vue原型上Vue.prototype.$http = axios----使用的时候,就可以this.$http 22 | 全局配置axios.defaults.baseURL = 'http://192.168.1.5:3000' 23 | axios.defaults.withCredentials = true 表示跨域请求时是否需要使用凭证 24 | **2.element-UI** 25 | 下载npm i element-ui -save 26 | 我是在src下面建了一个elementUI文件夹,再建了一个element.js文件 27 | 在这个文件中,按需引入elementUI 28 | ```javascript 29 | import Vue from 'vue' 30 | import { 31 | Form, 32 | FormItem 33 | }from 'element-ui'; 34 | Vue.use(Form) 35 | Vue.use(FormItem) 36 | ``` 37 | 再在main.js中引入import './elementUi/element' 38 | 最后删掉views,components里面原本存在的vue文件,连同src/router/index.js里的路由一起删掉----然后做完这些,我就开始研究文档了,一开始真的好难上手 39 | [网易云github地址](https://github.com/Binaryify/NeteaseCloudMusicApi). 40 | 下载后 node app.js 就可以了 41 | ## 遇到的问题 42 | - ### 播放音乐 43 | 最开始的时候,我知道肯定会用audio标签,建立了一个musicPlayer组件,然后把它固定在浏览器底部,因为有好几个页面都有音乐播放,所以我只能把音乐数据放在vuex里面统一管理,传给vuex的值都是可用数据了,每次只能播放一首歌,播放完后,就直接停止了,我应该在他的ended事件里面做些什么。逻辑是这样的 44 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200516185345847.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoeXh4aHducw==,size_16,color_FFFFFF,t_70) 45 | 大概吧,我真的不知道怎么表述了,反正数据,我都存在vuex里面了, 46 | 总结: 47 | - 1.在actions里面可以调用mutation--------context.commit('事件类型','参数'),网络请求等异步操作,放在actions里面------------组件调用this.$store.dispatch('事件类型', '参数') 48 | - 2.mutations------组件调用this$store.commit('事件类型','参数')--vuex的store状态的更新唯一方式,注意不能在actions里直接修改state里的值,改是可以改的,不提倡,容易出问题 49 | - ### 路由跳转 50 | 问题:elementui中的导航菜单,自带的:default-active="activeIndex",他只有点击才有对应的效果,你要是选择了第二项,然后刷新,他就会自动跳到第一个上面,整个导航菜单就会乱掉 51 | 52 | - 我把首页里的activeName值保存在vuex中,同时也从vuex中取值,每次跳转时,都会在生命周期created里面提交修改activeName的值,路由就不会乱掉了 53 | - ### flex布局 54 | 在项目中,我经常遇到布局问题,因为好多图片,都要居中对齐,看起来整洁一点,总结一下经常用的 55 | - 容器的justify-content属性,属性值space-between两端项目之间的距离都相等,center居中对齐 56 | - 容器的flex-wrap----定义一行排不下item,如何换行----wrap换行 57 | - 容器的align-items--定义在交叉轴上如何对齐,可以用来垂直居中块级元素 58 | - 容器属性 59 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200516200935636.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoeXh4aHducw==,size_16,color_FFFFFF,t_70) 60 | - 项目属性 61 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200516200935595.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoeXh4aHducw==,size_16,color_FFFFFF,t_70) 62 | - ### 定位 63 | - relative:相对定位,不脱离文档流,参考自身的静态位置 64 | - absolute:绝对定位,参考最近一个不为static的父级元素的位置 65 | - fixed:固定定位,参照对象为可视窗口 66 | - static :默认,按照正常流进行排列 67 | - inherit:继承父属性的position值 68 | - ### 修饰符sync 69 | 在我使用elementUI时,我发现经常有数据,会加上这个修饰符.sync,一直不明白是什么意思 70 | 71 | - 其实sync是一个语法糖,是什么语法糖呢? 72 | - 在子组件中不能修改父组件中的值,要想修改父组件中的值,必须向父组件发射一个方法this.$emit('方法名',‘修改的的值);,然后父组件接收这个方法@方法名=‘处理数据操作’ 73 | - 如果使用.sync,就不用上面操作了,在子组件中修改的值,父组件也会同步变化 74 | - ### sessionStorage 75 | 存储的数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁.只能存储字符串类型,如果存储的数据类型不是字符串类型,存储时,会自动调用toString方法,存入一个对象数据,会变成 [object Object]字符串 76 | 数据存储不正确,获取的sessionStorage数据也就不对了 77 | - 1.存储时:JSON.stringify()方法转换成字符串,再存储到sessionStorage中 78 | - 2.使用时:通过JSON.parse()方法将字符串转换成JSON格式即可 79 | - ### v-model原理 80 | 本质上是一个语法糖,通过@input事件+v-bind指令实现数据的双向绑定 81 | == 82 | - ### 使单行文字超过一定长度显示... 83 | - 1.规定元素的宽度 84 | width: 200px; 85 | - 2.定义超过元素宽度的文字隐藏 86 | overflow: hidden 87 | - 3.规定当文本溢出时包含元素时发生的事情------ellipsis(显示省略符号来代表被修剪的文本) 88 | text-overflow: ellipsis 89 | - 4.规定元素不换行 90 | white-space: nowrap 91 | - ### 多行文字显示... 92 | - 1.规定元素的宽度 93 | width: 200px; 94 | - 2.定义超过元素宽度的文字隐藏 95 | overflow: hidden 96 | - 3.设置盒子样式 97 | display: -webkit-box 98 | - 4.设置盒子参考方式 99 | -webkit-box-orient: vertical 100 | - 5.设置超出多少行显示省略号 101 | -webkit-line-clamp 2 102 | ## 项目演示:[地址](https://www.bilibili.com/video/BV1ci4y1x7YV) 103 | ## 项目截图 104 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200606174625811.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoeXh4aHducw==,size_16,color_FFFFFF,t_70) 105 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200606174625768.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoeXh4aHducw==,size_16,color_FFFFFF,t_70) 106 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200606174625788.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoeXh4aHducw==,size_16,color_FFFFFF,t_70) 107 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200606174625781.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoeXh4aHducw==,size_16,color_FFFFFF,t_70) 108 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200606174625671.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoeXh4aHducw==,size_16,color_FFFFFF,t_70) 109 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200606174625560.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoeXh4aHducw==,size_16,color_FFFFFF,t_70) 110 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200606174625538.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoeXh4aHducw==,size_16,color_FFFFFF,t_70) 111 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200606174625510.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hoeXh4aHducw==,size_16,color_FFFFFF,t_70) 112 | -------------------------------------------------------------------------------- /src/components/register/register.vue: -------------------------------------------------------------------------------- 1 | 54 | 55 | 187 | 188 | 202 | -------------------------------------------------------------------------------- /src/views/singer/singer.vue: -------------------------------------------------------------------------------- 1 | 59 | 60 | 187 | 188 | 219 | -------------------------------------------------------------------------------- /src/views/songMenu/songMenu.vue: -------------------------------------------------------------------------------- 1 | 69 | 70 | 210 | 211 | 285 | -------------------------------------------------------------------------------- /src/views/singer/singerInformation/singerInformation.vue: -------------------------------------------------------------------------------- 1 | 85 | 86 | 236 | 237 | 273 | -------------------------------------------------------------------------------- /src/views/mv/videos.vue: -------------------------------------------------------------------------------- 1 | 61 | 62 | 212 | 213 | 311 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import axios from 'axios' 4 | 5 | Vue.use(Vuex) 6 | 7 | export default new Vuex.Store({ 8 | state: { 9 | // 当前播放音乐的地址,图片,歌曲名,歌手,歌词,在歌单里的位置信息 10 | playSong: { 11 | url: window.sessionStorage.getItem('url'), 12 | img: window.sessionStorage.getItem('img'), 13 | name: window.sessionStorage.getItem('name'), 14 | singer: window.sessionStorage.getItem('singer'), 15 | lyric: JSON.parse(window.sessionStorage.getItem('lyric')), 16 | num: window.sessionStorage.getItem('num') 17 | }, 18 | // 音乐是否处于播放状态,决定小图标该显示哪一个 19 | playIf: false, 20 | // 获取的audio dom 元素 21 | audio: {}, 22 | // 记录audio的状态,id值加一代表处于暂停状态 23 | active: window.sessionStorage.getItem('active') + 1, 24 | // 元总播放时长 25 | metaDuration: 0, 26 | // 元已经播放的时长 27 | metaCurrentTime: 0, 28 | // 菜单应该选到哪里 29 | activeName: '', 30 | // 歌曲列表 31 | songs: JSON.parse(window.sessionStorage.getItem('songs')), 32 | // 总歌曲数 33 | total: window.sessionStorage.getItem('total'), 34 | // songstable还是songs 35 | tableName: window.sessionStorage.getItem('tableName'), 36 | // 用户id,看是否存在用户id,判断用户是否登录 37 | accountId: window.localStorage.getItem('accountId'), 38 | // 用户的歌单id,用于添加/取消收藏歌曲 39 | songMenuId: window.localStorage.getItem('songMenuId'), 40 | checkFalse: true, 41 | memberSong: false 42 | }, 43 | getters: { 44 | // 播放进度 45 | percentage (state) { 46 | if (state.metaDuration === 0) { 47 | return 0 48 | } 49 | return Math.floor(state.metaCurrentTime / state.metaDuration * 100) 50 | }, 51 | // 播放总时长分钟 52 | duration (state) { 53 | const double = function (num) { 54 | if (num.toString().length !== 2) { 55 | if (num === 0) { 56 | return '00' 57 | } 58 | return '0' + num 59 | } 60 | return num 61 | } 62 | return `${double(Math.floor(state.metaDuration / 60))}:${double(Math.floor(state.metaDuration % 60))}` 63 | }, 64 | // 已经播放的分钟 65 | currentTime (state) { 66 | const double = function (num) { 67 | if (num.toString().length !== 2) { 68 | if (num === 0) { 69 | return '00' 70 | } 71 | return '0' + num 72 | } 73 | return num 74 | } 75 | return `${double(Math.floor(state.metaCurrentTime / 60))}:${double(Math.floor(state.metaCurrentTime % 60))}` 76 | } 77 | }, 78 | mutations: { 79 | // 提交当前播放音乐的地址,图片,歌曲名,歌手,歌词,在歌单里的位置信息并存在session里面 80 | playUrl (state, payload) { 81 | state.playSong.url = payload.url 82 | state.playSong.img = payload.img 83 | state.playSong.name = payload.name 84 | state.playSong.singer = payload.singer 85 | state.playSong.lyric = payload.lyric 86 | state.playSong.num = payload.num 87 | state.playIf = true 88 | window.sessionStorage.setItem('url', payload.url) 89 | window.sessionStorage.setItem('img', payload.img) 90 | window.sessionStorage.setItem('name', payload.name) 91 | window.sessionStorage.setItem('singer', payload.singer) 92 | window.sessionStorage.setItem('lyric', JSON.stringify(payload.lyric)) 93 | window.sessionStorage.setItem('num', payload.num) 94 | }, 95 | // 一首音乐结束操作 96 | ended (state, num) { 97 | // 让musicPlayer里面的播放标签变为停止标签 98 | if (state.playSong.num === state.total - 1) { 99 | state.playSong.num = 0 100 | } else { 101 | state.playSong.num = num + 1 102 | } 103 | state.playIf = false 104 | state.active = 0 105 | }, 106 | // 得到元总时长 107 | getDuration (state, audio) { 108 | state.metaDuration = audio.duration 109 | state.metaCurrentTime = audio.currentTime 110 | state.audio = audio 111 | }, 112 | // 得到元已经播放的时间 113 | getCurrentTime (state) { 114 | state.metaCurrentTime = state.audio.currentTime 115 | }, 116 | // 暂停音乐,songTable 117 | pauseMusic (state) { 118 | state.playIf = false 119 | state.audio.pause() 120 | }, 121 | // 放音乐,songTable 122 | playMusic (state) { 123 | if (state.playSong !== '') { 124 | state.audio.play() 125 | state.playIf = true 126 | } 127 | }, 128 | // 放音乐。musicPlayer 129 | playSongs (state) { 130 | if (state.playUrl !== '') { 131 | console.log(state.active) 132 | state.audio.play() 133 | state.playIf = true 134 | state.active = state.active - 1 135 | } 136 | }, 137 | // 暂停音乐,musicPlayer 138 | pauseSongs (state) { 139 | state.playIf = false 140 | state.audio.pause() 141 | console.log(state.active) 142 | state.active = state.active + 1 143 | }, 144 | // 通过控制active,来记录audio状态 145 | editActive (state, num) { 146 | state.active = num 147 | }, 148 | // 修改活跃主菜单的名称 149 | editActiveName (state, name) { 150 | state.activeName = name 151 | }, 152 | // 得到一个歌单的总的歌曲数并存在session里 153 | getTotal (state, total) { 154 | window.sessionStorage.setItem('total', total) 155 | state.total = total 156 | }, 157 | // 上一首播放 158 | editPreNum (state) { 159 | if (state.playSong.num === 0) { 160 | state.playSong.num = state.total - 1 161 | } else { 162 | state.playSong.num-- 163 | } 164 | }, 165 | // 下一首播放 166 | editNextNum (state) { 167 | if (state.playSong.num === state.total - 1) { 168 | state.playSong.num = 0 169 | } else { 170 | state.playSong.num++ 171 | } 172 | }, 173 | // 得到歌单的总歌曲信息并存在session里 174 | getSongs (state, songs) { 175 | window.sessionStorage.setItem('songs', JSON.stringify(songs)) 176 | state.songs = songs 177 | // this.play(0) 178 | }, 179 | // 修改是哪一种类型的歌曲列表 180 | editName (state, name) { 181 | state.tableName = name 182 | }, 183 | // 得到用户id 184 | getAccountId (state, value) { 185 | state.accountId = value 186 | window.localStorage.setItem('accountId', value) 187 | }, 188 | // 得到用户歌单id 189 | getSongMenuId (state, value) { 190 | state.songMenuId = value 191 | window.localStorage.setItem('songMenuId', value) 192 | }, 193 | editCheckFalse (state, value) { 194 | state.checkFalse = value 195 | }, 196 | editMemberSong (state, value) { 197 | state.memberSong = value 198 | }, 199 | addSongs (state, value) { 200 | window.sessionStorage.setItem('total', state.total + 1) 201 | state.total = state.total + 1 202 | state.songs.push(value) 203 | console.log(state.songs) 204 | } 205 | }, 206 | actions: { 207 | play (context, payload) { 208 | context.commit('editCheckFalse', true) 209 | context.commit('editMemberSong', false) 210 | console.log(context.state.songs[payload.num]) 211 | axios.get(`/check/music?id=${context.state.songs[payload.num].id}`).then(() => { 212 | axios.all([axios.get(`/song/url?id=${context.state.songs[payload.num].id}`), axios.get(`/lyric?id=${context.state.songs[payload.num].id}`)]) 213 | .then(axios.spread((songUrl, lyric) => { 214 | if (songUrl.data[0].url !== null) { 215 | window.sessionStorage.setItem('active', context.state.songs[payload.num].id) 216 | context.commit('editActive', context.state.songs[payload.num].id) 217 | context.commit('editName', payload.name) 218 | window.sessionStorage.setItem('tableName', payload.name) 219 | if (payload.name === 'songs') { 220 | context.commit('playUrl', { 221 | url: songUrl.data[0].url, 222 | img: context.state.songs[payload.num].artists[0].img1v1Url, 223 | name: context.state.songs[payload.num].name, 224 | singer: context.state.songs[payload.num].artists[0].name, 225 | lyric: lyric, 226 | num: payload.num 227 | }) 228 | } else if (payload.name === 'songTable') { 229 | context.commit('playUrl', { 230 | url: songUrl.data[0].url, 231 | img: context.state.songs[payload.num].al.picUrl, 232 | name: context.state.songs[payload.num].name, 233 | singer: context.state.songs[payload.num].al.name, 234 | lyric: lyric, 235 | num: payload.num 236 | }) 237 | } else { 238 | context.commit('playUrl', { 239 | url: songUrl.data[0].url, 240 | img: context.state.songs[payload.num].album.picUrl, 241 | name: context.state.songs[payload.num].name, 242 | // singer: context.state.songs[payload.num].al[0].name, 243 | lyric: lyric, 244 | num: payload.num 245 | }) 246 | } 247 | } else { 248 | context.commit('editMemberSong', true) 249 | } 250 | })) 251 | }).catch(() => { 252 | context.commit('editCheckFalse', false) 253 | }) 254 | } 255 | }, 256 | modules: { 257 | } 258 | }) 259 | -------------------------------------------------------------------------------- /src/views/mv/mv.vue: -------------------------------------------------------------------------------- 1 | 66 | 67 | 222 | 223 | 320 | -------------------------------------------------------------------------------- /src/views/album/album.vue: -------------------------------------------------------------------------------- 1 | 70 | 71 | 212 | 213 | 320 | -------------------------------------------------------------------------------- /src/views/songMenu/detail/detail.vue: -------------------------------------------------------------------------------- 1 | 68 | 69 | 205 | 206 | 346 | -------------------------------------------------------------------------------- /src/views/myMusic/myMusic.vue: -------------------------------------------------------------------------------- 1 | 86 | 87 | 262 | 263 | 402 | -------------------------------------------------------------------------------- /src/views/index.vue: -------------------------------------------------------------------------------- 1 | 120 | 121 | 286 | 424 | --------------------------------------------------------------------------------