共计 3877 个字符,预计需要花费 10 分钟才能阅读完成。
最近公司要开发一套线上付费的会员 App,是和原生一起混合式的开发,有一个会员权益模块是全部使用 H5 开发,想给大家看下需要做成的案例:
其实没什么难点,主要就是功能有:1、顶部导航栏可以左右滑动,点击某一个栏目按钮内容跟着切换;2、并且加载一次之后,第二次就重新加载;3、被点击的栏目按钮居中显示,左右会跟随点击的位置滚动 4、手机物理返回按键对路由的影响
感觉自己表达不是特别的清楚,来一张动图把:
好了 废话不多说 开始说代码相关的东西了:
顶部导航的实现方案:
使用 swiper3 实现导航回弹和左右滑动效果
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 变量 这个用于记录路由的访问来源
2、在对应的路由文件里面添加路由卫士:
3、在 mounted 里面配置 popstate 和配置 goBack 方法:
4、销毁组件的时候 移除 popstate
我的三个路由的名称分别为:mpos、payPhoneBill、movieTicket,接下来看动图:
可以看到 我们只需要判断 global.beforeRouteName 和 路由的名称作为判断条件,就可以做任何操作和交互了,可以自己很好的控制物理键啦!
demo 在线预览:
demo 的代码地址:https://github.com/yulongwuko…