zl程序教程

您现在的位置是:首页 >  APP

当前栏目

微信小程序实现左右滑动触发内容及联动选项卡切换、Math、abs、findIndex、parseInt、String、push、createSelectorQuery、selectAll

2023-04-18 14:28:58 时间

序言

在写原生微信小程序项目的时候,遇到左右滑动更新内容及联动选项卡切换的功能。于是就写了这篇文章,关于文章的css不在此文章中展示,使用了公共的自定义类名,所以通过类名大概就能推敲出css的属性及值。


1、HTML部分

1.1、代码

<view>
  <!-- tabBar选项卡 -->
  <view class="width_100_100">
    <scroll-view scroll-x="true" scroll-left="{{scrollLeft}}">
      <view class="dis_r_fs">
        <view id="idScrollLeft" class="padding_lr_20 {{index===0?'padding_l_40':''}} {{index===LR_tabBar.length-1?'padding_r_40':''}}" style="white-space: nowrap;" wx:for="{{LR_tabBar}}" wx:key="id">
          <view class="font_weight_700 padding_lr_6 radius_6 twinkle_background_ccc {{isH===item.id?'color_royalblue':''}}" data-item="{{item}}" catchtap="catchtapTabBar">{{item.title}}</view>
        </view>
      </view>
    </scroll-view>
  </view>

  <!-- 内容 -->
  <view class="margin_t_26 padding_lr_20 padding_b_36" bindtouchstart="slideStart" bindtouchend="slideEnd">
    <view>
      <view class="height_90 line_height_90 padding_lr_26" wx:for="{{list}}" wx:key="id">
        <view class="ellipsis">{{item.title}}</view>
      </view>
    </view>
  </view>

  <!-- 返回顶部 -->
  <view class="position_fixed z_index_5 bottom_160 right_36">
    <backToTop width='86' height='86' wx:if="{{scrollTop}}"></backToTop>
  </view>
</view>

1.2、注解

页面分为三个模块,分别是顶部横向滚动选项卡,底部内容区和返回顶部按钮。twinkle_background_ccc这是一个点击背景闪烁的类,使用cssactive属性实现。


2、JavaScript部分

2.1、代码

const {
  tabBar,
  objList,
  method_clone,
  showToast
} = getApp();

Page({
  /**
   * 页面的初始数据
   */
  data: {
    LR_tabBar: [],
    originObjList: [],
    isH: '',
    list: [],
    startPageX: 0,
    scrollTop: false,
    distanceLeft: [],
    scrollLeft: 0
  },

  // 获取各个元素与左边的距离值
  obtainLeft() {
    let self = this,
      selfData = self.data,
      query = wx.createSelectorQuery();

    query = query.selectAll('#idScrollLeft').boundingClientRect();

    query.exec(function (res) {
      res = res[0];

      let arr = [];

      res.forEach(item => arr.push(parseInt(item.left)));

      self.setData({
        distanceLeft: arr
      }, function () {
        let distanceLeft = selfData.distanceLeft,
          len = distanceLeft.length;

        // 第一次获取大概率会失败
        // 二次获取横向滚动各个元素宽度
        if (len === 0) return self.obtainLeft();
      });
    });
  },

  // 滑动结束
  slideEnd({ changedTouches }) {
    let self = this,
      selfData = self.data,
      endPageX = changedTouches[0].pageX,
      tabBar = selfData.LR_tabBar,
      tabBarLen = tabBar.length,
      originObjList = selfData.originObjList,
      isH = selfData.isH,
      startPageX = selfData.startPageX,
      distanceLeft = selfData.distanceLeft,
      i = tabBar.findIndex(item => item.id === isH),
      id = '',
      slidingDistance = 0,
      direction = '';

    // 滑动结束,并舍弃小数点
    endPageX = parseInt(endPageX);
    // 滑动距离
    slidingDistance = endPageX - startPageX;
    // 滑动方向
    direction = String(slidingDistance)[0];

    if (Math.abs(slidingDistance) < 156) return false;

    if (direction === '-' && i < tabBarLen - 1) { // 向左滑动
      i += 1;
    } else if (direction !== '-' && i > 0) { // 向右滑动
      i -= 1;
    } else {
      if (i === 0) {
        showToast('滑到最左侧了');
      } else {
        showToast('滑到最右侧了');
      }

      return false;
    }

    id = tabBar[i].id;

    self.setData({
      list: originObjList[id],
      isH: id,
      scrollLeft: distanceLeft[i]
    });
  },

  // 开始滑动 
  slideStart({ changedTouches }) {
    let pageX = changedTouches[0].pageX;

    pageX = parseInt(pageX);

    this.setData({
      startPageX: pageX
    });
  },

  // tabBar
  catchtapTabBar({ currentTarget: { dataset: { item } } }) {
    let self = this,
      selfData = self.data,
      originObjList = selfData.originObjList;

    self.setData({
      list: originObjList[item.id],
      isH: item.id
    });
  },

  // 初始化
  init() {
    let newTabBar = method_clone(tabBar),
      id = newTabBar[0].id,
      originObjList = method_clone(objList);

    this.setData({
      LR_tabBar: newTabBar,
      originObjList,
      isH: id,
      list: originObjList[id]
    }, function () {
      this.obtainLeft();
    });
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    this.init();
  },
  
  /**
   * 监听滚动条
   */
  onPageScroll({
    scrollTop
  }) {
    this.setData({
      scrollTop: scrollTop > 20 ? true : false
    });
  }
})

2.2、注解

.js文件顶部引入相关变量或函数。
tabBar:选项卡数据;
objList:内容数据;
method_clone:克隆函数,使用JSON克隆,属于浅克隆;
showToast:全局提示方法,对微信小程序原生API的重新封装。

第一步
定义名为init的函数进行初始化操作。函数主要功能是获取数据,并且赋值到data对应的变量中。克隆选项卡数据,重新命名为LR_tabBar。获取选项卡数据第一项的id,把id赋值给isH变量,通过isH对选项卡的选中高亮显示。克隆全部的内容数据,并重新命名为originObjList。截取当前选项卡对应的数据放到list变量中,list变量即页面显示的数据,因为全部的内容数据是对象形式,所以通过id即可得到对应数据。使用赋值API的第二个参数实现代码的同步运行,加载页面时需要把页面结构的数据先赋值到data中,之后再通过调用obtainLeft函数获取选项卡每一项距离左边的值。

第二步
定义获取选项卡距离左边值函数,名称为obtainLeft。使用微信小程序的wx.createSelectorQuery().selectAll('#idScrollLeft').boundingClientRect();方法获取HTMLid。通过exec方法解析每一个选项卡距离左边的值,因为exec返回的参数比较多,所以使用循环提取需要的值即可。if (len === 0) return self.obtainLeft();判断函数调用过早就执行自调,必须等到DOM渲染完成才能获取到距离值。

第三步
定义选项卡单击函数,名称为catchtapTabBar。通过解构获取对应的点击项,根据点击项的id进行内容的获取。

第四步
定义开始滑动函数,名称为slideStart。使用微信小程序自带的滑动事件获取pageX的滑动属性值记录开始滑动的横坐标值,并赋值给startPageX变量。函数中使用parseInt去除小数点及小数部分(个人习惯,不属于必要的操作)。

第五步
定义滑动结束函数,名称为slideEnd。使用微信小程序自带的滑动事件获取pageX的滑动属性值记录开始滑动的横坐标值,并赋值给endPageX变量备用。
第一点:
slidingDistance变量用来保存结束结束的横坐标值减去开始滑动的横坐标值的差。
使用String方法把得到的差值变为字符串类型,并截取字符串的第一个字符作为方向值放到变量direction中。
第二点:
if (Math.abs(slidingDistance) < 156) return false;使用Mathabs方法获取slidingDistance变量的绝对值与156对比,如果小于156说明滑动距离太短,不需要做任何操作,并终止程序继续往下运行。
第三点:
if (direction === '-' && i < tabBarLen - 1)如果direction的值为-i的值小于选项卡长度减1,那么说明当前操作是向左滑动,且不是选项卡的最后一项,所以i进行加1操作。
第四点:
else if (direction !== '-' && i > 0)如果direction的值不为-i的值大于0,那么说明当前操作是向右滑动,且不是选项卡的第一项,所以i进行减1操作。
第五点:
else里面实现滑动到两端的提示功能,逻辑简单,不做详细介绍。
第六点:
id = tabBar[i].id;通过i值获取id的值,注意这里的id值需要在赋值之前和所有逻辑处理之后获取,也就是代码位置不能随便颠倒。
第七点:
这里的赋值不仅仅是列表的值和高亮显示的值,还需要把选项卡的滚动条距离值也进行赋值,选项卡的每一项距离左边的值已经在页面初始化时获取保存在distanceLeft变量中。


3、微信小程序演示

X2_1_5s