微信小程序-滚播效果实现方案

1,029 阅读4分钟

小程序要做自动滚播而且可以点击可以拉动的效果,我尝试过几种方案都没有达到很好的效果...

1.scroll-view + setInterval

这种方法最简单粗暴,使用小程序自带的滑动元素再加上setInterval定时让滚动条移动,做出的一个滑动效果。

index.wxml:

<view class="demo">
  <scroll-view
    class="scrollView"
    scroll-x="{{true}}"
    scroll-left="{{left}}"
  >
    <view
      class="scrollItem"
      wx:for="{{itemList}}"
      wx:for-index="index"
      wx:for-item="item"
      wx:key="{{index}}"
      bindtap="showTips"
    >
      {{item}}
    </view>
  </scroll-view>
</view>

index.wxss:

.demo {
  padding: 20px 0;
}
.demo .scrollView {
  white-space: nowrap;
}
.demo .scrollView .scrollItem{
  display: inline-block;
  background: red;
  margin: 20rpx;
  width: 200px;
  height: 200px;
}

index.js

const app = getApp()

Page({
  data: {
    itemList: [1, 2, 3, 4, 5, 6],
    left: 0,
  },
  onShow() {
    setInterval(() => {
      this.setData({
        left: this.data.left +=1,
      })
    }, 100)
  },

  showTips() {
    console.log('点击~');
  }
})

效果(没有动图):

这样你就得到了一个有缓慢向左移动的滚播

但是

因为你需要短时间去调用setData来刷新视图,这样会让你页面上dom操作都无法被触发,所以当你点击 showTips时是不会有任何反应。

这个方法不建议使用。

2.animation

这种方法是获取元素的宽度计算出需要滑动的长度,然后使用小程序动画效果。

index.wxml:

<!--index.wxml-->
<view class="demo">
  <view
    class="scrollView"
  >
    <view
      id="box"
      animation="{{animationData}}"
    >
      <view
        class="scrollItem"
        wx:for="{{itemList}}"
        wx:for-index="index"
        wx:for-item="item"
        wx:key="{{index}}"
        bindtap="showStop"
      >
        {{item}}
      </view>
    </view>

  </view>
</view>


index.wxss:

/**index.wxss**/
.demo {
  padding: 20px 0;
}
.demo .scrollView {
  white-space: nowrap;
  /* 不是 srcoll-view 需要加上滚动条 */
  overflow-x: auto;
}
.demo .scrollView .scrollItem{
  display: inline-block;
  background: red;
  margin: 20rpx;
  width: 200px;
  height: 200px;
}

#box {
  display: inline-block;
  background: rgb(0, 0, 0);
}

index.js

const app = getApp()

Page({
  data: {
    itemList: [1, 2, 3, 4, 5, 6],
    /**
     * 通过 wx.createSelectorQuery().select() 方法动态获取
     */
    width: 0,
    animationData: {},
  },
  onLoad() {
    wx.createSelectorQuery().select('#box').boundingClientRect().exec(res => {
      // 时间
      let duration = 3000;
      let animation = wx.createAnimation({
        duration
      });
      // 手机宽度
      let phoneWidth = wx.getSystemInfoSync().windowWidth;
      let moveLeng = - res[0].width + phoneWidth;
      animation.translateX(moveLeng).step();
      this.setData({
        animationData: animation.export(),
      });
      console.log(res);
    })
  },

  showStop() {
    console.log('停止动画');
    // 停止动作
    wx.createSelectorQuery().select('#box').boundingClientRect().exec(res => {
      var animation = wx.createAnimation({
        duration: 0,
      });
      // 停在当前位置
      animation.translateX(res[0].left).step();
      this.setData({
        animationData: animation.export(),
      });
    });
  }
})

这种方法可以流畅滚动并且可以触发事件,可以触发事件就可以去做点播的停止和其他操作

但是

当这个动画滑动完成或者你中途停止动画,会发现移动的部分已经是超出了浏览器以外,没办法再滑动回来,因为动画的滑动是定位滑动直接把元素定位到外部了。

3.(view + animation) + srcoll-view

经过上面两次失败的尝试得到两个想法,animation实现滑动动作非常好用,scroll-view用于实现左右滑动,那么就可以结合这两个各司其职(感觉做法好蠢)。

思路:建两个模块滑动时显示view + anomatiom,暂停时隐藏掉,显示srcoll-view给用户滑动,一个相互切换的过程。

index.wxml:

<!--index.wxml-->
<view class="demo">
  <view
    class="scrollView"
  >
    <!-- 动作模块 -->
    <view
      id="box-animation"
      animation="{{animationData}}"
      wx:if="{{isShow}}"
    >
      <view
        class="scrollItem"
        wx:for="{{itemList}}"
        wx:for-index="index"
        wx:for-item="item"
        wx:key="{{index}}"
        bindtap="showStop"
      >
        {{item}}
      </view>
    </view>

    <!-- 滑动模块 -->
    <scroll-view
      scroll-x="true"
      id="box-scroll"
      wx:if="{{!isShow}}"
      scroll-left="{{scrollLeft}}"
    >
      <view
        class="scrollItem"
        wx:for="{{itemList}}"
        wx:for-index="index"
        wx:for-item="item"
        wx:key="{{index}}"
        bindtap="showStop"
      >
        {{item}}
      </view>
    </scroll-view>

  </view>
</view>

index.wxss:

/**index.wxss**/
.demo {
  padding: 20px 0;
}
.demo .scrollView {
  white-space: nowrap;
  overflow-y: hidden;
  width: 100%;
}
.demo .scrollView .scrollItem{
  display: inline-block;
  background: red;
  margin: 20rpx;
  width: 200px;
  height: 200px;
}

#box-animation {
  display: inline-block;
  white-space: nowrap;
  background: rgb(0, 0, 0);
  /* 不需要显示滑动 */
  position: fixed;
}

#box-scroll {
  display: inline-block;
  white-space: nowrap;
  background: rgb(0, 0, 0);
}

index.js:

const app = getApp()

Page({
  data: {
    itemList: [1, 2, 3, 4, 5, 6],
    width: 0,
    animationData: {},
    
    isShow: true,
    scrollLeft: 0,
  },
  onLoad() {
    this.animationFun();
  },
  animationFun() {
    wx.createSelectorQuery().select('#box-animation').boundingClientRect().exec(res => {
      // 时间
      let duration = 10000;
      let animation = wx.createAnimation({
        duration
      });
      // 手机宽度
      let phoneWidth = wx.getSystemInfoSync().windowWidth;
      let moveLeng = - res[0].width + phoneWidth;
      animation.translateX(moveLeng).step();
      this.setData({
        animationData: animation.export(),
      });
    })
  },

  showStop() {
    console.log('停止动画');
    // 停止动作
    wx.createSelectorQuery().select('#box-animation').boundingClientRect().exec(res => {
      var animation = wx.createAnimation({
        duration: 0,
      });
      // 停在当前位置
      animation.translateX(res[0].left).step();
      this.setData({
        animationData: animation.export(),
        // 切换并让scoll-view定位到对于位置
        isShow: false,
        scrollLeft: - res[0].left,
      });
    });
  }
})

总结

做这个效果最理想的方法应该是只用一个模块利用js去控制滑动和停止,但是最终用了第三种方法去实现,用这种方法实现出来对自己很不满意的,后续如果有更好的方案会补充,希望有小伙伴有更好方案可以提供给我参考参考...