一個類似於京東Plus權益介紹的小功能

最近公司要開發一套線上付費的會員App,是和原生一起混合式的開發,有一個會員權益模塊是全部使用H5開發,想給大家看下需要做成的案例:

clipboard.png

其實沒什麼難點,主要就是功能有:
1、頂部導航欄可以左右滑動,點擊某一個欄目按鈕內容跟着切換;
2、並且加載一次之後,第二次就重新加載;
3、被點擊的欄目按鈕居中顯示,左右會跟隨點擊的位置滾動
4、手機物理返回按鍵對路由的影響

感覺自己表達不是特別的清楚,來一張動圖把:

圖片描述

好了 廢話不多說 開始說代碼相關的東西了:

頂部導航的實現方案:

使用 swiper3 實現導航回彈和左右滑動效果

clipboard.png

html內容:

<div class="rightsProfile">
            <div class="rightsProfile_head">
                <div id="nav" class="swiper-container">
                    <ul class="swiper-wrapper">
                        <li :key="i" v-for="i in myNavBar" :class="{'active-nav':i.active}" class="swiper-slide">
                            {{i.title}}
                        </li>
                    </ul>
                </div>
            </div>
        </div>

我使用了vuejs的循環渲染li

swiper.js的調用:

               var myNav = new Swiper('#nav', {
                    freeMode: true,
                    freeModeMomentumRatio: 0.5,
                    slidesPerView: '3',
                });
                let swiperWidth = myNav.container[0].clientWidth
                let maxTranslate = myNav.maxTranslate();
                let maxWidth = -maxTranslate + swiperWidth / 2

                myNav.on("tap",function(swiper,e){
                    
                    let slide = swiper.slides[swiper.clickedIndex]
                    let slideLeft = slide.offsetLeft
                    let slideWidth = slide.clientWidth
                    let slideCenter = slideLeft + slideWidth / 2;

                    // 被點擊slide的中心點
                    myNav.setWrapperTransition(300)
                    if (slideCenter < swiperWidth / 2) {
                        myNav.setWrapperTranslate(0)
                    } else if (slideCenter > maxWidth) {
                        myNav.setWrapperTranslate(maxTranslate)
                    } else {
                        let nowTlanslate = slideCenter - swiperWidth / 2
                        myNav.setWrapperTranslate(-nowTlanslate)
                    }

                })

上面的代碼就可以實現1、3的要求了 我上傳的代碼不是很全,細節代碼我會附上github地址。

我們接下來看第2個要求,就是點擊加載一次之後,再次點擊不會重新加載,這裏我使用了vue-router

結構如下:

<template>
  <div id="page">

          <Loading :isLoading="isLoading"></Loading>

        <div class="rightsProfile">
            <div class="rightsProfile_head">
                <div id="nav" class="swiper-container">
                    <ul class="swiper-wrapper">
                        <li :key="i" v-for="i in myNavBar" :class="{'active-nav':i.active}" class="swiper-slide">
                            {{i.title}}
                        </li>
                    </ul>
                </div>
            </div>
        </div>

        <keep-alive>
            <router-view v-if="$route.meta.keepAlive">
                <!-- 這裏是會被緩存的視圖組件,比如 page1,page2 -->
            </router-view>
        </keep-alive>

        <router-view v-if="!$route.meta.keepAlive">
            <!-- 這裏是不被緩存的視圖組件,比如 page3 -->
        </router-view>
  </div>
</template>

<style lang="less">
    #nav{
        height: 100%;
        .swiper-wrapper{
            height: 100%;
            li{
                text-align: center;
                height: 100%;
                display: flex;
                align-items: center;
                justify-content: center;
                &.active-nav{
                    color:#fff;
                    background:#ddd !important;
                }
                &.active-nav a{
                    color:#fff;
                    background:#ddd !important;
                }
            }
        }
    }
    
</style>

<script>
    import Loading from "@/components/loading";
    export default{
        data(){
            return{
                myNavBar:[{
                        title:"移動機具",
                        active:true,
                        mark:"mpos"
                    },{
                        title:"8折話費",
                        active:false,
                        mark:"payPhoneBill"
                    },{
                        title:"5折看電影",
                        active:false,
                        mark:"movieTicket"
                    },{
                        title:"家用",
                        active:false
                    },{
                        title:"家用電器",
                        active:false
                    },{
                        title:"家用",
                        active:false
                    }],
                routerName:""
            }
        },
        components:{
            Loading
        },
        watch: {
            $route(to, from) {
                // console.log(this.$route.name);
                let routerName = this.$route.name;
                this.myNavBar.map((el)=>{
                    el.active = false;
                    if(el.mark==routerName){
                        el.active = true;
                    }
                });
            }
        },    
        mounted(){

            this.$nextTick(()=>{

                let that = this;
                var myNav = new Swiper('#nav', {
                    freeMode: true,
                    freeModeMomentumRatio: 0.5,
                    slidesPerView: '3',
                });
                let swiperWidth = myNav.container[0].clientWidth
                let maxTranslate = myNav.maxTranslate();
                let maxWidth = -maxTranslate + swiperWidth / 2

                myNav.on("tap",function(swiper,e){
                    
                    let slide = swiper.slides[swiper.clickedIndex]
                    let slideLeft = slide.offsetLeft
                    let slideWidth = slide.clientWidth
                    let slideCenter = slideLeft + slideWidth / 2;

                    // 被點擊slide的中心點
                    myNav.setWrapperTransition(300)
                    if (slideCenter < swiperWidth / 2) {
                        myNav.setWrapperTranslate(0)
                    } else if (slideCenter > maxWidth) {
                        myNav.setWrapperTranslate(maxTranslate)
                    } else {
                        let nowTlanslate = slideCenter - swiperWidth / 2
                        myNav.setWrapperTranslate(-nowTlanslate)
                    }

                    that.myNavBar.map((el)=>{
                        el.active = false;
                    });
                    that.myNavBar[swiper.clickedIndex].active = true;
                    that.$router.push({
                        path:that.myNavBar[swiper.clickedIndex].mark
                    })

                })
            })    
        }
    }
</script>

頭部導航在主路由裏面,router-view顯示每個欄目對應的內容,可以給每個路由設置keep-alive,實現條件3。

從事移動端web開發的小夥伴們應該對手機的物理返回鍵“深惡痛絕”把,同樣我們做完了上面那個demo,當你點擊安卓的物理返回鍵的時候,demo會一步一步的返回,顯然,這不是我們要的結果,我們要的效果應該是“指哪打哪,自我掌控

1、首先,我們新建一個 global變量 這個用於記錄路由的訪問來源

clipboard.png

2、在對應的路由文件裏面添加路由衛士:

clipboard.png

3、在mounted裏面配置popstate和配置goBack方法:

clipboard.png

4、銷燬組件的時候 移除popstate

clipboard.png

我的三個路由的名稱分別爲:mpos、payPhoneBill、movieTicket,接下來看動圖:

圖片描述

可以看到 我們只需要判斷 global.beforeRouteName 和 路由的名稱作爲判斷條件,就可以做任何操作和交互了,可以自己很好的控制物理鍵啦!

demo在線預覽:

clipboard.png

demo的代碼地址:https://github.com/yulongwuko...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章