Vue webAPP首页开发(二)_蜡烛_前端开发者

接上篇 https://www.cnblogs.com/chenyingying0/p/12612393.html

https://www.cnblogs.com/chenyingying0/p/12612393.html

 

Loading组件

在api–home.js中,添加代码,使ajax获取到轮播图数据后,延迟一秒再显示

import axios from 'axios';
import {SUCC_CODE,TIMEOUT} from './config';

//获取幻灯片数据 ajax
export const getHomeSliders=()=>{
    // es6使用promise代替回调
    // axios返回的就是一个promise
    // return axios.get('http://www.imooc.com/api/home/slider').then(res=>{
    //     console.log(res);
    //     if(res.data.code===SUCC_CODE){
    //         return res.data.slider;
    //     }

    //     throw new Error('没有成功获取到数据');
    // }).catch(err=>{
    //     console.log(err);
    //     //错误处理
    //     return [{       
    //         linkUrl:'www.baidu.com',
    //         picUrl:require('assets/img/404.png')
    //     }]
    // });

    //演示超时错误
    return axios.get('http://www.imooc.com/api/home/slider',{
        timeout:TIMEOUT
    }).then(res=>{
        console.log(res);
        if(res.data.code===SUCC_CODE){
            return res.data.slider;
        }

        throw new Error('没有成功获取到数据');
    }).catch(err=>{
        console.log(err);
        //错误处理
        return [{       
            linkUrl:'www.baidu.com',
            picUrl:require('assets/img/404.png')
        }]
    }).then(data=>{//获取轮播图数据后,延迟一秒再显示
        return new Promise(resolve=>{
            setTimeout(()=>{
                resolve(data);
            },1000);
        })
    });
}
import axios from 'axios';
import {SUCC_CODE,TIMEOUT} from './config';

//获取幻灯片数据 ajax
export const getHomeSliders=()=>{
    // es6使用promise代替回调
    // axios返回的就是一个promise
    // return axios.get('http://www.imooc.com/api/home/slider').then(res=>{
    //     console.log(res);
    //     if(res.data.code===SUCC_CODE){
    //         return res.data.slider;
    //     }

    //     throw new Error('没有成功获取到数据');
    // }).catch(err=>{
    //     console.log(err);
    //     //错误处理
    //     return [{       
    //         linkUrl:'www.baidu.com',
    //         picUrl:require('assets/img/404.png')
    //     }]
    // });

    //演示超时错误
    return axios.get('http://www.imooc.com/api/home/slider',{
        timeout:TIMEOUT
    }).then(res=>{
        console.log(res);
        if(res.data.code===SUCC_CODE){
            return res.data.slider;
        }

        throw new Error('没有成功获取到数据');
    }).catch(err=>{
        console.log(err);
        //错误处理
        return [{       
            linkUrl:'www.baidu.com',
            picUrl:require('assets/img/404.png')
        }]
    }).then(data=>{//获取轮播图数据后,延迟一秒再显示
        return new Promise(resolve=>{
            setTimeout(()=>{
                resolve(data);
            },1000);
        })
    });
}

;
import {SUCC_CODE,TIMEOUT} from
;

//获取幻灯片数据 ajax{
// es6使用promise代替回调// axios返回的就是一个promise// return axios.get(‘http://www.imooc.com/api/home/slider’).then(res=>{// console.log(res);// if(res.data.code===SUCC_CODE){// return res.data.slider;// }// throw new Error(‘没有成功获取到数据’);// }).catch(err=>{// console.log(err);// //错误处理// return [{ // linkUrl:’www.baidu.com’,// picUrl:require(‘assets/img/404.png’)// }]// });//演示超时错误return,{
timeout:TIMEOUT
}).then(res
{
console.log(res);
ifSUCC_CODE){
return res.data.slider;
}

thrownew);
}).
catch{
console.log(err);
//错误处理return [{
linkUrl:
,
picUrl:require(
)
}]
}).then(data
//获取轮播图数据后,延迟一秒再显示returnnew{
setTimeout(()
{
resolve(data);
},
);
})
});
}

 

在base下创建loading文件夹,里面创建index.vue

<template>
    <div class="mine-loading" :class="{'me-loading-inline':inline}">
        <span class="mine-loading-indicator" v-if="indicator==='on'" >
            <img src="./loading.gif" alt="">
        </span>
        <span class="mine-loading-text" v-if="text">{{text}}</span>
    </div>
</template>

<script>
export default {
   name:"MeLoading",
   props:{//过滤器
       indicator:{
           type:String,
           default:'on',
           validator(value){
               return ['on','off'].indexOf(value)>-1;
           }
       },
       text:{
           type:String,
           default:'加载中...'
       },
        inline:{
            type:Boolean,
            default:false
        }
   }
}
</script>

<style lang="scss" scoped>
    @import '~assets/scss/mixins';

    .mine-loading{
        width:100%;
        height:100%;
        @include flex-center(column);

        //图文左右排列时
        &.me-loading-inline{
            flex-direction: row;
           
            .mine-loading-indicator ~ .mine-loading-text{
                margin-top:0px;
                margin-left:7px;
            }
        }

        .mine-loading-indicator{

        }

        // 存在.mine-loading-indicator和.mine-loading-text时
        .mine-loading-indicator ~ .mine-loading-text{
            margin-top:7px;
        }
    }
</style>
<template>
    <div class="mine-loading" :class="{'me-loading-inline':inline}">
        <span class="mine-loading-indicator" v-if="indicator==='on'" >
            <img src="./loading.gif" alt="">
        </span>
        <span class="mine-loading-text" v-if="text">{{text}}</span>
    </div>
</template>

<script>
export default {
   name:"MeLoading",
   props:{//过滤器
       indicator:{
           type:String,
           default:'on',
           validator(value){
               return ['on','off'].indexOf(value)>-1;
           }
       },
       text:{
           type:String,
           default:'加载中...'
       },
        inline:{
            type:Boolean,
            default:false
        }
   }
}
</script>

<style lang="scss" scoped>
    @import '~assets/scss/mixins';

    .mine-loading{
        width:100%;
        height:100%;
        @include flex-center(column);

        //图文左右排列时
        &.me-loading-inline{
            flex-direction: row;
           
            .mine-loading-indicator ~ .mine-loading-text{
                margin-top:0px;
                margin-left:7px;
            }
        }

        .mine-loading-indicator{

        }

        // 存在.mine-loading-indicator和.mine-loading-text时
        .mine-loading-indicator ~ .mine-loading-text{
            margin-top:7px;
        }
    }
</style>

ifif
export
default {
name:
,
props:{
//过滤器 indicator:{
type:String,
default,
validator(value){
return;
}
},
text:{
type:String,
default
},
inline:{
type:Boolean,
defaultfalse
}
}
}

@import
;

.mineloading{
width:
;
height:
;
@include flex
center(column);

//图文左右排列时inline{
flex
direction: row;

.minetext{
margin
top:0px;
margin
left:7px;
}
}

.mineindicator{

}

// 存在.mine-loading-indicator和.mine-loading-text时text{
margin
top:7px;
}
}

 

在base-loading文件夹下放入loadging.gif

 

在home–slider.vue中引入loading组件

<template>
    <div class="slider-wrapper">
        <!-- sliders没加载时显示loading -->
        <Meloading v-if="!sliders.length"></Meloading>
        <!-- 分开传才能分开校验,因此不直接传入对象 -->
        <MeSlider 
            :direction="direction"
            :loop="loop"
            :interval="interval"
            :pagination="pagination"
            v-else
        >
            <swiper-slide v-for="(item,index) in sliders" :key="index">
                <a :href="item.linkUrl" class="slider-link">
                    <img :src="item.picUrl" class="slider-img">
                </a>
            </swiper-slide>
        </MeSlider>
    </div>
</template>

<script>
import MeSlider from 'base/slider';
import { SwiperSlide } from 'vue-awesome-swiper';
import { sliderOptions } from './config';
import { getHomeSliders } from 'api/home';
import Meloading from 'base/loading';

export default {
   name:"HomeSlider",
   components:{
       MeSlider,
       SwiperSlide,
       Meloading
   },
    data(){
        return{
            direction:sliderOptions.direction,
            loop:sliderOptions.loop,
            interval:sliderOptions.interval,
            pagination:sliderOptions.pagination,
            sliders:[],//这是从服务器读取
            //这是静态写入
            // sliders:[
            //     {
            //        linkUrl:'www.baidu.com',
            //        picUrl:require('./1.jpg') //js中本地图片引入必须加require
            //     },
            //     {
            //        linkUrl:'www.baidu.com',
            //        picUrl:require('./2.jpg') 
            //     },
            //     {
            //        linkUrl:'www.baidu.com',
            //        picUrl:require('./3.jpg') 
            //     },
            //     {
            //        linkUrl:'www.baidu.com',
            //        picUrl:require('./4.jpg') 
            //     }
            // ]
        }
    },
    created(){
        //一般在created里获取远程数据
        this.getSliders();
        
        
    },
    methods:{
        getSliders(){
            getHomeSliders().then(data=>{
                console.log(data);
                this.sliders=data;
            });
        }
    }
}
</script>

<style lang="scss" scoped>
    // 引入前面需要加波浪线,否则会报错
    @import "~assets/scss/mixins";
    .slider-wrapper{
        width:100%;
        height:183px;
    }
    .slider-link{
        display:block;
    }
    .slider-link,
    .slider-img{
        width:100%;
        height:100%;
    }
    
</style>
<template>
    <div class="slider-wrapper">
        <!-- sliders没加载时显示loading -->
        <Meloading v-if="!sliders.length"></Meloading>
        <!-- 分开传才能分开校验,因此不直接传入对象 -->
        <MeSlider 
            :direction="direction"
            :loop="loop"
            :interval="interval"
            :pagination="pagination"
            v-else
        >
            <swiper-slide v-for="(item,index) in sliders" :key="index">
                <a :href="item.linkUrl" class="slider-link">
                    <img :src="item.picUrl" class="slider-img">
                </a>
            </swiper-slide>
        </MeSlider>
    </div>
</template>

<script>
import MeSlider from 'base/slider';
import { SwiperSlide } from 'vue-awesome-swiper';
import { sliderOptions } from './config';
import { getHomeSliders } from 'api/home';
import Meloading from 'base/loading';

export default {
   name:"HomeSlider",
   components:{
       MeSlider,
       SwiperSlide,
       Meloading
   },
    data(){
        return{
            direction:sliderOptions.direction,
            loop:sliderOptions.loop,
            interval:sliderOptions.interval,
            pagination:sliderOptions.pagination,
            sliders:[],//这是从服务器读取
            //这是静态写入
            // sliders:[
            //     {
            //        linkUrl:'www.baidu.com',
            //        picUrl:require('./1.jpg') //js中本地图片引入必须加require
            //     },
            //     {
            //        linkUrl:'www.baidu.com',
            //        picUrl:require('./2.jpg') 
            //     },
            //     {
            //        linkUrl:'www.baidu.com',
            //        picUrl:require('./3.jpg') 
            //     },
            //     {
            //        linkUrl:'www.baidu.com',
            //        picUrl:require('./4.jpg') 
            //     }
            // ]
        }
    },
    created(){
        //一般在created里获取远程数据
        this.getSliders();
        
        
    },
    methods:{
        getSliders(){
            getHomeSliders().then(data=>{
                console.log(data);
                this.sliders=data;
            });
        }
    }
}
</script>

<style lang="scss" scoped>
    // 引入前面需要加波浪线,否则会报错
    @import "~assets/scss/mixins";
    .slider-wrapper{
        width:100%;
        height:183px;
    }
    .slider-link{
        display:block;
    }
    .slider-link,
    .slider-img{
        width:100%;
        height:100%;
    }
    
</style>

ifMeSlider
:direction

:loop

:interval

:pagination

v
elsefor
import MeSlider from
;
import { SwiperSlide } from
;
import { sliderOptions } from
;
import { getHomeSliders } from
;
import Meloading from
;

export default {
name:
,
components:{
MeSlider,
SwiperSlide,
Meloading
},
data(){
return{
direction:sliderOptions.direction,
loop:sliderOptions.loop,
interval:sliderOptions.interval,
pagination:sliderOptions.pagination,
sliders:[],
//这是从服务器读取//这是静态写入// sliders:[// {// linkUrl:’www.baidu.com’,// picUrl:require(‘./1.jpg’) //js中本地图片引入必须加require// },// {// linkUrl:’www.baidu.com’,// picUrl:require(‘./2.jpg’) // },// {// linkUrl:’www.baidu.com’,// picUrl:require(‘./3.jpg’) // },// {// linkUrl:’www.baidu.com’,// picUrl:require(‘./4.jpg’) // }// ] }
},
created(){
//一般在created里获取远程数据this.getSliders();

},
methods:{
getSliders(){
getHomeSliders().then(data{
console.log(data);
thisdata;
});
}
}
}
// 引入前面需要加波浪线,否则会报错;
.slider
wrapper{
width:
;
height:183px;
}
.slider
link{
display:block;
}
.slider
link,
.slider
img{
width:
;
height:
;
}

 

目录如下:

 

 

效果图

 

滚动条组件

在base目录下创建scroll目录,新建index.vue

<template>
    <swiper :options="swiperOption">
        <swiper-slide>
            <slot></slot>
        </swiper-slide>
        <div class="swiper-scrollbar" v-if="scrollbar" slot="scrollbar"></div>
    </swiper>
</template>

<script>
// 组件首字母大写,否则会报错
import {Swiper,SwiperSlide} from 'vue-awesome-swiper';

export default {
    name:"MeScroll",
    components:{
        Swiper,
        SwiperSlide
    },
    props:{//过滤器
       scrollbar:{
           type:Boolean,
           default:true
       }
    },
    data(){
        return {
            swiperOption:{
                direction:'vertical',//垂直方向
                slidesPerView:'auto',//一次显示几张
                freeMode:true,//任意滑动多少距离
                setWrapperSize:true,//根据内容设置容器尺寸
                scrollbar:{
                    el:this.scrollbar?'.swiper-scrollbar':null,
                    hide:true //滚动条自动隐藏
                }

            }
        }
    }
}
</script>

<style lang="scss" scoped>
    @import '~assets/scss/mixins';

    .swiper-container{
        width:100%;
        height:100%;
        overflow:hidden;

        & .swiper-slide{
            height:auto;
        }  
    }
     
</style>
<template>
    <swiper :options="swiperOption">
        <swiper-slide>
            <slot></slot>
        </swiper-slide>
        <div class="swiper-scrollbar" v-if="scrollbar" slot="scrollbar"></div>
    </swiper>
</template>

<script>
// 组件首字母大写,否则会报错
import {Swiper,SwiperSlide} from 'vue-awesome-swiper';

export default {
    name:"MeScroll",
    components:{
        Swiper,
        SwiperSlide
    },
    props:{//过滤器
       scrollbar:{
           type:Boolean,
           default:true
       }
    },
    data(){
        return {
            swiperOption:{
                direction:'vertical',//垂直方向
                slidesPerView:'auto',//一次显示几张
                freeMode:true,//任意滑动多少距离
                setWrapperSize:true,//根据内容设置容器尺寸
                scrollbar:{
                    el:this.scrollbar?'.swiper-scrollbar':null,
                    hide:true //滚动条自动隐藏
                }

            }
        }
    }
}
</script>

<style lang="scss" scoped>
    @import '~assets/scss/mixins';

    .swiper-container{
        width:100%;
        height:100%;
        overflow:hidden;

        & .swiper-slide{
            height:auto;
        }  
    }
     
</style>

if// 组件首字母大写,否则会报错;

export default {
name:
,
components:{
Swiper,
SwiperSlide
},
props:{
//过滤器 scrollbar:{
type:Boolean,
defaulttrue
}
},
data(){
return {
swiperOption:{
direction:
//垂直方向//一次显示几张true//任意滑动多少距离true//根据内容设置容器尺寸 scrollbar:{
el:
thisnull,
hide:
true//滚动条自动隐藏 }

}
}
}
}

@import
;

.swipercontainer{
width:
;
height:
;
overflow:hidden;

slide{
height:auto;
}
}

 

在home–index.vue中引入scroll组件

<template>
    <div class="home">
        <header class="g-header-container">
            <!-- 没有内容自闭合即可-->
            <home-header/>
        </header> 
        <me-scroll>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
        </me-scroll>
        <div class="g-backup-container"></div>
        <!-- 当前页面存在二级页面时需要使用router-view -->
        <router-view></router-view>
    </div>
</template>

<script>
import MeScroll from 'base/scroll';
import HomeHeader from './header';
import HomeSlider from './slider';


export default {
    name:"Home",
    components:{
        HomeHeader,
        HomeSlider,
        MeScroll
    }
}
</script>

<style lang="scss" scoped>
    // 引入前面需要加波浪线,否则会报错
    @import "~assets/scss/mixins";
    .home{
        overflow:hidden;
        width:100%;
        height:100%;
        background:$bgc-theme;
    }

</style>
<template>
    <div class="home">
        <header class="g-header-container">
            <!-- 没有内容自闭合即可-->
            <home-header/>
        </header> 
        <me-scroll>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
            <home-slider></home-slider>
        </me-scroll>
        <div class="g-backup-container"></div>
        <!-- 当前页面存在二级页面时需要使用router-view -->
        <router-view></router-view>
    </div>
</template>

<script>
import MeScroll from 'base/scroll';
import HomeHeader from './header';
import HomeSlider from './slider';


export default {
    name:"Home",
    components:{
        HomeHeader,
        HomeSlider,
        MeScroll
    }
}
</script>

<style lang="scss" scoped>
    // 引入前面需要加波浪线,否则会报错
    @import "~assets/scss/mixins";
    .home{
        overflow:hidden;
        width:100%;
        height:100%;
        background:$bgc-theme;
    }

</style>


import MeScroll from
;
import HomeHeader from
;
import HomeSlider from
;

export default {
name:
,
components:{
HomeHeader,
HomeSlider,
MeScroll
}
}
// 引入前面需要加波浪线,否则会报错;
.home{
overflow:hidden;
width:
;
height:
;
background:$bgc
theme;
}

 

这里添加这么多组轮播图是为了增高高度展示下轮播图效果

 

导航面板

在home目录中新建nav.vue

<template>
    <nav class="nav">
        <ul class="nav-list">
            <li class="nav-item" v-for="(item,index) in navs" :key="index">
                <a :href="item.linkUrl" class="nav-link">
                    <img :src="item.picUrl" alt="" class="nav-pic">
                    <span>{{item.text}}</span>
                </a>
            </li>
        </ul>
    </nav>
</template>

<script>
import {navItems} from './config.js';

export default {
    name:"HomeNav",
    components:{
        
    },
    props:{//过滤器
       
    },
    data(){
        return {
           
        }
    },
    created(){
        //不建议把这个数据放在data里,因为data里的数据都会添加getter和setter,而这里的数据并不需要实时响应变化,放在data里对资源是一种浪费
        this.navs=navItems;
    }
}
</script>

<style lang="scss" scoped>
    @import '~assets/scss/mixins';

    .nav{
        width:100%;
        margin-top:15px;
    }
    .nav-list{
        display:flex;
        flex-wrap:wrap;
    }
    .nav-item{
        width:20%;
    }
    .nav-link{
        @include flex-center(column);
        margin-bottom:15px;
    }
    .nav-pic{
        width:60%;
        margin-bottom:7px;
    }
     
</style>
<template>
    <nav class="nav">
        <ul class="nav-list">
            <li class="nav-item" v-for="(item,index) in navs" :key="index">
                <a :href="item.linkUrl" class="nav-link">
                    <img :src="item.picUrl" alt="" class="nav-pic">
                    <span>{{item.text}}</span>
                </a>
            </li>
        </ul>
    </nav>
</template>

<script>
import {navItems} from './config.js';

export default {
    name:"HomeNav",
    components:{
        
    },
    props:{//过滤器
       
    },
    data(){
        return {
           
        }
    },
    created(){
        //不建议把这个数据放在data里,因为data里的数据都会添加getter和setter,而这里的数据并不需要实时响应变化,放在data里对资源是一种浪费
        this.navs=navItems;
    }
}
</script>

<style lang="scss" scoped>
    @import '~assets/scss/mixins';

    .nav{
        width:100%;
        margin-top:15px;
    }
    .nav-list{
        display:flex;
        flex-wrap:wrap;
    }
    .nav-item{
        width:20%;
    }
    .nav-link{
        @include flex-center(column);
        margin-bottom:15px;
    }
    .nav-pic{
        width:60%;
        margin-bottom:7px;
    }
     
</style>

for
import {navItems} from
;

export default {
name:
,
components:{

},
props:{//过滤器
},
data(){
return {

}
},
created(){
//不建议把这个数据放在data里,因为data里的数据都会添加getter和setter,而这里的数据并不需要实时响应变化,放在data里对资源是一种浪费thisnavItems;
}
}

@import
;

.nav{
width:;
margin
top:15px;
}
.nav
list{
display:flex;
flex
wrap:wrap;
}
.nav
item{
width:
;
}
.nav
link{
@include flex
center(column);
margin
bottom:15px;
}
.nav
pic{
width:
;
margin
bottom:7px;
}

 

在index.vue中引入nav组件

<template>
    <div class="home">
        <header class="g-header-container">
            <!-- 没有内容自闭合即可-->
            <home-header/>
        </header> 
        <me-scroll>
            <home-slider />
            <home-nav></home-nav>
        </me-scroll>
        <div class="g-backup-container"></div>
        <!-- 当前页面存在二级页面时需要使用router-view -->
        <router-view></router-view>
    </div>
</template>

<script>
import MeScroll from 'base/scroll';
import HomeHeader from './header';
import HomeSlider from './slider';
import HomeNav from './nav';


export default {
    name:"Home",
    components:{
        HomeHeader,
        HomeSlider,
        MeScroll,
        HomeNav
    }
}
</script>

<style lang="scss" scoped>
    // 引入前面需要加波浪线,否则会报错
    @import "~assets/scss/mixins";
    .home{
        overflow:hidden;
        width:100%;
        height:100%;
        background:$bgc-theme;
    }

</style>
<template>
    <div class="home">
        <header class="g-header-container">
            <!-- 没有内容自闭合即可-->
            <home-header/>
        </header> 
        <me-scroll>
            <home-slider />
            <home-nav></home-nav>
        </me-scroll>
        <div class="g-backup-container"></div>
        <!-- 当前页面存在二级页面时需要使用router-view -->
        <router-view></router-view>
    </div>
</template>

<script>
import MeScroll from 'base/scroll';
import HomeHeader from './header';
import HomeSlider from './slider';
import HomeNav from './nav';


export default {
    name:"Home",
    components:{
        HomeHeader,
        HomeSlider,
        MeScroll,
        HomeNav
    }
}
</script>

<style lang="scss" scoped>
    // 引入前面需要加波浪线,否则会报错
    @import "~assets/scss/mixins";
    .home{
        overflow:hidden;
        width:100%;
        height:100%;
        background:$bgc-theme;
    }

</style>


import MeScroll from
;
import HomeHeader from
;
import HomeSlider from
;
import HomeNav from
;

export default {
name:
,
components:{
HomeHeader,
HomeSlider,
MeScroll,
HomeNav
}
}
// 引入前面需要加波浪线,否则会报错;
.home{
overflow:hidden;
width:
;
height:
;
background:$bgc
theme;
}

 

数据在config.js中

//暴露一个常量
export const sliderOptions={
    direction:"horizontal",
    loop:"loop",
    interval:1000,
    pagination:"pagination"
}

export const navItems=[
    {
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-1.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-2.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-3.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-4.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-5.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-6.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-7.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-8.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-9.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-10.png'),
        text:'团购'
    }
];
//暴露一个常量
export const sliderOptions={
    direction:"horizontal",
    loop:"loop",
    interval:1000,
    pagination:"pagination"
}

export const navItems=[
    {
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-1.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-2.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-3.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-4.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-5.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-6.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-7.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-8.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-9.png'),
        text:'团购'
    },{
        linkUrl:'www.baidu.com',
        picUrl:require('./img/nav-item-10.png'),
        text:'团购'
    }
];

//暴露一个常量{
direction:
,
loop:
,
interval:
,
pagination:

}

export const navItems[
{
linkUrl:
,
picUrl:require(
),
text:

},{
linkUrl:
,
picUrl:require(
),
text:

},{
linkUrl:
,
picUrl:require(
),
text:

},{
linkUrl:
,
picUrl:require(
),
text:

},{
linkUrl:
,
picUrl:require(
),
text:

},{
linkUrl:
,
picUrl:require(
),
text:

},{
linkUrl:
,
picUrl:require(
),
text:

},{
linkUrl:
,
picUrl:require(
),
text:

},{
linkUrl:
,
picUrl:require(
),
text:

},{
linkUrl:
,
picUrl:require(
),
text:

}
];

 

效果图

 

 

热卖推荐–jsonp封装

热卖推荐–jsonp封装

准备一个淘宝接口 

https://ju.taobao.com/json/tg/ajaxGetItemsV2.json
 

安装jsonp的库

cnpm install –save jsonp

 

 

封装jsonp方法

在assets–js下创建jsonp.js

import jsonp from 'jsonp';

/*data格式案例
{
    id:1,
    name:'cyy'
}
*/
const parseParam=param=>{
    /*将data格式转换为
    [
        [id,1],
        [name,cyy]
    ]
    */
    let arr=[];
    for(const key in param){
        arr.push([key,param[key]]);
    }
    /*先将data格式转换为
    [
        id=1,
        name=cyy
    ]
    */
   /*再将data格式转换为
    id=1&name=cyy
    */
    return arr.map(value=>value.join("=")).join('&');
}

export default (url,data,options)=>{
    // 如果存在?,则url后面加&;如果不存在则加?
    url+=((url.indexOf('?')<0) ? '?' : '&' ) + parseParam(data);

    return new Promise((resolve,reject)=>{
        
        //jsonp用法,三个参数:jsonp(url,options,callback)
        jsonp(url,options,(err,data)=>{
            if(err){
                reject(err);
            }else{
                resolve(data);
            }
        })
    })
}
import jsonp from 'jsonp';

/*data格式案例
{
    id:1,
    name:'cyy'
}
*/
const parseParam=param=>{
    /*将data格式转换为
    [
        [id,1],
        [name,cyy]
    ]
    */
    let arr=[];
    for(const key in param){
        arr.push([key,param[key]]);
    }
    /*先将data格式转换为
    [
        id=1,
        name=cyy
    ]
    */
   /*再将data格式转换为
    id=1&name=cyy
    */
    return arr.map(value=>value.join("=")).join('&');
}

export default (url,data,options)=>{
    // 如果存在?,则url后面加&;如果不存在则加?
    url+=((url.indexOf('?')<0) ? '?' : '&' ) + parseParam(data);

    return new Promise((resolve,reject)=>{
        
        //jsonp用法,三个参数:jsonp(url,options,callback)
        jsonp(url,options,(err,data)=>{
            if(err){
                reject(err);
            }else{
                resolve(data);
            }
        })
    })
}

;

/*data格式案例
{
id:1,
name:’cyy’
}
*/
const parseParam
{
/*将data格式转换为
[
[id,1],
[name,cyy]
]
*/
let arr
[];
forin param){
arr.push([key,param[key]]);
}
/*先将data格式转换为
[
id=1,
name=cyy
]
*//*再将data格式转换为
id=1&name=cyy
*/return);
}

export default{
// 如果存在?,则url后面加&;如果不存在则加? parseParam(data);

returnnew{

//jsonp用法,三个参数:jsonp(url,options,callback){
if(err){
reject(err);
}
else{
resolve(data);
}
})
})
}

 

在api / home.js中调用jsonp方法获取数据

import axios from 'axios';
import {SUCC_CODE,TIMEOUT,HOME_RECOMMEND_PAGE_SIZE,JSONP_OPTIONS} from './config';
import jsonp from 'assets/js/jsonp';

//获取幻灯片数据 ajax
export const getHomeSliders=()=>{
    // es6使用promise代替回调
    // axios返回的就是一个promise
    // return axios.get('http://www.imooc.com/api/home/slider').then(res=>{
    //     console.log(res);
    //     if(res.data.code===SUCC_CODE){
    //         return res.data.slider;
    //     }

    //     throw new Error('没有成功获取到数据');
    // }).catch(err=>{
    //     console.log(err);
    //     //错误处理
    //     return [{       
    //         linkUrl:'www.baidu.com',
    //         picUrl:require('assets/img/404.png')
    //     }]
    // });

    //演示超时错误
    return axios.get('http://www.imooc.com/api/home/slider',{
        timeout:TIMEOUT
    }).then(res=>{
        //console.log(res);
        if(res.data.code===SUCC_CODE){
            return res.data.slider;
        }

        throw new Error('没有成功获取到数据');
    }).catch(err=>{
        console.log(err);
        //错误处理
        return [{       
            linkUrl:'www.baidu.com',
            picUrl:require('assets/img/404.png')
        }]
    }).then(data=>{//获取轮播图数据后,延迟一秒再显示
        return new Promise(resolve=>{
            setTimeout(()=>{
                resolve(data);
            },1000);
        })
    });
}

//获取热门推荐数据
export const getHomeRecommend=(page=1,psize=HOME_RECOMMEND_PAGE_SIZE)=>{
    const url='https://ju.taobao.com/json/tg/ajaxGetItemsV2.json';
    const params={
        page,
        psize,
        type:0,
        frontCatId:''//type和frontCatId是根据给定的淘宝接口来添加的
    }

    //调用jsonp获取数据
    return jsonp(url,params,JSONP_OPTIONS).then(res=>{
        if(res.code==='200'){
            return res;
        }

        throw new Error('没有成功获取到数据');
    }).catch(err=>{
        if(err){
            console.log(err);
        }
        
    }).then(res=>{
        //延迟一秒返回数据
        return new Promise(resolve=>{
            setTimeout(()=>{
                resolve(res);
            },1000);
        })
    })
    
}
import axios from 'axios';
import {SUCC_CODE,TIMEOUT,HOME_RECOMMEND_PAGE_SIZE,JSONP_OPTIONS} from './config';
import jsonp from 'assets/js/jsonp';

//获取幻灯片数据 ajax
export const getHomeSliders=()=>{
    // es6使用promise代替回调
    // axios返回的就是一个promise
    // return axios.get('http://www.imooc.com/api/home/slider').then(res=>{
    //     console.log(res);
    //     if(res.data.code===SUCC_CODE){
    //         return res.data.slider;
    //     }

    //     throw new Error('没有成功获取到数据');
    // }).catch(err=>{
    //     console.log(err);
    //     //错误处理
    //     return [{       
    //         linkUrl:'www.baidu.com',
    //         picUrl:require('assets/img/404.png')
    //     }]
    // });

    //演示超时错误
    return axios.get('http://www.imooc.com/api/home/slider',{
        timeout:TIMEOUT
    }).then(res=>{
        //console.log(res);
        if(res.data.code===SUCC_CODE){
            return res.data.slider;
        }

        throw new Error('没有成功获取到数据');
    }).catch(err=>{
        console.log(err);
        //错误处理
        return [{       
            linkUrl:'www.baidu.com',
            picUrl:require('assets/img/404.png')
        }]
    }).then(data=>{//获取轮播图数据后,延迟一秒再显示
        return new Promise(resolve=>{
            setTimeout(()=>{
                resolve(data);
            },1000);
        })
    });
}

//获取热门推荐数据
export const getHomeRecommend=(page=1,psize=HOME_RECOMMEND_PAGE_SIZE)=>{
    const url='https://ju.taobao.com/json/tg/ajaxGetItemsV2.json';
    const params={
        page,
        psize,
        type:0,
        frontCatId:''//type和frontCatId是根据给定的淘宝接口来添加的
    }

    //调用jsonp获取数据
    return jsonp(url,params,JSONP_OPTIONS).then(res=>{
        if(res.code==='200'){
            return res;
        }

        throw new Error('没有成功获取到数据');
    }).catch(err=>{
        if(err){
            console.log(err);
        }
        
    }).then(res=>{
        //延迟一秒返回数据
        return new Promise(resolve=>{
            setTimeout(()=>{
                resolve(res);
            },1000);
        })
    })
    
}

;
import {SUCC_CODE,TIMEOUT,HOME_RECOMMEND_PAGE_SIZE,JSONP_OPTIONS} from
;
import jsonp from
;

//获取幻灯片数据 ajax{
// es6使用promise代替回调// axios返回的就是一个promise// return axios.get(‘http://www.imooc.com/api/home/slider’).then(res=>{// console.log(res);// if(res.data.code===SUCC_CODE){// return res.data.slider;// }// throw new Error(‘没有成功获取到数据’);// }).catch(err=>{// console.log(err);// //错误处理// return [{ // linkUrl:’www.baidu.com’,// picUrl:require(‘assets/img/404.png’)// }]// });//演示超时错误return,{
timeout:TIMEOUT
}).then(res
{
//console.log(res);ifSUCC_CODE){
return res.data.slider;
}

thrownew);
}).
catch{
console.log(err);
//错误处理return [{
linkUrl:
,
picUrl:require(
)
}]
}).then(data
//获取轮播图数据后,延迟一秒再显示returnnew{
setTimeout(()
{
resolve(data);
},
);
})
});
}

//获取热门推荐数据{
const url
;
const params
{
page,
psize,
type:
,
frontCatId:
//type和frontCatId是根据给定的淘宝接口来添加的 }

//调用jsonp获取数据return{
if){
return res;
}

thrownew);
}).
catch{
if(err){
console.log(err);
}

}).then(res{
//延迟一秒返回数据returnnew{
setTimeout(()
{
resolve(res);
},
);
})
})

}

 

api / config.js中添加常量

//获取轮播图
export const SUCC_CODE=0;
export const TIMEOUT=10000;

//获取热门推荐
export const HOME_RECOMMEND_PAGE_SIZE=20;
export const JSONP_OPTIONS={
    param:'callback',
    timeout:TIMEOUT
};
//获取轮播图
export const SUCC_CODE=0;
export const TIMEOUT=10000;

//获取热门推荐
export const HOME_RECOMMEND_PAGE_SIZE=20;
export const JSONP_OPTIONS={
    param:'callback',
    timeout:TIMEOUT
};

//获取轮播图;
export const TIMEOUT
;

//获取热门推荐;
export const JSONP_OPTIONS
{
param:
,
timeout:

};

 

在pages/home/recommend.vue中添加代码

<template>
    <div class="recommend">
        <h3 class="recommend-title">热卖推荐</h3>
        <div class="loading-container" v-if="!recommends.length">
            <!-- 完整写法是 inline:inline ,不过布尔值类型可以直接写 inline -->
            <me-loading inline />
        </div>
        <ul class="recommend-list">
            <li class="recommend-item" v-for="(item,index) in recommends" :key="index">
                <router-link class="recommend-link" :to="{name:'home-product',params:{id:item.baseinfo.itemId}}">
                    <p class="recommend-pic"><img class="recommend-img" :src="item.baseinfo.picUrl" alt=""></p>
                    <p class="recommend-name">{{item.name.shortName}}</p>
                    <p class="recommend-oriPrice"><del>¥{{item.price.origPrice}}</del></p>
                    <p class="recommend-info">
                        <span class="recommend-price">¥<strong class="recommend-price-num">{{item.price.actPrice}}</strong></span>
                        <span class="recommend-count">{{item.remind.soldCount}}件已售</span>
                    </p>
                </router-link>
            </li>
        </ul>
    </div>
</template>

<script>
import {getHomeRecommend} from 'api/home';
import MeLoading from 'base/loading';

export default {
    name:"HomeRecommend",
    data(){
        return {
           recommends:[],
           curPage:1,
           totalPage:1
        }
    },
    components:{
        MeLoading
    },
    created(){
        this.getRecommends();        
    },
    methods:{
        getRecommends(){
            
            if(this.curPage>this.totalPage) return Promise.reject(new Error('没有更多了'));

            getHomeRecommend(this.curPage).then(data=>{
                return new Promise(resolve=>{
              
                    if(data){
                        console.log(data);
                        
                        this.curPage++;
                        this.totalPage=data.totalPage;

                        // concat合并数组内容,每次获取的数据都追加进来
                        this.recommends=this.recommends.concat(data.itemList);

                        resolve();
                    }
                })
            });
        }
    }
}
</script>

<style lang="scss" scoped>
    @import '~assets/scss/mixins';

    .recommend{
        position:relative;
        width:100%;
        padding:10px 0;
        font-size:$font-size-l;
        text-align:center;

        &:before,
        &:after{
            content:"";
            display:block;
            position:absolute;
            top:50%;
            width:40%;
            height:1px;
            background:#ddd;
        }

        &:before{
            left:0;        
        }

        &:after{
            right:0;
        }
    }
    .recommend-list{
        @include flex-between();
        flex-wrap:wrap;
    }
    .recommend-title{
        margin-bottom:8px;
    }
    .recommend-item{
        width:49%;
        background:#fff;
        box-shadow:0 1px 1px 0 rgba(0,0,0,0.12);
        margin-bottom:8px;
    }
    .recommend-link{
        display:block;
    }
    .recommend-pic{
        position:relative;
        width:100%;
        padding-top:100%;// 可以实现高度与宽度一致
        margin-bottom:5px;
    }
    .recommend-img{
        width:100%;
        position:absolute;
        top:0;
        left:0;
        height:100%;
    }
    .recommend-name{
        height:40px;
        padding:0 5px;
        margin-bottom:8px;
        line-height:1.5;
        @include multiline-ellipsis();
        text-align:left;

    }
    .recommend-oriPrice{
        padding:0 5px;
        margin-bottom:8px;
        color:#ccc;

        del{

        }
    }
    .recommend-info{
        @include flex-between();
        padding:0 5px;
        margin-bottom:8px;
    }
    .recommend-price{
        color:#e61414;

        &-num{
            font-size:20px;
        }
    }
    .recommend-count{
        color:#999;
    }
    .loading-container{
        padding-top:150px;
    }
     
</style>
<template>
    <div class="recommend">
        <h3 class="recommend-title">热卖推荐</h3>
        <div class="loading-container" v-if="!recommends.length">
            <!-- 完整写法是 inline:inline ,不过布尔值类型可以直接写 inline -->
            <me-loading inline />
        </div>
        <ul class="recommend-list">
            <li class="recommend-item" v-for="(item,index) in recommends" :key="index">
                <router-link class="recommend-link" :to="{name:'home-product',params:{id:item.baseinfo.itemId}}">
                    <p class="recommend-pic"><img class="recommend-img" :src="item.baseinfo.picUrl" alt=""></p>
                    <p class="recommend-name">{{item.name.shortName}}</p>
                    <p class="recommend-oriPrice"><del>¥{{item.price.origPrice}}</del></p>
                    <p class="recommend-info">
                        <span class="recommend-price">¥<strong class="recommend-price-num">{{item.price.actPrice}}</strong></span>
                        <span class="recommend-count">{{item.remind.soldCount}}件已售</span>
                    </p>
                </router-link>
            </li>
        </ul>
    </div>
</template>

<script>
import {getHomeRecommend} from 'api/home';
import MeLoading from 'base/loading';

export default {
    name:"HomeRecommend",
    data(){
        return {
           recommends:[],
           curPage:1,
           totalPage:1
        }
    },
    components:{
        MeLoading
    },
    created(){
        this.getRecommends();        
    },
    methods:{
        getRecommends(){
            
            if(this.curPage>this.totalPage) return Promise.reject(new Error('没有更多了'));

            getHomeRecommend(this.curPage).then(data=>{
                return new Promise(resolve=>{
              
                    if(data){
                        console.log(data);
                        
                        this.curPage++;
                        this.totalPage=data.totalPage;

                        // concat合并数组内容,每次获取的数据都追加进来
                        this.recommends=this.recommends.concat(data.itemList);

                        resolve();
                    }
                })
            });
        }
    }
}
</script>

<style lang="scss" scoped>
    @import '~assets/scss/mixins';

    .recommend{
        position:relative;
        width:100%;
        padding:10px 0;
        font-size:$font-size-l;
        text-align:center;

        &:before,
        &:after{
            content:"";
            display:block;
            position:absolute;
            top:50%;
            width:40%;
            height:1px;
            background:#ddd;
        }

        &:before{
            left:0;        
        }

        &:after{
            right:0;
        }
    }
    .recommend-list{
        @include flex-between();
        flex-wrap:wrap;
    }
    .recommend-title{
        margin-bottom:8px;
    }
    .recommend-item{
        width:49%;
        background:#fff;
        box-shadow:0 1px 1px 0 rgba(0,0,0,0.12);
        margin-bottom:8px;
    }
    .recommend-link{
        display:block;
    }
    .recommend-pic{
        position:relative;
        width:100%;
        padding-top:100%;// 可以实现高度与宽度一致
        margin-bottom:5px;
    }
    .recommend-img{
        width:100%;
        position:absolute;
        top:0;
        left:0;
        height:100%;
    }
    .recommend-name{
        height:40px;
        padding:0 5px;
        margin-bottom:8px;
        line-height:1.5;
        @include multiline-ellipsis();
        text-align:left;

    }
    .recommend-oriPrice{
        padding:0 5px;
        margin-bottom:8px;
        color:#ccc;

        del{

        }
    }
    .recommend-info{
        @include flex-between();
        padding:0 5px;
        margin-bottom:8px;
    }
    .recommend-price{
        color:#e61414;

        &-num{
            font-size:20px;
        }
    }
    .recommend-count{
        color:#999;
    }
    .loading-container{
        padding-top:150px;
    }
     
</style>

iffor
import {getHomeRecommend} from
;
import MeLoading from
;

export default {
name:
,
data(){
return {
recommends:[],
curPage:
,
totalPage:

}
},
components:{
MeLoading
},
created(){
this.getRecommends();
},
methods:{
getRecommends(){

ifthisthisreturnnew));

getHomeRecommend(this{
returnnew{

if(data){
console.log(data);

this;
thisdata.totalPage;

// concat合并数组内容,每次获取的数据都追加进来thisthis.recommends.concat(data.itemList);

resolve();
}
})
});
}
}
}

@import
;

.recommend{
position:relative;
width:;
padding:10px
;
font
l;
text
align:center;

:before,
:after{
content:
;
display:block;
position:absolute;
top:
;
width:
;
height:1px;
background:#ddd;
}

:before{
left:
;
}

:after{
right:
;
}
}
.recommend
list{
@include flex
between();
flex
wrap:wrap;
}
.recommend
title{
margin
bottom:8px;
}
.recommend
item{
width:
;
background:#fff;
box
);
margin
bottom:8px;
}
.recommend
link{
display:block;
}
.recommend
pic{
position:relative;
width:
;
padding
// 可以实现高度与宽度一致bottom:5px;
}
.recommend
img{
width:
;
position:absolute;
top:
;
left:
;
height:
;
}
.recommend
name{
height:40px;
padding:
5px;
margin
bottom:8px;
line
;
@include multiline
ellipsis();
text
align:left;

}
.recommendoriPrice{
padding:
5px;
margin
bottom:8px;
color:#ccc;

del{

}
}
.recommendinfo{
@include flex
between();
padding:
5px;
margin
bottom:8px;
}
.recommend
price{
color:#e61414;

num{
font
size:20px;
}
}
.recommend
count{
color:#
;
}
.loading
container{
padding
top:150px;
}

 

src/pages/product.vue

<template>
    <div class="product">
        product
    </div>
</template>

<script>
export default {
   name:"Product"
}
</script>

<style lang="scss" scoped>
    @import '~assets/scss/_mixins';

    .product{
        overflow:hidden;
        position:absolute;
        top:0;
        left:0;
        width:100%;
        height:100%;
        background:#fff;
        z-index:$product-z-index;
    }
</style>
<template>
    <div class="product">
        product
    </div>
</template>

<script>
export default {
   name:"Product"
}
</script>

<style lang="scss" scoped>
    @import '~assets/scss/_mixins';

    .product{
        overflow:hidden;
        position:absolute;
        top:0;
        left:0;
        width:100%;
        height:100%;
        background:#fff;
        z-index:$product-z-index;
    }
</style>


product

export
default {
name:

}

@import
;

.product{
overflow:hidden;
position:absolute;
top:;
left:
;
width:
;
height:
;
background:#fff;
z
index;
}

 

效果图

 

 

 

更新滚动条

更新滚动条

由于热门推荐是异步加载的,热门推荐还没加载完时,滚动条已经加载完毕,因此滚动条无法获取到正确的热门推荐区域的高度,导致滚动条效果失效

因此当热门推荐加载完毕时,需要再次更新滚动条

 

1、recommend.vue中,热门推荐加载完成后,触发loaded消息并传递recommends数据

 

 2、接收触发的消息loaded,触发getRecommends函数

 

 3、在getRecommends函数中更新recommends数据

 

 4、让滚动条接收到recommends数据

 

 5、滚动条检测到数据变化,开始更新滚动条

 

 6、这里用到了swiper实例,需要在swiper元素上获取到

 

 7、滚动条效果回来啦!

 

图片的懒加载

图片的懒加载

1、安装lazyload插件  cnpm install –save vue-lazyload

 

2、在main.js中引入组件

 

 3、在recommend.vue中将:src改为v-lazy

 

 完美实现懒加载!

 

» 本文来自:前端开发者 » 《Vue webAPP首页开发(二)_蜡烛_前端开发者》
» 本文链接地址:https://www.rokub.com/73156.html
» 您也可以订阅本站:https://www.rokub.com
赞(0)
64K

评论 抢沙发

评论前必须登录!