# harmonyos-swipe **Repository Path**: xiaojin1233323/harmonyos-swipe ## Basic Information - **Project Name**: harmonyos-swipe - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-02-18 - **Last Updated**: 2022-02-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## HarmonyOS 自定义组件之swipe ### 初学鸿蒙技术不久,就想自己试着实现一下swipe组件。 当组件绑定autoplay属性为true时 , 即可开启自动播放,也可以手动去左右移动图片,并且会修改自动播放的播放方向。 ### 效果演示 ![mode](img/mode.gif) ### 实现思路 ##### 1.布局思路 通过对内外层盒子定位(父相子绝),外层盒子对溢出的内容进行隐藏,调整每个小盒子的left值来显示不同的图片内容。 ![1643094939429](img/1643094939429.png) ##### 2.移动实现 ```js //初始化赋值 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(); }, ``` ##### 3.自动播放 ```js 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) }, ``` ### 使用方法 ```vue 引入swipe组件 ``` ```js 在data中挂载图片路径数据并传入到swipe组件中 arr: [ '/common/images/a1.jpg', '/common/images/a2.jpg', '/common/images/a3.jpg', '/common/images/a4.jpg' ] ``` ```js 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.onReady生命周期中无法直接获取到dom元素,可以使用定时器来获取。 2.鸿蒙中无法直接获取dom元素的style属性 。 3.只有6以上的版本才支持transition属性,而且只支持个别属性拥有渐变效果 。 4.overflow属性好像并不支持,我就改用clip-path属性,它可以对不同区域进行裁剪。 ####