当前位置: 移动技术网 > IT编程>开发语言>JavaScript > Vue webAPP首页开发(五)

Vue webAPP首页开发(五)

2020年04月05日  | 移动技术网IT编程  | 我要评论

接上篇 

 

返回顶部组件

base/backtop/index.vue

<template>
    <transition name="mine-backtop">
        <a href="javascript:;" class="mine-backtop" v-show="visible" @click="backtotop">
            <i class="iconfont icon-backtop"></i>
        </a>
    </transition>
</template>

<script>
export default {
    name:"mebacktop",
    props:{
       visible:{
           type:boolean,
           default:false
       } 
    },
    methods:{
        backtotop(){
            this.$emit("backtop");//基础组件,与业务无关,具体实现去页面里
        }
    }
}
</script>

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

    .mine-backtop{
        overflow:hidden;
        @include flex-center();
        width:45px;
        height:45px;
        background:rgba(0,0,0,.6);
        border:none;
        border-radius:50%;
    }
    .iconfont{
       color:#fff;
       font-size:38px; 
    }
    .mine-backtop{
        &-enter-active,
        &-leave-active{
            transition:opacity 0.4s;
        }
        &-enter,
        &-leave-to{
            opacity:0;
        }
    }
</style>

 

pages/home/index.vue

<template>
    <div class="home">
        <header class="g-header-container">
            <!-- 没有内容自闭合即可-->
            <home-header/>
        </header> 
        <!-- 滚动条接收到数据后开始更新 -->
        <!-- pulldown是布尔值,可以使用简写直接传入,不加冒号 -->
        <!-- 接收到pull-down消息后,触发pulltorefresh方法 -->
        <me-scroll :data="recommends" pulldown pullup @pull-down="pulltorefresh" @pull-up="pulltoloadmore" @scroll-end="scrollend" ref="scroll">
            <home-slider ref="slider" />
            <home-nav />
            <!-- 接收热门推荐加载完毕的消息 -->
            <home-recommend @loaded="getrecommends" ref="recommend" />
        </me-scroll>
        <div class="g-backup-container">
            <me-backtop :visible="isbacktopvisible" @backtop="backtotop" />
        </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';
import homerecommend from './recommend';
import mebacktop from 'base/backtop';


export default {
    name:"home",
    components:{
        homeheader,
        homeslider,
        mescroll,
        homenav,
        homerecommend,
        mebacktop
    },
    data(){
        return{
            recommends:[],
            isbacktopvisible:false
        }
    },
    methods:{
        getrecommends(recommends){
            this.recommends=recommends;
        },
        updatescroll(){

        },
        pulltorefresh(end){
            this.$refs.slider.update().then(end);
        },
        pulltoloadmore(end){
            this.$refs.recommend.update().then(end).catch(err=>{
                //没有更多内容时
                if(err){
                    console.log(err);
                }
                end();
                //禁止继续加载更多数据
                //替换上拉时的loading,改为“没有更多数据了”
            });
        },
        scrollend(translate,scroll){
            // translate<0向下拉
            // -translate>scroll.height拉过的距离大于一屏的高度
            this.isbacktopvisible=translate<0 && -translate>scroll.height;
        },
        backtotop(){
            this.$refs.scroll && this.$refs.scroll.scrolltotop();
        }
    }
}
</script>

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

</style>

 

修改assets/scss/_containers.scss(之前写错了)

 

 

效果图

 

header动画效果和显示隐藏

pages/home/header.vue

<template>
    <div>
        <me-navbar class="header" v-show="visible">
            <i class="iconfont icon-scan" slot="left"></i>
            <div slot="center">搜索框</div>
            <i class="iconfont icon-msg" slot="right"></i>
        </me-navbar>
    </div>
</template>

<script>
import menavbar from 'base/navbar';
export default {
   name:"homeheader",
   components:{
       menavbar
   },
   data(){
       return{
           visible:true
       }
   },
   methods:{
       show(){
           this.visible=true;
       },
       hide(){
           this.visible=false;
       }
   }
}
</script>

<style lang="scss" scoped>
    // 引入前面需要加波浪线,否则会报错
    @import "~assets/scss/mixins";
    .header{
        &.mine-navbar{
            background:transparent;
            transition:background-color 0.5s;
        }

        .iconfont{
            font-size:$icon-font-size;
            color:$icon-color-default;
        }

        
    }

    .header-transition .header.mine-navbar{
        background-color:$header-bgc-translucent;
    }
    
    
</style>

 

base/scroll/index.vue

<template>
    <!-- wiper会实例化构造函数,生成swiper实例 -->
    <!-- ref="swiper"能够获取到这个swiper实例 -->
    <swiper :options="swiperoption" ref='swiper'>
        <div class="mine-scroll-pull-down" v-if="pulldown">
            <!-- ref="pulldownloading" -- 获取下拉的loading -->
            <me-loading :text="pulldowntext" inline ref="pulldownloading" />
        </div>
        <swiper-slide>
            <slot></slot>
        </swiper-slide>
        <div class="mine-scroll-pull-up" v-if="pullup">
            <!-- ref="pulluploading" -- 获取上拉的loading -->
            <me-loading :text="pulluptext" inline ref="pulluploading" />
        </div>
        <div class="swiper-scrollbar" v-if="scrollbar" slot="scrollbar"></div>
    </swiper>
</template>

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

import {
    pull_down_height,
    pull_down_text_init,
    pull_down_text_start,
    pull_down_text_ing,
    pull_down_text_end,
    pull_up_height,
    pull_up_text_init,
    pull_up_text_start,
    pull_up_text_ing,
    pull_up_text_end
} from './config';

export default {
    name:"mescroll",
    components:{
        swiper,
        swiperslide,
        meloading
    },
    props:{//过滤器
       scrollbar:{
           type:boolean,
           default:true
       },
       data:{//热门推荐加载完成后传递过来的recommends数据
           type:[array,object]         
       },
       pulldown:{//是真就开启下拉刷新
           type:boolean,
           default:false
       },
       pullup:{//是真就开启下拉加载
           type:boolean,
           default:false
       }
    },
    methods:{
        update(){//不知道怎么写就去swiper官网查api
            //console.log(this.$refs.swiper);//打印swiper实例

            this.$refs.swiper && this.$refs.swiper.$swiper.update();//调用swiper.update()更新滚动条
        },
        scrolltotop(speed,runcallback){
            // slideto回到第x张幻灯片,swiper的api提供的
            this.$refs.swiper && this.$refs.swiper.$swiper.slideto(0,speed,runcallback);
        },
        init(){
            //将不需要设置getter和setter的数据,放在init中初始化即可
            this.pulling=false;//是否正在下拉
            this.pulldowntext=pull_down_text_init;//设置下拉初始化文字
            this.pulluptext=pull_up_text_init;//设置上拉初始化文字
            this.swiperoption={
                direction:'vertical',//垂直方向
                slidesperview:'auto',//一次显示几张
                freemode:true,//任意滑动多少距离
                setwrappersize:true,//根据内容设置容器尺寸
                scrollbar:{
                    el:this.scrollbar?'.swiper-scrollbar':null,
                    hide:true //滚动条自动隐藏
                },
                on:{
                    //swiper配置时会触发slidermove方法,这里调用时执行自定义的scroll方法
                    slidermove:this.scroll,
                    touchend:this.touchend,//touchend是swiper提供的滚动结束的函数,this.touchend是我们自己写的函数,
                    transitionend:this.scrollend
                }

            };

        },
        scroll(){
            const swiper=this.$refs.swiper.$swiper;

            //滚动时触发scroll事件
            this.$emit("scroll",swiper.translate,this.$refs.swiper.$swiper);

            //如果正在下拉中,不会再次执行
            if(this.pulling) return;

            //console.log(swiper.translate);//打印出滚动条滚过的距离
            if(swiper.translate>0){//下拉
                if(!this.pulldown){//如果不需要下拉刷新
                    return;
                }
                if(swiper.translate>pull_down_height){
                    this.$refs.pulldownloading.settext(pull_down_text_start);
                }else{
                    this.$refs.pulldownloading.settext(pull_down_text_init);
                }
            }else if(swiper.isend){//上拉
                if(!this.pullup){
                    return;
                }

                //是否达到上拉的触发条件
                //swiper的位移加上swiper的高度(617px)-50px的值如果大于当前内容高度
                //swiper.translate这个属性可以获取到wrapper的位移,其实可以理解为滚动条滚动的距离
                //swiper.height这个属性获取swiper容器的高度, 也就是显示区域的高度
                //pull_up_height是我们设置的一个值。为了让页面不是到达最低部的时候,可以提前加载内容
                //parseint(swiper.$wrapperel.css('height'))是wrapper的html元素的height属性, 也就是所有内容的高度
                const ispullup=math.abs(swiper.translate)+swiper.height-pull_up_height>parseint(swiper.$wrapperel.css('height'));

                if(ispullup){//开始上拉
                    this.$refs.pulluploading.settext(pull_up_text_start);
                }else{//保持初始化
                    this.$refs.pulluploading.settext(pull_up_text_init);
                }
            }
        },
        scrollend(){
            this.$emit("scroll-end",this.$refs.swiper.$swiper.translate,this.$refs.swiper.$swiper,this.pulling);
        },
        touchend(){
            const swiper=this.$refs.swiper.$swiper;

            //如果正在下拉中,不会再次执行
            if(this.pulling) return;           

            if(swiper.translate>pull_down_height){//如果距离大于设定的距离
                if(!this.pulldown){//如果不需要下拉刷新
                    return;
                }
                this.pulling=true;

                swiper.allowtouchmove=false;//禁止触摸
                swiper.settransition(swiper.params.speed);//设置初始速度
                swiper.settranslate(pull_down_height);//移动到设定的位置(拖动过度时回到设置的位置)
                swiper.params.virtualtranslate=true;//定住不给回弹
                this.$refs.pulldownloading.settext(pull_down_text_ing);//设置正在刷新中的文字
                this.$emit("pull-down",this.pulldownend);//触发消息,传递结束下拉的函数
            }else if(swiper.isend){//上拉
                //是否达到上拉的触发条件
                const ispullup=math.abs(swiper.translate)+swiper.height-pull_up_height>parseint(swiper.$wrapperel.css('height'));

                if(ispullup){//开始上拉
                    if(!this.pullup){//如果不需要上拉刷新
                        return;
                    }
                    
                    this.pulling=true;

                    swiper.allowtouchmove=false;//禁止触摸
                    swiper.settransition(swiper.params.speed);//设置初始速度
                    swiper.settranslate(-(parseint(swiper.$wrapperel.css('height'))+pull_up_height-swiper.height));//超过拉动距离时回弹
                    swiper.params.virtualtranslate=true;//定住不给回弹
                    this.$refs.pulluploading.settext(pull_up_text_ing);//设置正在刷新中的文字
                    this.$emit("pull-up",this.pullupend);//触发消息,传递结束下拉的函数
                }
            }
        },
        pulldownend(){
            const swiper=this.$refs.swiper.$swiper;

            this.pulling=false;

            this.$refs.pulldownloading.settext(pull_down_text_end);//设置加载结束后的文字
            swiper.allowtouchmove=true;//可以触摸
            swiper.settransition(swiper.params.speed);//设置初始速度           
            swiper.params.virtualtranslate=false;//可以回弹
            swiper.settranslate(0);//移动到最初的位置

            //下拉完成后,显示head组件(下拉过程中会被隐藏)
            settimeout(()=>{
                this.$emit("pull-down-transition-end");
            },swiper.params.speed);
        },
        pullupend(){
            const swiper=this.$refs.swiper.$swiper;

            this.pulling=false;

            this.$refs.pulluploading.settext(pull_up_text_end);//设置加载结束后的文字
            swiper.allowtouchmove=true;//可以触摸           
            swiper.params.virtualtranslate=false;//可以回弹
        }
    },
    watch:{//检测数据变化的事件
        data(){
            this.update();//data数据变化时执行update函数
        }
    },
    created(){//在created中初始化数据
        this.init();
    }
}
</script>

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

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

        & .swiper-slide{
            height:auto;
        }  
    }
    //默认是不显示的
    .mine-scroll-pull-down{
        position:absolute;
        left:0;
        bottom:100%;
        width:100%;
        height:80px;
    }
    .mine-scroll-pull-up{
        position:absolute;
        left:0;
        top:100%;
        width:100%;
        height:30px;
    }
     
</style>

 

pages/home/config.js

 

 

pages/home/index.vue

<template>
    <div class="home">
        <header class="g-header-container">
            <!-- 没有内容自闭合即可-->
            <!-- ref用来获取到组件 -->
            <home-header :class="{'header-transition':isheadertransition}" ref="header" />
        </header> 
        <!-- 滚动条接收到数据后开始更新 -->
        <!-- pulldown是布尔值,可以使用简写直接传入,不加冒号 -->
        <!-- 接收到pull-down消息后,触发pulltorefresh方法 -->
        <me-scroll :data="recommends" pulldown pullup @pull-down="pulltorefresh" @pull-up="pulltoloadmore" @scroll="scroll" @scroll-end="scrollend" @pull-down-transition-end="pulldowntransitionend" ref="scroll">
            <home-slider ref="slider" />
            <home-nav />
            <!-- 接收热门推荐加载完毕的消息 -->
            <home-recommend @loaded="getrecommends" ref="recommend" />
        </me-scroll>
        <div class="g-backup-container">
            <me-backtop :visible="isbacktopvisible" @backtop="backtotop" />
        </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';
import homerecommend from './recommend';
import mebacktop from 'base/backtop';
import {header_transition_height} from './config';


export default {
    name:"home",
    components:{
        homeheader,
        homeslider,
        mescroll,
        homenav,
        homerecommend,
        mebacktop
    },
    data(){
        return{
            recommends:[],
            isbacktopvisible:false,
            isheadertransition:false
        }
    },
    methods:{
        getrecommends(recommends){
            this.recommends=recommends;
        },
        updatescroll(){

        },
        pulltorefresh(end){
            this.$refs.slider.update().then(end);
        },
        pulltoloadmore(end){
            this.$refs.recommend.update().then(end).catch(err=>{
                //没有更多内容时
                if(err){
                    console.log(err);
                }
                end();
                //禁止继续加载更多数据
                //替换上拉时的loading,改为“没有更多数据了”
            });
        },
        scroll(translate){
            this.changeheaderstatus(translate);
        },
        scrollend(translate,scroll,pulling){
            if(!pulling){
                this.changeheaderstatus(translate);
            }
            // translate<0向下拉
            // -translate>scroll.height拉过的距离大于一屏的高度
            this.isbacktopvisible=translate<0 && -translate>scroll.height;
            
        },
        backtotop(){
            this.$refs.scroll && this.$refs.scroll.scrolltotop();
        },
        changeheaderstatus(translate){
            if(translate>0){//上拉
                this.$refs.header.hide();
                return;
            }

            this.$refs.header.show();
            this.isheadertransition=-translate>header_transition_height;
        },
        pulldowntransitionend(){//下拉完成之后显示导航条
            this.$refs.header.show();
        }
    }
}
</script>

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

</style>

 

api/home.js

import axios from 'axios';
import {succ_code,timeout,home_recommend_page_size,jsonp_options} from './config';
import jsonp from 'assets/js/jsonp';

// shuffle打乱数组顺序的方法
const shuffle=(arr)=>{
    const arrlength=arr.length;
    let i=arrlength;
    let rndnum;

    while(i--){
        //如果当前索引不等于随机数索引,则交换这两个索引的位置
        if(i!==(rndnum=math.floor(math.random()*arrlength))){
            //这是一种新的交换写法 es6解构
            [arr[i],arr[rndnum]]=[arr[rndnum],arr[i]];
        }
    }
    return arr;
}

//获取幻灯片数据 ajax
export const gethomesliders=()=>{

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

            //这段代码的作用主要是演示下拉刷新的效果
            //每次刷新会加载出不同数量,不同顺序的轮播图
            let sliders=res.data.slider;
            const slider=[sliders[math.floor(math.random()*sliders.length)]];//slider是从sliders中随机取出一张图片,并包装成数组
            sliders=shuffle(sliders.filter(()=>math.random()>=0.5));//50%的概率,真就返回,假就剔除
            if(sliders.length===0){
                sliders=slider;//如果不幸一张都没有,就把之前随机的那张赋值给sliders
            }
            return sliders;

            //return res.data.slider;
        }

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

//获取热门推荐数据
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);
        }
        
    });
    
}

 

效果图

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网