微信小程序:自定義可滑動導航欄

app一般會有這樣的導航欄卿啡,標題下的指示器(橫線)會隨著頁面的移動而移動嘱支。

indicator1.gif

最近要做一個小程序,也需要一個導航欄厕九,但翻了一些網(wǎng)上的demo蓖捶,都沒有類似的效果。android中可以通過TabLayout + ViewPager實現(xiàn)扁远,于是決定照貓畫虎俊鱼,寫一個小程序的自定義TabLayout。

思路是畅买,小程序提供了swiper組件可以實現(xiàn)左右滑動的效果并闲,那么只要再有一個view可以隨著swiper頁面移動就好了。

在項目中新建一個page谷羞,并把該page聲明為自定義控件帝火。

//json
{
  "component":true
}

導航欄的標題應該是調(diào)用者用參數(shù)的方式告訴我們的,所以tablayout需要一個屬性接收標題湃缎。

//js
properties: { 
      titles:{
        type:Array,
        value: [],
      }
  }

tablayout布局分為兩部分犀填,標題部分和滑動頁面部分。
標題部分包括導航欄的標題和標題下的會移動的小橫線(這里稱為indicator)嗓违,標題綁定titles數(shù)據(jù)九巡,同時給indicator綁定一個動畫。

//wxml

<!-- title -->
  <view id="head" style='display:flex; flex-direction:column; align-items:center;'>
    <view>
      <view style='height:55rpx; display:flex; flex-direction:row; text-align:center;'>
        <view wx:for="{{titles}}" style='width:100rpx;'>
          <text data-index='{{index}}' bindtap='clickTitle'>{{item}}</text>
        </view>
      </view>
      <!-- indicator -->
      <view style='width:100rpx; height:5rpx; background:lightgray;' animation="{{animation}}"></view>
    </view>
  </view>

滑動頁面部分靠瞎,相當于viewpager的角色,為了保證和標題一致求妹,同樣需要綁定titles數(shù)據(jù)乏盐,監(jiān)聽swiper滑動和滑動結(jié)束狀態(tài)。在<swiper-item>中添加<slot>標簽制恍,使調(diào)用者可以動態(tài)為swiper添加布局父能,可以用for循環(huán)的index作為<slot>的key。

//wxml
<!-- page -->
  <swiper style='height:100%;' current="{{swiperIndex}}" bindtransition="swiperTrans" bindanimationfinish="swiperAnimationfinish" bindchange='swiperChange'>
    <view wx:for="{{titles}}" wx:key="*this">
      <swiper-item style='background:lightblue; display:flex; align-items:center; justify-content:center'>
        <slot name="{{index}}"></slot>
      </swiper-item>  
    </view>
  </swiper>

因為可能有多個頁面净神,所以還要添加一個多slot支持

//js
options: {
    multipleSlots: true // 在組件定義時的選項中啟用多slot支持
}

通過swiper中頁面的滑動距離計算indicator的需要移動多少何吝,除需要知道swiper的滑動距離外溉委,還需要知道每個swiper-item的寬度和indicator所在布局的寬度,通過兩個寬度的比例計算出indicator的位移爱榕。

這里swiper寬度為屏幕寬度瓣喊,可在頁面加載時獲取,indicator滑動范圍可自行定義黔酥。不過有個問題藻三,通過wx.getSystemInfoSync().screenWidth獲取的屏幕寬度單位是px,而給indecator賦值時單位是rpx跪者,單位不同不能用于計算棵帽,好在小程序默認的屏幕寬度為750rpx,可用于計算比例渣玲。

data:{
    //屏幕寬度 
    screenWidth:"",
    //微信規(guī)定的屏幕寬度750 rpx
    wxScreenWidth:750,
    //指示器滑動范圍寬度逗概,單位寬度
    indicatorLayoutWidth:100
}
...
lifetimes: {
    attached() {
      // 獲取屏幕寬度
      var that = this;
      that.setData({ screenWidth: wx.getSystemInfoSync().screenWidth });
    }
}

在swiper滑動時需要判斷滑動位置,在左右盡頭是不能繼續(xù)滑動的忘衍,所以在在swiper滑動完成后判斷一下狀態(tài)逾苫。

data:{
    //標題 swiper-item 所在位置
    titleIndex: 0,
    //滑動狀態(tài):滑動到左邊(1)、滑動到右邊(2)淑履、其他位置(0)
    scrollStatus:1
}
...
swiperAnimationfinish: function(e) {
      var that = this;
      that.setData({
        titleIndex: e.detail.current
      });

      //計算指示器位移狀態(tài)
      if (that.data.titleIndex == (that.data.titles.length-1)) {
        // console.log("move to the right")
        that.setData({ scrollStatus: 2 });
      } else if (that.data.titleIndex == 0) {
        // console.log("move to the left")
        that.setData({ scrollStatus: 1 });
      }else {
        that.setData({ scrollStatus: 0 });
      }
    }

之后就可以通過監(jiān)聽swiper的滑動隶垮,讓indicator一起聯(lián)動了。

//tablayout.js

data:{
    //indiator 動畫
    animation: "",
}
...
methods:{
  swiperTrans:function (e) {
      var that = this;
      // swipter位移 中間變量
      var dx;

      //e.detail.dx 頁面滑動距離秘噪,手指向左滑動距離為正狸吞,反之為負
      if (e.detail.dx >= 0)
        if (that.data.scrollStatus == 2)//頁面處于最右,且仍向左滑動時指煎,頁面位置保持在最右蹋偏。
          dx = that.data.screenWidth * that.data.titleIndex;
        else
          dx = e.detail.dx + that.data.screenWidth * that.data.titleIndex;
      else if (that.data.scrollStatus == 1) //頁面在初始位置,且仍向右滑動時至壤,頁面停留在初始位置威始。
        dx = 0
      else
        dx = e.detail.dx + that.data.screenWidth * that.data.titleIndex;

      //indicator與swipter之間移動比例
      var scale = (that.data.indicatorLayoutWidth / that.data.wxScreenWidth).toFixed(2);//保留兩位小數(shù),否則indicator動畫有誤差
      //indicator 位移
      var ds = dx * scale;

      this.transIndicator(ds);
    },

  //indicator 平移動畫
  transIndicator(x) {
      let option = {
        duration: 100,
        timingFunction: 'linear'
      };
      this.animation = wx.createAnimation(option);
      this.animation.translateX(x).step();
      this.setData({
        animation: this.animation.export()
      })
    }
  }

在點擊小標題時像街,swiper的滑動到對應頁面黎棠。

//js
clickTitle(e) {
      //點擊切換卡片
      var that = this;

      that.setData({
        //swiper 綁定了 current="{{swiperIndex}}"
        swiperIndex: e.currentTarget.dataset.index
      });
    }

此時就可以在其他頁面進行調(diào)用了,調(diào)用的時候按模塊引入其他頁面就可以了镰绎。

<import src="../extend/extend.wxml"/>

<tablayout titles="{{titles}}">
  <view slot="0"><template is="extend"></template></view>
  <view slot="1"><template is="extend"></template></view>
  <view slot="2"><template is="extend"></template></view>
  <view slot="3"><template is="extend"></template></view>
</tablayout>

實現(xiàn)效果為


indicator2.gif

源碼

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末脓斩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子畴栖,更是在濱河造成了極大的恐慌随静,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異燎猛,居然都是意外死亡恋捆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門重绷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沸停,“玉大人,你說我怎么就攤上這事论寨⌒橇ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵葬凳,是天一觀的道長绰垂。 經(jīng)常有香客問我,道長火焰,這世上最難降的妖魔是什么劲装? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮昌简,結(jié)果婚禮上占业,老公的妹妹穿的比我還像新娘。我一直安慰自己纯赎,他們只是感情好谦疾,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著犬金,像睡著了一般念恍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晚顷,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天峰伙,我揣著相機與錄音,去河邊找鬼该默。 笑死瞳氓,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的栓袖。 我是一名探鬼主播匣摘,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼裹刮!你這毒婦竟也來了音榜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤必指,失蹤者是張志新(化名)和其女友劉穎囊咏,沒想到半個月后恕洲,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體塔橡,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡梅割,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了葛家。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片户辞。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖癞谒,靈堂內(nèi)的尸體忽然破棺而出底燎,到底是詐尸還是另有隱情,我是刑警寧澤弹砚,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布双仍,位于F島的核電站,受9級特大地震影響桌吃,放射性物質(zhì)發(fā)生泄漏朱沃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一茅诱、第九天 我趴在偏房一處隱蔽的房頂上張望逗物。 院中可真熱鬧,春花似錦瑟俭、人聲如沸翎卓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽失暴。三九已至,卻和暖如春椭迎,著一層夾襖步出監(jiān)牢的瞬間锐帜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工畜号, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缴阎,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓简软,卻偏偏與公主長得像蛮拔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子痹升,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

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