文档章节

图片或内容区域缩放及滚动

o
 osc_4nmshwhm
发布于 2018/08/07 10:37
字数 1428
阅读 0
收藏 0

钉钉、微博极速扩容黑科技,点击观看阿里云弹性计算年度发布会!>>>

因为最近公司的项目上有用到图片缩放及滚动的效果,而swiper在该项目上有一些问题,所以就决定自己写一个图片的缩放和滚动效果,以及回弹效果, 用的是面向对象的方式封装的, 因为是移动端的,所以用的

touch方法,HTML结构样式先放出来

  <div id="box">
    <div id="mask"></div>
    <div id="content">
      <img src="./11.jpg" alt="">
      <div>
        <table>
          <tr>
            <th>姓名</th>
            <th>手机号</th>
            <th>年龄</th>
            <th>性别</th>
          </tr>
          <tr id="tr">
            <td>六六六</td>
            <td>18437928787</td>
            <td>18</td>
            <td></td>
          </tr>
        </table>
      </div>
    </div>
  </div>
    * {
      padding: 0;
      margin: 0;
    }
    body,html {
      width: 100%;
      height: 100%;
    }
    #box {
      width: 100%;
      height: 100%;
      overflow: hidden;
      position: relative;
    }
    #content {
      position: absolute;
      top: 0;
      left: 0;
    }
    #mask {
      position: absolute;
      top: 0;
      left: 0;
      z-index: 10;
      width: 100%;
      height: 100%;
    }
    img {
      width: 100%;
      display: block;
    }

主要的缩放和滑动区域是content盒子,所以content里面随便放什么都无所谓, 这里的mask是一个遮罩层,层级大于content, 所有事件都绑定在了mask上, 这样做是因为, 如果content里的元素又小又多, 那么当双指进行缩放时,两个手指出碰到的不是同一元素, 获取到的e.target的目标会不一样,这样就会出问题, 所以设置这样一个遮罩层

function Scroll(ele) {
      this.box = document.querySelector(ele)
      this.content = document.querySelector('#content')
      this.mask = document.querySelector('#mask')
      this.data = {
        width: this.content.offsetWidth,  //获取内容区域的初始宽度
        height: this.content.offsetHeight,  //获取内容区域的初始高度
        currentWidth: this.content.offsetWidth,   //获取内容区域当前宽度  
        currentHeight: this.content.offsetHeight,   //获取内容区域当前高度
        startXA: 0,   //第一根手指的起始位置
        startYA: 0,   
        endXA: 0,   //第一根手指的结束位置
        endYA: 0,
        startXB: 0,   //第二根手指的起始位置
        startYB: 0,
        endXB: 0,   //第二根手指的结束位置
        endYB: 0,
        currentMultiple: 1,   //当前的缩放倍数
        multiple:1,   //缩放倍数
        positionY: 0,   //在Y轴的位置
        positionX: 0,   //在X轴的位置
        startTime: 0,   //手指触碰的起始时间
        endTime: 0,   //手指离开的结束时间
        centreX: 0,   //缩放位置的X轴坐标
        centreY: 0,   //缩放位置的Y轴坐标
        bool: false,    //用来判断是否是双指操作
        num: 0,   //用来判断屏幕上的手指数
        timer: null   //定时器
      }
      
      this.mask.ontouchstart = (e) => {
        this.touchBegin(e)
      }
      this.mask.ontouchmove = (e) => {
        this.touching(e)
      }
      this.mask.ontouchend = (e) => {
        this.touchFinish(e)
      }
    }

当触摸事件触发时,调用touchBegin事件

Scroll.prototype.touchBegin = function(e) {
      this.data.num++  //当调用这个方法时,num自增
      e.preventDefault()  //阻止浏览器滑动
      switch (e.targetTouches.length) {
        case 1:
          this.data.startXA = e.targetTouches[0].pageX  
          this.data.startYA = e.targetTouches[0].pageY
          this.data.startTime = new Date().getTime()
          break
        case 2:
          this.data.bool = true   //如果是双指操作,将bool的值置为true
          this.data.startXA = e.targetTouches[0].pageX
          this.data.startYA = e.targetTouches[0].pageY
          this.data.startXB = e.targetTouches[1].pageX
          this.data.startYB = e.targetTouches[1].pageY
          this.data.centreY = Math.abs((-this.data.positionY + this.data.startYA) - (-this.data.positionY + this.data.startYB)) / 2 + (-this.data.positionY + this.data.startYA)    
          this.data.centreX = Math.abs((-this.data.positionX + this.data.startXA) - (-this.data.positionX + this.data.startXB)) / 2 + (-this.data.positionX + this.data.startXA)
      }
    }

当手指滑动时, 触发touching事件

Scroll.prototype.touching = function(e) {
      switch (e.targetTouches.length) {
        case 1:
          if(!this.data.bool) {   //如果bool是false, 也就是说不是双手操作,或者刚刚结束双手操作,但只离开了一只手指
            this.data.endXA = e.targetTouches[0].pageX
            this.data.endYA = e.targetTouches[0].pageY
            let x= this.data.endXA - this.data.startXA+this.data.positionX    //content应在X轴上移动的距离
            let y= this.data.endYA - this.data.startYA+this.data.positionY    //content应在Y轴上移动的距离
            if(this.data.currentWidth === this.data.width) {    //判断当前的宽度与初始化时的宽度大小是否相等 , 如果相等,也就是说明没有进行缩放操作, 那么就只在Y轴进行移动
              this.content.style.transform = "translate(0,"+y+"px) scale("+this.data.multiple+")"
            } else {    //否则,就在X,Y轴上进行移动
              this.content.style.transform = "translate("+x+"px,"+y+"px) scale("+this.data.multiple+")"
            }
          }
          break
        case 2:
          this.data.endXA = e.targetTouches[0].pageX
          this.data.endYA = e.targetTouches[0].pageY
          this.data.endXB = e.targetTouches[1].pageX
          this.data.endYB = e.targetTouches[1].pageY
          this.content.style.transformOrigin = this.data.centreX+"px "+this.data.centreY+"px"   //设置缩放中心点坐标
          let multipleOne = Math.sqrt(Math.pow(Math.abs(this.data.startXA - this.data.startXB),2) + Math.pow(Math.abs(this.data.startYA - this.data.startYB),2))    //获取两只手指的起始直线距离
          let multipleTwo = Math.sqrt(Math.pow(Math.abs(this.data.endXA - this.data.endXB),2) + Math.pow(Math.abs(this.data.endYA - this.data.endYB),2))    //获取滑动时两只手指的直线距离
          let multiple = multipleTwo / multipleOne * this.data.currentMultiple    //获取放大倍数
          if(multiple < 1 ) {   //规定放大倍数,不能大于2且不能小于1
            multiple = 1
          }
          if(multiple > 2 ) {
            multiple = 2
          }
          this.data.multiple = multiple
          this.content.style.transform = "translate("+this.data.positionX+"px,"+this.data.positionY+"px) scale("+this.data.multiple+")"
          this.data.currentWidth = this.data.multiple * this.content.offsetWidth 
          this.data.currentHeight = this.data.multiple * this.content.offsetHeight
      }
    }

手指离开时,调用touchFinish事件

Scroll.prototype.touchFinish = function(e) {
      let limitTop = this.data.centreY*this.data.multiple - this.data.centreY   //获取上下左右的边界值(当图片进行缩放时,边界值也会发生改变,就是缩放中心到边界的距离*缩放倍数 - 缩放中心到边界的距离)
      let limitDown = (this.content.offsetHeight - this.data.centreY)*this.data.multiple - (this.content.offsetHeight - this.data.centreY)
      let limitLeft = this.data.centreX*this.data.multiple - this.data.centreX
      let limitRight = (this.content.offsetWidth - this.data.centreX)*this.data.multiple - (this.content.offsetWidth - this.data.centreX)
      this.data.num--   //num自减
      this.data.currentMultiple = this.data.multiple    
      let down = this.box.offsetHeight - this.content.offsetHeight
      let right = this.box.offsetWidth - this.content.offsetWidth
      this.data.endTime = new Date().getTime()
      this.data.positionY = this.content.style.transform.slice(this.content.style.transform.indexOf(',')+1,this.content.style.transform.indexOf(')')-2)-0
      this.data.positionX = this.content.style.transform.slice(this.content.style.transform.indexOf('(')+1,this.content.style.transform.indexOf(',')-2)-0
      if(this.data.endTime - this.data.startTime <300 && Math.abs(this.data.startYA-e.changedTouches[0].pageY)>50) {    //如果手指滑动时间小于300毫秒,并且距离大于50,则触发滑动缓冲效果
        let p = (this.data.endYA-this.data.startYA) * (1/(this.data.endTime - this.data.startTime)) * 100 + this.data.positionY   //缓冲的距离
        this.Drop(this.content,p,this.data.positionX)   //调用移动动画
      }
      this.data.timer = setTimeout(()=>{    //设置定时器,当手指离开200毫秒后触发边界判断
        if(this.data.positionY >= limitTop ){   //如果大于上边界,调用回弹动画,再判断左右边界是否超出
          this.Drop(this.content, limitTop,this.data.positionX)
          setTimeout(()=> {
            if(this.data.positionX >= limitLeft ){
            this.Drop(this.content,limitTop,limitLeft)
            }
            if(this.data.positionX <= right-limitRight) {
              this.Drop(this.content,limitTop,right-limitRight)
            }
          },200)
        }

        if(this.data.positionY <= -limitDown+down) {
          this.Drop(this.content,-limitDown+down,this.data.positionX)
          setTimeout(()=>{
            if(this.data.positionX >= limitLeft ){
              this.Drop(this.content,-limitDown+down,limitLeft)
            }
            if(this.data.positionX <= right-limitRight) {
              this.Drop(this.content,-limitDown+down,right-limitRight)
            }
          },200)
        }

        if(this.data.positionX >= limitLeft ){
          this.Drop(this.content,this.data.positionY,limitLeft)
        }

        if(this.data.positionX <= -limitRight+right) {
          this.Drop(this.content,this.data.positionY,right-limitRight)
        }
      },200)
      if(!this.data.num) {    //当两只手指都离开后, 将bool设置为false
        this.data.bool = false
      }
    }

移动动画方法

  Scroll.prototype.Drop = function(ele, positionY,positionX) {    //移动动画方式, 传入参数是目标元素, Y轴移动距离, X轴移动距离
      clearInterval(ele.timer);
      ele.timer = setInterval(() => {
        this.data.positionY = this.content.style.transform.slice(this.content.style.transform.indexOf(',')+1,this.content.style.transform.indexOf(')')-2)-0        
        this.data.positionX = this.content.style.transform.slice(this.content.style.transform.indexOf('(')+1,this.content.style.transform.indexOf(',')-2)-0
        var stepY = (positionY - this.data.positionY)/10
        var stepX = (positionX - this.data.positionX)/10
        stepY = stepY > 0 ? Math.ceil(stepY) : Math.floor(stepY); 
        stepX = stepX > 0 ? Math.ceil(stepX) : Math.floor(stepX);
        let longY = this.data.positionY + stepY
        let longX = this.data.positionX + stepX
        ele.style.transform = "translate("+longX+"px,"+longY+"px) scale("+this.data.multiple+")";
        if (Math.abs(positionY -  this.data.positionY) <= Math.abs(stepY) && Math.abs(positionX -  this.data.positionX) <= Math.abs(stepX)) {
          ele.style.transform = "translate("+positionX+"px,"+positionY+"px) scale("+this.data.multiple+")";
          this.data.positionX = positionX
          this.data.positionY = positionY
          clearInterval(ele.timer);
        }
      }, 10)
   }

 

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

OSChina 周三乱弹 —— 公主是大王的,命是自己的。小怪也要养家糊口啊!

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @巴拉迪维 :郭燕的单曲《下半生》 最近听一些轻快的歌 #今日歌曲推荐# 《下半生》 - 郭燕 手机党少年们想听歌,请使劲儿戳(这里) @锦年 :...

小小编辑
29分钟前
29
0
Git不断提示我输入密码 - Git keeps prompting me for a password

问题: I've been using Git for a while now, but the constant requests for a password are starting to drive me up the wall. 我已经使用Git一段时间了,但是不断要求输入密码的人开始把......

fyin1314
38分钟前
20
0
未捕获ReferenceError:未定义$? - Uncaught ReferenceError: $ is not defined?

问题: How come this code throws an 此代码如何引发 Uncaught ReferenceError: $ is not defined 未捕获的ReferenceError:未定义$ when it was OK before? 以前什么时候可以? $(document......

javail
今天
12
0
263. Ugly Number

题目: 263. Ugly Number 题目地址:https://leetcode.com/problems/ugly-number/ Write a program to check whether a given number is an ugly number. Ugly numbers are positive numbers......

JiaMing
今天
68
0
HCIA_ARP01

ARP(地址解析协议) eNSP 常用路由器:AR2220 常用交换机:S5700、S3700 常用终端:PC、MCS(主播服务器) 设备连线:Copper(以太网用到的双绞线)、Serial(串口线,2SA接口)、Auto(自动连...

创业789
今天
27
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部