自定义组件之 Swiper 特效组件

效果演示
一、需求说明

使用微信小程序原生代码,实现如上图的交互效果。具体要求如下:

  • 当手指触发(tap / touch) Tab区块时,页面自动向上滚动,滚动至视窗的顶部。
  • Tab区块,最多只能滚动到视窗的顶部,不可以继续向上滚动。
  • 当用户向下滑动时,Tab区块正常向下滚动。
  • 当Tab区块里的内容超出一屏的高度时,只能在 Tab区块的内部进行滚动。
二、封装自定义组件

根据以上需求,使用原生小程序组件和代码,封装一个 组件,完整代码如下所示。其中的要点(坑)罗列如下:

  • 当Tab区块置顶时,组件的高度必须等于屏幕视窗的高度,因此将使用wx.getSystemInfo来动态获取屏幕尺寸(单位是px),通过计算后,手动地设置自定义组件 和 原生组件 的高度,分别是h1h2。详细代码见下方的myswiper.js
  • 小程序原生组件是有默认高度的,必须手动设置其高度h2
  • 默认是position:absolute;overflow:hidden;的,我们必须更改其默认样式(见下方的 myswiper.wxss文件),否则当内部内容较多时会被隐藏掉。另外,为了让中的内容滚动更流畅,还要为其加上 -webkit-overflow-scrolling:touch;属性。
  • Tab项可能多于3个,或者是 4个,因此建议使用 flex 来动态布局,以确保 Tabs的数量是可变的。
  • 使用 slot 插槽来动态渲染 Tab区块中的内容,在组合使用来定义插槽。
  • 组件绑定 tap``touch事件,并判断当用户点击、上滑时,让页面滚动 的位置。详细逻辑见下方的 myswiper.js文件。
# myswiper.wxml


  
  
    
      {{item}}
      
    
  
  
  
    
      
    
  


# myswiper.wxss

.myswiper {
  position: relative;
  /* height: 1200rpx; */
  background: white;
}
.tabs{
  width: 100%;
  height: 100rpx;
  background-color: #eeeeee;
  display: flex;
}
.tab{
  flex: 1;
  font-size:28rpx;
  font-family:PingFangSC;
  font-weight:400;
  color:rgba(102,102,102,1);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  font-weight: bold;
}
.tab>text{
  display: block;
}
.on .tab-line{
  width:90rpx;
  height:4rpx;
  background:rgba(255,117,56,1);
  border-radius:3rpx;
  margin-top: 5rpx;
}
.on .tab-title{
  font-size:32rpx;
  font-family:PingFangSC;
  font-weight:500;
  color:rgba(255,117,56,1);
}
.swiper swiper-item {
  /* 开启swiper-item滚动,touch流畅滚动 */
  overflow: scroll;
  -webkit-overflow-scrolling:touch;
}
# myswiper.js

let startY = 0;
Component({
  options: {
    multipleSlots: true // 启用多slot支持
  },
  properties: {
    tabArr: {   /* Tab项的名称列表 */
      type: Array,
      value: []
    }
  },
  data: {
    h1: '',   // my-swiper 组件的高度
    h2: '',   // swiper 组件的高度
    curIdx: 0 // tab 索引号
  },

  attached: function() {
    const that = this
    // 获取信息,动态设置组件高度
    wx.getSystemInfo({
      success: function(e) {
        const w = e.windowWidth
        const h = e.windowHeight
        // 100 是Tab的默认高度,单位rpx
        // 把 rpx 转化为 px
        const tabH = 100 * w / h
        that.setData({ h1: h, h2: h - tabH })
      }
    });
  },
  methods: {
    /* my-swiper 组件的系列事件 */
    tabTouch: function(e) {
      // 当用户点击my-swiper组件时,将其置顶
      const top = e.currentTarget.offsetTop
      // 滚动到顶部
      wx.pageScrollTo({scrollTop: top});
    },
    touchStart: function(e) {
      startY = e.changedTouches[0].clientY
      console.log('start', startY)
    },
    touchEnd: function(e) {
      const endY = e.changedTouches[0].clientY
      // 当手势向上滑动时,把my-swiper组件置顶
      if (startY - endY > 10) {
        const top = e.currentTarget.offsetTop
        wx.pageScrollTo({scrollTop: top});
      }
      console.log('end', endY)
    },
    // 点击标签事件
    tabClick:function(e){
      let data = e.currentTarget.dataset;
      this.setData({ curIdx: data.index })
    },
    // swiper切换事件
    swiperChange:function(e){
      this.setData({ curIdx:e.detail.current })
    },
  }
})
# myswiper.json

{ "component": true }
三、使用 组件,进行测试

组件封装好了,测试代码如下。我们只需要传递一个 tabArr 标签列表进去即可。再使用 slot 插槽动态地插入多个区块的内容。

# demo.json

{
  "navigationBarTitleText": "自定义Swiper组件及特效",
  "usingComponents": {
    "my-swiper": "/component/myswiper/myswiper"
  }
}
# demo.wxml


  
    
  

  
    人物
    自然
    汽车
    美女
  

# demo.wxss

.other image {
    display: block;
    width: 100%;
}
.content {
    font-size: 80rpx;
    text-align: center;
    line-height: 200rpx;
}
# demo.js

Page({
  data: {},
  onLoad: function() {},
})
四、总结

组件的封装,填平了一些坑,比如 swiper默认的样式问题。通过这个组件,我们至少学到了如下前端知识:

  • 什么是组件?如何自定义组件?
  • 如何使用小程序的原生组件,并修改其默认的样式?
  • 学会使用 slot 插槽,实现组件内容的差异化
  • 学会使用小程序原生 api 获取手机信息,用 js 改变组件样式
  • 学会使用 touch 事件,区分e.touchese.changedTouches
  • 学会pxrpx单位之间的区别和相互转化
  • 学会使用小程序 api 来手动地滚动页面,等。

以上完整代码,复制黏贴即可实现这个效果,相关要点已经在代码中进行了注释。事实上,要总结的内容还有很多,时间有限就不啰嗦了。好了,本篇就总结到这里。

往期 相关的小程序demo笔记:

  • 手动实现 Swiper 视窗滑动效果
  • 微信小程序 模拟打电话 实践
  • 微信小程序 Animation 动画实践
  • 小程序Canvas画布保存至相册
  • CSS动画|JavaScript动画|小程序动画


本篇结束 2019-08-27

你可能感兴趣的:(自定义组件之 Swiper 特效组件)