router.js
{
path: '/botnav',
name: 'botnav',
component: () => import('./views/Botnav.vue'),
children:[
{
path: 'index',
name: 'index',
component: () => import('./views/Index.vue')
},
{
path: 'list',
name: 'list',
component: () => import('./views/List.vue')
},
{
path: 'search',
name: 'search',
component: () => import('./views/Search.vue')
},
{
path: 'cart',
name: 'cart',
meta:{
requireAuth:true,//当有这个字段的时候,我们就认为他这个路由页面是要有登录权限的
},
component: () => import('./views/Cart.vue')
},
{
path: 'mine',
name: 'mine',
meta:{
requireAuth:true,//当有这个字段的时候,我们就认为他这个路由页面是要有登录权限的
},
component: () => import('./views/Mine.vue')
},
]
}
vue.config.js
//首页轮播图数据接口
app.get('/api/banner',(req,res)=>{
res.json({
data:[ {
url: 'https://m.xdclass.net',
image: /learn.png'
},
......
]
})
})
//滚动分类接口
app.get('/api/rollinglist',(req,res)=>{
res.json({
data:[
[
{
url: 'https://m.xdclass.net',
image: '/learn.png',
label:'分类一'
}
......
],
[
{
url: 'https://m.xdclass.net',
image: '/bat.png',
label:'分类一'
}
......
],
]
})
})
//获取分类页的分类接口
app.get('/api/classify',(req,res)=>{
switch(req.query.type){
case '0':
res.json({
data:[
{
image:'/5a1692eeN105a64b4.png',
label:'小米'
}
......
]
});
break;
case '1':
res.json({
data: [
{
image:'/5a1692eeN105a64b4.png',
label:'小米'
}
......
]
});
break;
case '2':
res.json({
data: [
{
image:'/5a1692e2Nbea6e136.jpg',
label:'华为'
},
{
image:'/5a1692e2Nbea6e136.jpg',
label:'华为'
},
{
image:'/5a1692e2Nbea6e136.jpg',
label:'华为'
},
{
image:'/5a1692e2Nbea6e136.jpg',
label:'华为'
}
]
});
break;
case '3':
res.json({
data: [
{
image:'/5a1692e2N6df7c609.jpg',
label:'荣耀'
}
......
]
});
break;
case '4':
res.json({
data: [
{
image:'/5a1692eeN105a64b4.png',
label:'小米'
}
......
]
});
break;
case '5':
res.json({
data: [
{
image:'/5a1692ebN8ae73077.jpg',
label:'雪梨手机'
}
......
]
});
break;
case '6':
res.json({
data: [
{
image:'/5a1692eeN105a64b4.png',
label:'小米'
}
......
]
});
break;
}
})
main.js
//路由守卫
router.beforeEach((to,from,next)=>{
//无论是刷新还是跳转路由,第一个进入的就是这个路由前置钩子函数
//如果有token,正常进入,没有跳转到登陆页面
store.commit('settoken',localStorage.getItem('token'))
if(to.meta.requireAuth){
if(store.state.token){
next()
}else{
next({
path:'/login',
query:{redirect:to.fullPath}
})
}
}else{
next()
}
})
Botnav.vue
##footer
<template>
<div>
<transition :name="transitionName">
<router-view class="Router"></router-view>
</transition>
<cube-tab-bar
v-model="selectedLabelDefault"
:data="tabs"
@click="clickHandler"
@change="changeHandler"
class="botnav">
</cube-tab-bar>
</div>
</template>
<script>
export default {
data () {
return {
transitionName:'slide-right',
selectedLabelDefault: '首页',
tabs: [{
label: '首页',
icon: 'cubeic-home'
}, {
label: '分类',
icon: 'cubeic-tag'
}, {
label: '搜索',
icon: 'cubeic-search'
}, {
label: '购物车',
icon: 'cubeic-mall'
}, {
label: '我的',
icon: 'cubeic-person'
}]
}
},
methods: {
clickHandler (label) {
// if you clicked home tab, then print 'Home'
console.log(label)
},
//点击与自身不同的其他导航
changeHandler (label) {
// if you clicked different tab, this methods can be emitted
switch(label){
case '首页':
this.$router.push({path:'/botnav/index'});
break;
case '分类':
this.$router.push({path:'/botnav/list'});
break;
case '搜索':
this.$router.push({path:'/botnav/search'});
break;
case '购物车':
this.$router.push({path:'/botnav/cart'});
break;
case '我的':
this.$router.push({path:'/botnav/mine'});
break;
}
}
},
//页面对应的footer的图标是发亮的
created(){
switch(this.$route.path){
case '/botnav/index':
this.selectedLabelDefault='首页';
break;
case '/botnav/list':
this.selectedLabelDefault='分类';
break;
case '/botnav/search':
this.selectedLabelDefault='搜索';
break;
case '/botnav/cart':
this.selectedLabelDefault='购物车';
break;
case '/botnav/mine':
this.selectedLabelDefault='我的';
break;
}
}
}
</script>
//带有动画效果
<style lang="stylus">
.cube-tab-bar.botnav
position fixed
bottom 0
left 0
z-index 1000
width 100%
background #fff
.cube-tab div
font-size 16px
padding-top 3px
i
font-size 20px
.Router
position absolute
width 100%
transition all 0.8s ease
.silde-left-enter,.slide-right-leave-active
opacity 0
-webkit-transform translate(100%,0)
transform translate(100%,0)
.slide-left-leave-active,.slide-right-enter
opacity 0
-webkit-transform translate(-100%,0)
transform translate(-100%,0)
</style>
Index.vue
//首页
<template>
<div id="index">
<!-- 轮播图 -->
<cube-slide ref="slide" :data="items" @change="changePage">
<cube-slide-item v-for="(item, index) in items"
:key="index" @click.native="clickHandler(item, index)">
<a :href="item.url">
<img class="banner" :src="item.image">
</a>
</cube-slide-item>
</cube-slide>
<!-- 滚动分类 -->
<cube-slide ref="slidelists" :auto-play="false" :data="lists">
<cube-slide-item v-for="(list, index) in lists" :key="index">
<ul class="listul">
<li class="listli" v-for="(item,index1) in list" :key="index1">
<a :href="item.url">
<img :src="item.image" alt="">
<p>{{item.label}}</p>
</a>
</li>
</ul>
</cube-slide-item>
</cube-slide>
</div>
</template>
<script>
export default {
data() {
return {
items: [],//轮播图数组
lists:[],//滚动分类数组
}
},
methods: {
changePage(current) {
// console.log('当前轮播图序号为:' + current)
},
clickHandler(item, index) {
console.log(item, index)
}
},
async created(){
try{
//获取轮播图数据
const items=await this.$http.get('/api/banner')
this.items=items.data
//获取滚动分类数据
const lists=await this.$http.get('/api/rollinglist')
this.lists=lists.data
}catch(err){
console.log(err)
}
}
}
</script>
<style lang="stylus" scoped>
#index
a
.banner
display block
width 100%
height 175px
.listul
display flex
flex-wrap wrap
.listli
width 20%
justify-content center
img
width 35px
height 35px
border-radius 50%
padding 5px 0
p
font-size 14px
padding-bottom 10px
</style>
List.vue
//分类
<template>
<div class="panelsbox">
<cube-scroll class="leftpanels">
<ul>
<li v-for="(list,index) in tabslabel" @click='selectlist(index)'
:class="list.active?'active':''" :key='index'>
{{list.label}}
</li>
</ul>
</cube-scroll>
<cube-scroll class="rightpanels">
<ul>
<li v-for="(tag,index) in tags" :key="index">
<img :src="tag.image" alt="">
<p>{{tag.label}}</p>
</li>
</ul>
</cube-scroll>
</div>
</template>
<script>
export default {
data(){
return{
tags:[],
tabslabel:[
{
label:'热门推荐',
active:true
},
{
label:'手机数码',
active:false
},
{
label:'家用电器',
active:false
},
{
label:'家用空调',
active:false
},
{
label:'电脑产品',
active:false
},
{
label:'计生情趣',
active:false
},
{
label:'美妆护肤',
active:false
},
{
label:'口红',
active:false
},
{
label:'手袋',
active:false
},
{
label:'金银财宝',
active:false
},
{
label:'手机数码',
active:false
},
{
label:'手机数码',
active:false
},
]
}
},
methods:{
//点击左侧分类
selectlist(index){
this.tabslabel.forEach((val,ind)=>{
if(index==ind){
val.active=true
}else{
val.active=false
}
})
this.getclassify(index)
},
//获取分类
async getclassify(index){
const result=await this.$http.get('/api/classify',{params:{type:index}})
this.tags=result.data
}
},
created(){
//获取默认的分类数据
this.getclassify(0)
},
mounted(){
//设置滚动盒子的高度
const leftpanels=document.querySelector('.leftpanels')
const rightpanels=document.querySelector('.rightpanels')
const bodyheight=document.documentElement.clientHeight
leftpanels.style.height=bodyheight-57+'px'
rightpanels.style.height=bodyheight-57+'px'
}
}
</script>
<style lang="stylus" scoped>
.panelsbox
display flex
.leftpanels
width 30%
li
height 50px
line-height 50px
border-bottom 1px solid #fff
color #333
background #f8f8f8
font-size 14px
.active
background #fff
color #e93b3d
.rightpanels
width 70%
ul
display flex
flex-wrap wrap
li
width 50%
justify-content center
align-items center
font-size 15px
img
width 80px
height 80px
</style>
Login.vue
##默认跳转到首页,如果是丢失token,则得到token后跳转到相应页面
methods:{
async submitHandler(e){
e.preventDefault()
try{
const result=await this.$http.get('/api/login',{params:this.model})
if(result.code=='0'){
this.$store.commit('settoken',result.token)
window.localStorage.setItem('token',result.token)
//判断路由是否带参,带参就去到重定向参数地址,否则就去首页
if(this.$route.query.redirect){
this.$router.replace({path:this.$route.query.redirect})
}else{
this.$router.replace({path:'/botnav/index'})
}
}else{
alert(result.message)
}
}catch(err){
console.log(err)
}
}
}