HarmonyOS-自定义swipe组件 原创 精华

中软小助手
发布于 2022-2-18 11:34
浏览
3收藏

作者:金豪杰

前言

初学鸿蒙技术不久,就想自己试着实现一下swipe组件。 当组件绑定autoplay属性为true时 , 即可开启自动播放,也可以左右移动图片,并且会修改自动播放的播放方向。

效果演示

HarmonyOS-自定义swipe组件-鸿蒙开发者社区

实现思路

1.布局思路

通过对内外层盒子定位(父相子绝),外层盒子对溢出的内容进行隐藏,调整每个小盒子的left值来显示不同的图片内容。

HarmonyOS-自定义swipe组件-鸿蒙开发者社区

2.移动实现

//初始化赋值
onReady() {
        setTimeout(()=>{
            //获取组件宽度
            this.clientWidth=this.$refs.moveBox.getBoundingClientRect().width;
            let screenWidth=this.clientWidth;
            //设置 spacing值
            this.spacing=this.clientWidth/4;
            if(!(this.imgArr instanceof Array)) return;
            //初始化 传入的图片数组
            this.arr = [
                this.imgArr[this.imgArr.length - 2],
                this.imgArr[this.imgArr.length - 1],
                ...this.imgArr,
                this.imgArr[0],
            ];
            //初始化left值
            this.leftArr=this.arr.map((item,id)=> (-2+id)*screenWidth);
            //备份 整体位置
            this.leftArrCopy=[...this.leftArr];
            //是否开启自动播放
           this.autoplay && this.autoPlay();
        },100)
        //初始化修改图片数组
    },
 //手指点下
    moveStart(e) {
        //记录手指点下的起始位置
        this.startPoint = e.touches[0].localX;
        //记录固定的起始数据
        this.startPointCopy=this.startPoint;
        //开放事件
        this.pointerEvent=true;
        clearInterval(this.auto);
        this.auto=null;
    },
    //手指移动
    move(e) {
        //移动的距离
        this.newX = e.touches[0].localX - this.startPoint;
        //重置起点
        this.startPoint=e.touches[0].localX;
        //改变整体的left值 随着手指移动
        this.leftArr=this.leftArr.map((item)=> item+this.newX);
    },
    //手指松开
   moveEnd() {
       //计算移动了的距离
        let direction=this.startPoint-this.startPointCopy;
        //判断移动的距离是否大于spacing值
        if (Math.abs(direction) > this.spacing) {
            //根据newX值判断方向
            if (this.newX < 0) {
                //向右
                this.index++;
                this.direction=1;
            } else {
                //向左
                this.index--;
                this.direction=-1;
            }
            //开始移动
            this.startMove();
        }else{
            //没有超过spacing 则回弹
            //确定回弹方向
            this.direction=this.newX>0? -1:1;
            //回弹移动
            this.moveBack();
        }
    },
  // 移动距离过小 开始回弹
    moveBack(){
        this.timer=setInterval(()=>{
            this.sec+=this.direction;
            //移动距离累计和
            this.oldNum=this.sec+this.oldNum;
            //改变整体left值
            this.leftArr=this.leftArr.map((item)=> parseInt(item+this.sec));
            //累计和大于移动距离时 图片回弹
            if(Math.abs(this.oldNum)>=Math.abs(this.startPoint-this.startPointCopy)){
                //根据index改变left值 从而显示对应图片
                this.leftArr=this.leftArrCopy.map((item,id)=> (-2+id-                                             this.index)*this.clientWidth);
                this.stopMove();
                //移动结束后 是否开启自动播放
                this.autoplay && this.autoPlay();
            }
        },20)
    },
    //开始移动
    startMove(){
        //计算剩余所需移动的距离
        let a=this.clientWidth-Math.abs(this.startPoint-this.startPointCopy);
        this.timer=setInterval(()=>{
           this.changeLeft();
            //当累计和大于等于剩余所需移动的距离时
            if(Math.abs(this.oldNum)>=Math.abs(a)){
                //图片归位
                this.comeBack();
                //图片归位后开启自动播放
                this.autoplay && this.autoPlay();
            }
        },10);
    },
        changeLeft(){
        //每次移动的距离
        this.sec-=this.direction;
        //移动距离累计和
        this.oldNum=this.sec+this.oldNum;
        //改变整体left值
        this.leftArr=this.leftArr.map((item)=> parseInt(item+this.sec));
    },
        
   //位置判断
    comeBack(){
        //到达右边界回归原位
        this.num=this.index;
        if (this.index === this.arr.length - 4 ) {
            this.index=-1;
            this.num=this.imgArr.length - 1;
        }
        //到达左边界回归原位
        if (this.index === -2 ) {
            this.index=this.arr.length - 5;
            this.num=this.imgArr.length - 2;
        }
        if(this.index===-1){
            this.num=this.imgArr.length - 1;
        }
        //改变left值
        this.leftArr=this.leftArrCopy.map((item,id)=> (-2+id-this.index)*this.clientWidth);
        this.stopMove();
    },
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.

3.自动播放

autoPlay(){
        this.auto=setInterval(()=>{
            //根据移动方向改变index值
            this.index=this.index+this.direction;
            this.timer=setInterval(()=>{
                this.changeLeft();
                //当累计和大于等于容器宽时 图片不在移动
                if(Math.abs(this.oldNum)>=this.clientWidth){
                    this.comeBack();
                    //清除数据
                    this.stopMove();
                }
            },10);
        },this.timing)
    },
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

使用方法

引入swipe组件
<element name="swipea" src="../../common/swipea/swipea"></element>

<swipea img-arr="{{arr}}" autoplay="true"></swipea>
  • 1.
  • 2.
  • 3.
  • 4.
在data中挂载图片路径数据并传入到swipe组件中 
arr: [
  '/common/images/a1.jpg',
    '/common/images/a2.jpg',
    '/common/images/a3.jpg',
    '/common/images/a4.jpg'
      ]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

属性

属性名 类型 默认值 作用
imgArr Array 图片路径(必传项)
liColor String ‘red’ 底部激活状态颜色
swipeHeight Number 250 组件高度
autoplay Boolean false 是否开启自动播放
timing Number 2000 播放间隔时间
swipe组件可传值
//图片路径(必传项)
    props:{
        imgArr: {
            type:Array,
            default:[]
        },
        //底部激活状态颜色
        liColor:{
            type:String,
            default:'red'
        },
        //组件高度
        swipeHeight:{
            type:Number,
            default:250
        },
        //是否开启自动播放
        autoplay:{
            type:Boolean,
            default:false
        },
        //播放间隔
        timing:{
            type:Number,
            default:2000
        }
    },
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.

总结:

1.onReady生命周期中无法直接获取到dom元素,可以使用定时器来获取。

2.鸿蒙中无法直接获取dom元素的style属性 。

3.只有6以上的版本才支持transition属性,而且只支持个别属性拥有渐变效果 。

4.overflow属性好像并不支持,我就改用clip-path属性,它可以对不同区域进行裁剪。

源码地址

https://gitee.com/xiaojin1233323/harmonyos-swipe.git

更多原创内容请关注:中软国际 HarmonyOS 技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
4
收藏 3
回复
举报
4
3


回复
    相关推荐