开篇
直接说重点,本篇内容主要实现的功能有:导航栏tap切换、导航栏跟随滚动居中显示、手势滑动切换。
目前网上能看的讲解的多多少少有些问题,功能不够完整,走了很多弯路才调整成比较稳定效果和体验,开发过程中也借用了一些别人的案例。下面页面实现代码全部贴上,可直接copy套用。
1、js实现
js这部分页面触摸事件,通过触摸判断手势滑动的方向,重点在位置。
list页面不需要上下滚动,固定一屏的大小,只有左右滑动请使用:
this.starthDotX = e.touches[0].pageX;
this.starthDotY = e.touches[0].pageY;
list页面需要上下滚动,类似scroll-view效果,需上下左右滚动请使用:
如果list页面需要滚动,使用e.touches[0].pageX方法。list页面会上下滚动到某一个点的时候XY轴数据与实际滑动距离不符合,导致判断方法失效,上下滑动的同时突然执行左右滑动的操作,滑动的时候乱窜的情况
this.starthDotX = e.touches[0].clientX;
this.starthDotY = e.touches[0].clientY;
判断触摸手势方向的逻辑:
if(Math.abs(X) > Math.abs(Y) && X > 0 && Math.abs(X) > minOffset) {
console.log("向右滑动");
}else if(Math.abs(X) > Math.abs(Y) && X < 0 && Math.abs(X) > minOffset) {
console.log("向左滑动");
}else if(Math.abs(X) < Math.abs(Y) && Y > 0) {
console.log("向下滑动");
}else if(Math.abs(X) < Math.abs(Y) && Y < 0) {
console.log("向上滑动");
}
上代码:
var minOffset = 30;//最小偏移量,低于这个值不响应滑动处理
var DtaList0 = [{Name: "锦绣未央", url:"/image/timg0.jpg"},{Name: "锦民国往事", url:"/image/timg0.jpg"},{Name: "陈情令", url:"/image/timg0.jpg"}];
var DtaList1 = [{url:"/image/timg1.jpg", Name: "笑傲江湖"},{url:"/image/timg1.jpg", Name: "绣春刀"},{url:"/image/timg1.jpg", Name: "白夜追凶"},{url:"/image/timg1.jpg", Name: "三生三世"}];
var DtaList2 = [{url:"/image/timg2.jpg", Name: "法证先锋"},{url:"/image/timg2.jpg", Name: "无心法师"},{url:"/image/timg2.jpg", Name: "我是余欢水"}];
var DtaList3 = [{url:"/image/timg3.jpg", Name: "东宫"},{url:"/image/timg3.jpg", Name: "我只喜欢你"},{url:"/image/timg3.jpg", Name: "我只喜欢你"},{url:"/image/timg3.jpg", Name: "爱情公寓"}];
var DtaList4 = [{url:"/image/timg4.jpg", Name: "刘老根3"},{url:"/image/timg4.jpg", Name: "镇魂街"},{url:"/image/timg4.jpg", Name: "仙剑奇侠3"},{url:"/image/timg4.jpg", Name: "寻情记"}];
var DtaList5 = [{url:"/image/timg5.jpg", Name: "人民的正义"},{url:"/image/timg5.jpg", Name: "亮剑"}];
var DtaList6 = [{url:"/image/timg6.jpg", Name: "楚汉传奇"},{url:"/image/timg6.jpg",Name: "少帅"},{url:"/image/timg6.jpg",Name: "步步惊心"}];
var DtaList7 = [{url:"/image/timg7.jpg", Name: "大唐女法医"},{url:"/image/timg7.jpg", Name: "十二传说"}];
var DtaList8 = [{url:"/image/timg8.jpg", Name: "甄嬛传"},{url:"/image/timg8.jpg", Name: "萧十一郎"},{url:"/image/timg8.jpg", Name: "开国大典"}];
var DtaListArray = [DtaList0, DtaList1, DtaList2, DtaList3, DtaList4, DtaList5, DtaList6, DtaList7]
Page({
/*
* 页面的初始数据
*/
data: {
DtaList: [{}], //存放每个页面list数据
activeId: "", //记录导航栏tap的id
tabIndex: 0,//记录导航栏点击位置
starthDotX : 0, //触摸事件开始X轴的位置
starthDotY : 0,//触摸事件开始Y轴的位置
TypeList: [{posterId: 10561005, typeDesc: "央视网"},{posterId: 10561003, typeDesc: "爱奇艺"},{posterId: 10561008, typeDesc: "腾讯视频"},{posterId: 10561010, typeDesc: "PPTV"},{posterId: 10561002, typeDesc: "优酷"},{posterId: 10561007, typeDesc: "哔哩哔哩"}, {posterId: 10561006, typeDesc: "芒果TV"}, {posterId: 10561004, typeDesc: "西瓜视频"}] //导航栏假数据
},
/*****************************tap切换点击事件*****************************/
changeTab: function (e) {
var id = e.target.dataset.type;
var index = e.target.dataset.index;
//禁止tap重复点击
if(index == this.data.tabIndex){
return
}
//改变tap点击位置
this.setData({
activeId: id,
tabIndex:index,
DtaList: DtaListArray[index]
});
//当前tab点击栏居中显示
var singleNavWidth = this.data.windowWidth / 5;
this.setData({
navScrollLeft: (index - 2) * singleNavWidth
})
},
/*****************************触摸事件*****************************/
//触摸开始
touchstart: function(e){
// this.starthDotX = e.touches[0].pageX;
// this.starthDotY = e.touches[0].pageY;
this.starthDotX = e.touches[0].clientX;
this.starthDotY = e.touches[0].clientY;
},
//触摸进行中
touchmove: function(e){
var Direction = ""
// var moveDotX = e.touches[0].pageX;
// var moveDotY = e.touches[0].pageY;
var moveDotX = e.touches[0].clientX;
var moveDotY = e.touches[0].clientY;
var X = moveDotX - this.starthDotX;
var Y = moveDotY - this.starthDotY;
if(Math.abs(X) > Math.abs(Y) && X > 0 && Math.abs(X) > minOffset) {
Direction = "右滑"
}else if(Math.abs(X) > Math.abs(Y) && X < 0 && Math.abs(X) > minOffset) {
Direction = "左滑"
}else if(Math.abs(X) < Math.abs(Y) && Y > 0) {
Direction = "下滑"
}else if(Math.abs(X) < Math.abs(Y) && Y < 0) {
Direction = "上滑"
}
//记录当前滑动方向
this.setData({
glideDirection: Direction
})
},
//触摸结束
touchend: function(e){
if(this.data.glideDirection == "右滑"){
if(this.data.tabIndex !== 0){
var typeData = this.data.TypeList[this.data.tabIndex - 1];
var posterId = typeData.posterId;
//改变tap点击位置
this.setData({
activeId: posterId,
tabIndex: this.data.tabIndex - 1,
DtaList: DtaListArray[this.data.tabIndex - 1]
})
//新增tab点击当前栏居中显示
var singleNavWidth = this.data.windowWidth / 5;
this.setData({
navScrollLeft: (this.data.tabIndex - 2) * singleNavWidth
})
}else{
console.log("我是第一个滑不动啦,不要滑啦!!!")
}
}else if(this.data.glideDirection == "左滑"){
if(this.data.tabIndex !== this.data.TypeList.length -1){
var typeData = this.data.TypeList[this.data.tabIndex + 1];
var posterId = typeData.posterId;
//改变tap点击位置
this.setData({
activeId: posterId,
tabIndex: this.data.tabIndex + 1,
DtaList: DtaListArray[this.data.tabIndex + 1]
})
//tab点击当前栏居中显示
var singleNavWidth = this.data.windowWidth / 5;
this.setData({
navScrollLeft: (this.data.tabIndex - 2) * singleNavWidth
})
}else{
console.log("已经是最后一个啦,不要滑啦!!!")
}
}
},
//列表cell点击事件
clickBrand: function (e) {
var index = e.currentTarget.id;
var listData = this.data.DtaList[index];
console.log("当前点击的是:" + listData.Name)
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
//改变tap点击位置
this.setData({
activeId: '10561005',
DtaList: DtaList0
});
//新增获取屏幕Width
wx.getSystemInfo({
success: (res) => {
this.setData({
windowWidth: res.windowWidth
})
},
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {//页面已经显示出来
}
})
2、wxml实现
这部分没有太多难度,跟搭积木一样,一个view一个view的嵌套。
导航栏部分
原理:通过<scroll-view>控件实现,for循环每一个按钮,实现点击/滑动切换。
控件属性:scroll-left="{{navScrollLeft}} -> 用来控制当前点击栏滚动的位置,滚动居中效果。
list列表部分
原理:没有使用系统swiper组件,而是通过for循环<view>的形式实现。
控件属性:bindtouchstart="touchstart" / bindtouchmove="touchmove"/ bindtouchend="touchend" -> 监听list页面的触摸动作
上代码:
<scroll-view scroll-x="true" class="ip_tab_comtainer" scroll-with-animation="{{true}}" scroll-left="{{navScrollLeft}}">
<block wx:for="{{TypeList}}" wx:for-item="item" wx:ky = "*this" wx:for-index = "index">
<view class="ip_tab_item_n {{activeId == item.posterId?'active':''}}" bindtap="changeTab" data-type="{{item.posterId}}" data-index="{{index}}">{{item.typeDesc}}
</view>
</block>
</scroll-view>
<view class = "hotView" bindtouchstart="touchstart" bindtouchmove="touchmove" bindtouchend="touchend">
<view class = "hotCell" wx:for = "{{DtaList}}" wx:for-item='item' wx:for-index="dindex" wx:ky = "*this" bindtap = "clickBrand" id = "{{dindex}}">
<view class='imageBottomView'>
<image src="{{item.url}}"></image>
</view>
<view class='textBottom'>
<view class ="title" style="opacity:{{1}}">{{item.Name}}</view>
</view>
</view>
</view>
3、wxss实现
这部分没有太多可说的,样式自己慢慢去调。
上代码:
page{
background-color: #F1F1F1;
}
::-webkit-scrollbar{/*隐藏scrollerView滚动条*/
width: 0;
height: 0;
color: transparent;
}
.ip_tab_comtainer {
width: 100%;
display: flex;
position:fixed;
margin-bottom: 6rpx;
white-space: nowrap;
background-color: #ffffff;
}
.ip_tab_item_n {
display: inline-block;
margin: 0rpx 25rpx 0rpx 25rpx;
padding: 28rpx 0rpx 20rpx 0rpx;
color: #666666;
font-size: 32rpx;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
}
.active{
color: #F7353B;
border-bottom: 6rpx solid #F7353B;
}
.hotView {
display: flex;
flex-wrap: wrap;
padding-top: 120rpx;
}
.hotView .hotCell {
width: 46%;
text-align: center;
margin-bottom: 20rpx;
margin-left: 15rpx;
margin-right: 15rpx;
}
.imageBottomView{
width: 100%;
height: 450rpx;
}
.imageBottomView image{
width: 100%;
height: 100%;
border-radius: 5px 5px 0px 0px;
}
.textBottom{
height: 65rpx;
display: flex;
align-items: center;
background-color: white;
border-radius: 0px 0px 5px 5px;
}
.textBottom .title{
width: 65%;
color: #5E5E5E;
text-align: left;
font-size: 30rpx;
}
如有不足欢迎留言一起补充探讨 ~
网友评论