最近刚刚写好了网易云音乐(wymusic)的实例,那就总结总结吧~~~~

先感谢感谢前人的努力吧

因为Binaryify大神对接口的不对更新才有了这篇文章,感谢感谢!

公共引用

main.js(以element ui的使用为例)

1
2
3
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(Element)

关于分类

将view文件统一放在 src/pages/ 下面

将component文件统一放在 src/components/ 下面

vue-router

router/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mport Vue from 'vue'
import Router from 'vue-router'
import Recommend from '@/pages/Recommend'
import LeaderBoards from '@/pages/LeaderBoards'
Vue.use(Router)

export default new Router({
routes: [
{
path:'',
redirect: '/recommend'
},
{
path: '/recommend',
name: 'recommend',
component: Recommend
}
]
})

src/app.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div id="app">
<router-view :key="key" />
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {}
},
methods: {
},
computed:{
key() {
return this.$route.name !== undefined? this.$route.name + +new Date(): this.$route + +new Date()
}
}
}
</script>

ps:我创建和编辑的页面使用的是同一个component,默认情况下当这两个页面切换时并不会触发vue的created或者mounted钩子,官方说你可以通过watch $route的变化来做处理,但其实说真的还是蛮麻烦的。后来发现其实可以简单的在 router-view上加上一个唯一的key,来保证路由切换时都会重新渲染触发钩子了。这样简单的多了。

组件引用

src/pages/Recommend.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div id="Recommend">
<BannerComponent></BannerComponent>
</div>
</template>
<script>
import BannerComponent from '@/components/BannerComponent'
export default {
name:"Recommend",
components:{
BannerComponent,
AlbumComponent,
SingersComponent,
MVComponent
},
data () {
return {};
}
}
</script>

组件之间通信

父子组件之间(props)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//在父组件中注册子组件
//父组件(Recommend.vue):
<template>
<BannerComponent :toBanner="bannerJson.banners" title="recommend-banner"></BannerComponent>
</template>

....

//子组件(BannerComponent.vue):
<template>
<div id="BannerComponent" v-if="title === 'recommend-banner'">
<swiper :options="swiperOption">
<swiper-slide v-for="(item,index) in toBanner" :key="index">
<img :src="item.pic | filterImg">
</swiper-slide>
<div class="swiper-pagination" slot="pagination"></div>
<div class="swiper-button-prev" slot="button-prev"></div>
<div class="swiper-button-next" slot="button-next"></div>
</swiper>
</div>
</template>
<script>
export default{
name: 'BannerComponent',
props:['toBanner','title'],
data () {
return {}
}
}
</script>

ps: (:toBanner)代表值是动态获取的;(title)代表值是静态的

子父组件传值(emit)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//子组件:
<template>
<button @click="sendToParent">向父组件传值</buttoon>
</template>
<script>
export default {
methods: {
sendToParent() {
this.$emit("listenToChild","this message is from child");
}
}
}
</script>

.....

//父组件:
<template>
<child listenToChild="showMsgFromChild"></child>
</template>
<script>
export default{
data(){
return {};
},
methods: {
showMsgFromChild(data){
console.log(data); //this message is from child
}
}
}
</script>

vuex

封装axios

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//src/config.js
import Vue from 'vue'
import axios from 'axios'
import qs from 'qs'
Vue.prototype.$http = axios // 这样设置就可以在组件内用 this.$http 使用axios了
axios.defaults.baseURL = 'http://localhost:3000'

export var axiosRq = async(type = 'POST', url = '', data = {}) => {
let result
type = type.toUpperCase()
if (type === 'GET') {
await axios.get(url, { params: data })
.then(res => {
result = res.data
})
} else if (type === 'POST') {
await axios.post(url, qs.stringify(data))
.then(res => {
result = res.data
})
}
return result
}

使用

  • 在src先新建store文件夹
  • store中目录包含 index.js 和 modules文件夹
  • 在src/main.js中引用store
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//src/store/index.js
import Vue from "vue"
import Vuex from 'vuex'
import banner from './modules/banner'
Vue.use(Vuex)

export default new Vuex.Store({
modules: {
banner
}
})


src/store/modules/banner.js

import { axiosRq } from "../../config"
export default {
state: {
banner:[]
},
mutations: {
GETBANNER (state, res) {
state.banner = res;
}
},
actions: {
async getBannerData ({commit}) {
let res = await axiosRq('GET', 'banner')
if(res) {
commit('GETBANNER',res);
}
}
}
}

在view中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Recommend.vue
<template>
{{bannerJson}}
</template>
<script>
import { mapState, mapMutations, mapActions } from 'vuex'
export default {
data () {
return {}
},
methods: {
...mapAction([
'getBannerData' //相当于this.$store.dispatch('getBannerData')
])
},
computed: {
...mapState({
'bannerJson': state = > state.banner.banner, //第一个banner是export的banner对象,第二个banner是banner.js state值
})
},
mounted() {
this.getBannerData(); // 调用banner接口
}
}
</script>

公共js(filter.js为例)

将公共js部分写在src/filter.js内,在src/main.js中导入即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//filter.js
import Vue from 'vue'
Vue.filter('transformTime', (value)=>{
if(!value) return ''
let date = new Date(value)
let time
if(date.getHours() === 0 ){
time= date.getMinutes() + ":" + date.getSeconds()
}else{
time = date.getHours() +":"+ date.getMinutes() + ":" + date.getSeconds()
}
return time
})

//引用(src/main.js)
import "@/filter.js"

//使用
{{ message | transformTime }}

sass

  • 将公共变量写在 src/assets/css/variables.scss
  • 将公共样式写在 src/assets/css/style.scss
  • 在src/main.js 中引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//variables.scss
$grey:#eee;
$font-title-color:#333;
$font-detail-color:#999;
$font-color:#666;
$red:#c20c0c;
$white:#fff;
$black:#242424;
$blue:#0c73c2;
$body-color:#f5f5f5;
$font-size:14px;
$border-area-color:#d3d3d3;

//style.scss
body {
font-size:$font-size;
color:$font-color;
background-color:$body-color;
}
1
2
3
//main.js
import "@/assets/css/variables.scss"
import "@/assets/css/style.scss"