微信小程序?qū)崿F(xiàn)tap切換(可手勢(shì)滑動(dòng)、導(dǎo)航跟隨滾動(dòng))

demo效果.gif

開篇

直接說重點(diǎn)堆巧,本篇內(nèi)容主要實(shí)現(xiàn)的功能有:導(dǎo)航欄tap切換妄荔、導(dǎo)航欄跟隨滾動(dòng)居中顯示、手勢(shì)滑動(dòng)切換谍肤。
目前網(wǎng)上能看的講解的多多少少有些問題啦租,功能不夠完整,走了很多彎路才調(diào)整成比較穩(wěn)定效果和體驗(yàn)荒揣,開發(fā)過程中也借用了一些別人的案例篷角。下面頁面實(shí)現(xiàn)代碼全部貼上,可直接copy套用系任。

?

1恳蹲、js實(shí)現(xiàn)

js這部分\color{rgb(255,0,0)}{特別強(qiáng)調(diào)}頁面觸摸事件,通過觸摸判斷手勢(shì)滑動(dòng)的方向赋除,重點(diǎn)在\color{rgb(255,0,0)}{獲取手勢(shì)觸摸XY軸坐標(biāo)}位置阱缓。

list頁面不需要上下滾動(dòng),固定一屏的大小举农,只有左右滑動(dòng)請(qǐng)使用:
this.starthDotX = e.touches[0].pageX;
this.starthDotY = e.touches[0].pageY;

list頁面需要上下滾動(dòng)荆针,類似scroll-view效果,需上下左右滾動(dòng)請(qǐng)使用:
如果list頁面需要滾動(dòng)颁糟,使用e.touches[0].pageX方法航背。list頁面會(huì)上下滾動(dòng)到某一個(gè)點(diǎn)的時(shí)候XY軸數(shù)據(jù)與實(shí)際滑動(dòng)距離不符合,導(dǎo)致判斷方法失效棱貌,上下滑動(dòng)的同時(shí)突然執(zhí)行左右滑動(dòng)的操作玖媚,滑動(dòng)的時(shí)候亂竄的情況
this.starthDotX = e.touches[0].clientX;
this.starthDotY = e.touches[0].clientY;

判斷觸摸手勢(shì)方向的邏輯:
if(Math.abs(X) > Math.abs(Y) && X > 0 && Math.abs(X) > minOffset) {
console.log("向右滑動(dòng)");
}else if(Math.abs(X) > Math.abs(Y) && X < 0 && Math.abs(X) > minOffset) {
console.log("向左滑動(dòng)");
}else if(Math.abs(X) < Math.abs(Y) && Y > 0) {
console.log("向下滑動(dòng)");
}else if(Math.abs(X) < Math.abs(Y) && Y < 0) {
console.log("向上滑動(dòng)");
}

上代碼:

var minOffset = 30;//最小偏移量,低于這個(gè)值不響應(yīng)滑動(dòng)處理

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: "鎮(zhèn)魂街"},{url:"/image/timg4.jpg", Name: "仙劍奇?zhèn)b3"},{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: "大唐女法醫(yī)"},{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({
  /*
   * 頁面的初始數(shù)據(jù)
   */
  data: {
    DtaList: [{}], //存放每個(gè)頁面list數(shù)據(jù)
    activeId: "", //記錄導(dǎo)航欄tap的id
    tabIndex: 0,//記錄導(dǎo)航欄點(diǎn)擊位置
    starthDotX : 0, //觸摸事件開始X軸的位置
    starthDotY : 0,//觸摸事件開始Y軸的位置

    TypeList: [{posterId: 10561005, typeDesc: "央視網(wǎng)"},{posterId: 10561003, typeDesc: "愛奇藝"},{posterId: 10561008, typeDesc: "騰訊視頻"},{posterId: 10561010, typeDesc: "PPTV"},{posterId: 10561002, typeDesc: "優(yōu)酷"},{posterId: 10561007, typeDesc: "嗶哩嗶哩"}, {posterId: 10561006, typeDesc: "芒果TV"}, {posterId: 10561004, typeDesc: "西瓜視頻"}]   //導(dǎo)航欄假數(shù)據(jù)
  },

/*****************************tap切換點(diǎn)擊事件*****************************/
  changeTab: function (e) {
    var id = e.target.dataset.type;
    var index = e.target.dataset.index;

    //禁止tap重復(fù)點(diǎn)擊
    if(index == this.data.tabIndex){
      return
    }

    //改變tap點(diǎn)擊位置
    this.setData({
      activeId: id,
      tabIndex:index, 
      DtaList: DtaListArray[index]
    });

    //當(dāng)前tab點(diǎn)擊欄居中顯示
    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;
  },
    
  //觸摸進(jìn)行中
  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 = "上滑"
    } 

    //記錄當(dāng)前滑動(dòng)方向
    this.setData({
      glideDirection: Direction 
    })
  },

  //觸摸結(jié)束
  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點(diǎn)擊位置
        this.setData({
          activeId: posterId,
          tabIndex: this.data.tabIndex - 1,
          DtaList: DtaListArray[this.data.tabIndex - 1]
        })

        //新增tab點(diǎn)擊當(dāng)前欄居中顯示
        var singleNavWidth = this.data.windowWidth / 5;
        this.setData({
           navScrollLeft: (this.data.tabIndex - 2) * singleNavWidth
        }) 
      }else{
        console.log("我是第一個(gè)滑不動(dòng)啦婚脱,不要滑啦=衲АI紫瘛!")
      }
    }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點(diǎn)擊位置
        this.setData({
          activeId: posterId,
          tabIndex: this.data.tabIndex + 1,
          DtaList: DtaListArray[this.data.tabIndex + 1]
        })

        //tab點(diǎn)擊當(dāng)前欄居中顯示
        var singleNavWidth = this.data.windowWidth / 5;
        this.setData({
           navScrollLeft: (this.data.tabIndex - 2) * singleNavWidth
        }) 
      }else{
        console.log("已經(jīng)是最后一個(gè)啦错森,不要滑啦R骰隆!涩维!")
      }
    }
  },


  //列表cell點(diǎn)擊事件
  clickBrand: function (e) {
    var index = e.currentTarget.id;
    var listData = this.data.DtaList[index];
    console.log("當(dāng)前點(diǎn)擊的是:" + listData.Name)
  },

  /**
   * 生命周期函數(shù)--監(jiān)聽頁面加載
   */
  onLoad: function (options) {
    //改變tap點(diǎn)擊位置
    this.setData({
      activeId: '10561005',
      DtaList: DtaList0
    });
    
    //新增獲取屏幕Width
    wx.getSystemInfo({
      success: (res) => {
          this.setData({
              windowWidth: res.windowWidth
          })
      },
    })       
  },

  /**
   * 生命周期函數(shù)--監(jiān)聽頁面初次渲染完成
   */
  onReady: function () {
    
  },
  
  /**
   * 生命周期函數(shù)--監(jiān)聽頁面顯示
   */
  onShow: function () {//頁面已經(jīng)顯示出來
    
  }
})

?

2殃姓、wxml實(shí)現(xiàn)

這部分沒有太多難度,跟搭積木一樣瓦阐,一個(gè)view一個(gè)view的嵌套蜗侈。

導(dǎo)航欄部分
原理:通過<scroll-view>控件實(shí)現(xiàn),for循環(huán)每一個(gè)按鈕睡蟋,實(shí)現(xiàn)點(diǎn)擊/滑動(dòng)切換踏幻。
控件屬性:scroll-left="{{navScrollLeft}} -> 用來控制當(dāng)前點(diǎn)擊欄滾動(dòng)的位置,滾動(dòng)居中效果薄湿。

list列表部分
原理:沒有使用系統(tǒng)swiper組件叫倍,而是通過for循環(huán)<view>的形式實(shí)現(xiàn)。
控件屬性:bindtouchstart="touchstart" / bindtouchmove="touchmove"/ bindtouchend="touchend" -> 監(jiān)聽list頁面的觸摸動(dòng)作

上代碼:

<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實(shí)現(xiàn)

這部分沒有太多可說的吆倦,樣式自己慢慢去調(diào)。

上代碼:

page{
  background-color: #F1F1F1; 
}

::-webkit-scrollbar{/*隱藏scrollerView滾動(dòng)條*/
    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;
}

如有不足歡迎留言一起補(bǔ)充探討 ~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末坐求,一起剝皮案震驚了整個(gè)濱河市蚕泽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌桥嗤,老刑警劉巖须妻,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異泛领,居然都是意外死亡荒吏,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門渊鞋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绰更,“玉大人,你說我怎么就攤上這事锡宋±芡澹” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵执俩,是天一觀的道長徐钠。 經(jīng)常有香客問我,道長役首,這世上最難降的妖魔是什么尝丐? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任显拜,我火速辦了婚禮,結(jié)果婚禮上摊崭,老公的妹妹穿的比我還像新娘讼油。我一直安慰自己杰赛,他們只是感情好呢簸,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著乏屯,像睡著了一般根时。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辰晕,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天蛤迎,我揣著相機(jī)與錄音,去河邊找鬼含友。 笑死替裆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的窘问。 我是一名探鬼主播辆童,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼惠赫!你這毒婦竟也來了把鉴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤儿咱,失蹤者是張志新(化名)和其女友劉穎庭砍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體混埠,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怠缸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钳宪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片揭北。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡止喷,死狀恐怖矮烹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情继控,我是刑警寧澤侦高,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布嫉柴,位于F島的核電站,受9級(jí)特大地震影響奉呛,放射性物質(zhì)發(fā)生泄漏计螺。R本人自食惡果不足惜夯尽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望登馒。 院中可真熱鬧匙握,春花似錦、人聲如沸陈轿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽麦射。三九已至蛾娶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間潜秋,已是汗流浹背蛔琅。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留峻呛,地道東北人罗售。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像钩述,于是被迫代替她去往敵國和親寨躁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容