zoukankan      html  css  js  c++  java
  • 拖拽一个元素如此简单,mouse、drag、touch三兄弟的用处

    最近需要做一个投票活动,上传图片时需要拖拽、缩放来裁剪图片,vue的组件不少,不过自己动手才能丰衣足食,一味使用别人的组件实在难以进步,所以自己研究一番。

    一、mouse、drag、touch傻傻分不清

    1. mouse:pc端的鼠标按下、移动等事件 
      (1)、mousedown:
      当鼠标指针移动到元素上方,并按下鼠标按键时,会发生mousedown事件。
              与 click 事件不同,mousedown 事件仅需要按键被按下,而不需要松开即可发生。mousedown()方法触发 mousedown 事件,或规定当发生mousedown事件 时运行的函数。
      (2)、mouseenter:当鼠标指针穿过元素时,会发生 mouseenter 事件。
              该事件大多数时候会与mouseleave事件一起使用。mouseenter()方法触发mouseenter事件,或规定当发生mouseenter事件时运行的函数。(与mouseover事件不同,只有在鼠标指针穿过被选元素时,才会触mouseenter 事件。如果鼠标指针穿过任何子元素,同样会触发mouseover事件。)
      (3)、mouseleave:当鼠标指针离开元素时,会发生mouseleave事件。该事件大多数时候会与mouseenter事件一起使用。
              mouseleave()方法触发mouseleave事件,或规定当发生mouseleave事件时运行的函数。(与mouseout事件不同,只有在鼠标指针离开被选元素时,才会触发mouseleave事件。如果鼠标指针离开任何子元素,同样会触发mouseout事件。)
      (4)、mousemove:当鼠标指针在指定的元素中移动时,就会发生mousemove事件。
              mousemove()方法触发mousemove事件,或规定当发生mousemove事件时运行的函数。(注意:用户把鼠标移动一个像素,就会发生一次mousemove事件。处理所有 mousemove 事件会耗费系   统资源。请谨慎使用该事件。)
      (5)、mouseout:当鼠标指针从元素上移开时,发生mouseout事件。该事件大多数时候会与mouseover事件一起使用。
              mouseout()方法触发mouseout事件,或规定当发生 mouseout 事件时运行的函数。(与mouseleave事件不同,不论鼠标指针离开被选元素还是任何子元素,都会触发 mouseout 事件。只有在鼠标指针离开被选元素时,才会触发mouseleave事件。)
      (6)、mouseover:当鼠标指针位于元素上方时,会发生 mouseover 事件。该事件大多数时候会与mouseout事件一起使用。
              mouseover()方法触发 mouseover 事件,或规定当发生mouseover事件时运行的函数。(与 mouseenter 事件不同,不论鼠标指针穿过被选元素或其子元素,都会触发mouseover事件。只有在鼠标指针穿过被选元素时,才会触发 mouseenter 事件。)
      (7)、mouseup:当在元素上放松鼠标按钮时,会发生mouseup事件。与 click 事件不同,mouseup 事件仅需要放松按钮。当鼠标指针位于元素上方时,放松鼠标按钮就会触发该事件。mouseup()方法触发mouseup事件,或规定当发生mouseup事件时运行的函数。
      <div @mousedown="gMousedown"
           @mouseenter="gMouseenter"
           @mouseleave="gMouseleave"
           @mousemove="gMousemove"
           @mouseout="gMouseout" 
           @mouseover="gMouseover" 
           @mouseup="gMouseup">
           试一试移动
      </div>
      
      methods:{
                  gMousedown(e){
                      console.log("鼠标左键按下了");
                      console.log(e)
                  },
                  gMouseenter(e){
                      console.log("鼠标穿过了");
                      console.log(e)
                  },
                  gMouseleave(e){
                      console.log("鼠标离开了");
                      console.log(e)
                  },
                  gMousemove(e){
                      console.log("鼠标移动了");
                      console.log(e)
                  },
                  gMouseout(e){
                      console.log("鼠标移开了");
                      console.log(e)
                  },
                  gMouseover(e){
                      console.log("鼠标在元素上面了");
                      console.log(e)
                  },
                  gMouseup(e){
                      console.log("鼠标松开了");
                      console.log(e)
                  }
              }
    2. drag:pc端的鼠标事件,鼠标左键按下并且拖动
      (1)、在被拖动目标上触发的事件:
        ondragstart:在用户开始拖动元素或选择的文本时触发(为了让元素可拖动,需要使用draggable属性,链接和图片默认是可拖动的,不需要 draggable 属性)
        ondrag:元素正在拖动时触发
             ondragend:用户完成元素拖动后触发
      (2)、在其他对象容器中触发的事件:
             ondragenter:当被鼠标拖动的对象进入其容器范围内时触发此事件
        ondragover:当某被拖动的对象在另一对象容器范围内拖动时触发此事件
             ondragleave:当被鼠标拖动的对象离开其容器范围内时触发此事件
             ondrop:在一个拖动过程中,释放鼠标键时触发此事件
      <template>
          <div style="margin-top: 66px;">
              <div class="drag-container">
                  <p v-for="item in list"
                     draggable="true"
                     @dragstart="dragstart($event,item,'list')"
                     @dragend="dragend($event,item)"
                  >{{item.name}}</p>
              </div>
              <div class="drop-container">
                  <p>分层</p>
                  <div class="drop-area" v-if="showLayer"
                       @drop="drop($event,'layer')"
                       @dragenter="dragenter"
                       @dragover="dragover"
                  >
                      <p v-for="(item,index) in layer">
                          <span
                                  draggable="true"
                                  @dragstart="dragstart($event,item,'layer',index)"
                          >{{item.name}}</span>
                          <b v-if="index!==layer.length-1">-></b>
                      </p>
                  </div>
                  <p>维度</p>
                  <div class="drop-area"
                       @drop="drop($event,'dimensions')"
                       @dragover="dragover">
                      <span v-for="(item,index) in dimensions"
                            @drop="dropToItem($event,item)"
                            @dragover.prevent
                            draggable="true"
                            @dragstart="dragstart($event,item,'dimensions',index)"
                      >{{item.name}}</span>
                  </div>
                  <p>对比</p>
                  <div class="drop-area"
                       @drop="drop($event,'contrasts')"
                       @dragover="dragover">
                      <span v-for="(item,index) in contrasts"
                            @dragover.prevent
                            draggable="true"
                            @dragstart="dragstart($event,item,'contrasts',index)"
                      >{{item.name}}</span>
                  </div>
              </div>
          </div>
      </template>
      
      <script>
          export default {
              data() {
                  return {
                      dragItem: {},//拖动的字段
                      dragFrom: '',//拖动从哪开始
                      dragIndex: '',//拖动的字段在数组中的索引
                      dropIndex: '',//放入地方的字段的索引
                      showLayer: false,//是否显示分层
                      isDropToItem: false,//是否是拖动到维度字段中进行分层操作
                      layer: [],
                      dimensions: [],
                      contrasts: [],
                      list: [
                          {
                              id: 1,
                              name: '姓名'
                          }, {
                              id: 2,
                              name: '性别'
                          }, {
                              id: 3,
                              name: '年龄'
                          }, {
                              id: 4,
                              name: '分数'
                          }]
                  }
              },
              methods: {
                  //拖拽开始
                  dragstart(event, item, frm, index) {
                      console.log('拖拽开始');
                      console.log(event);
                      console.log(item);
                      console.log(frm);
                      console.log(index);
                      const that = this;
                      event.dataTransfer.setData("Text", event.target.id);
                      that.dragItem = item;
                      that.dragFrom = frm;
                      if (!isNaN(index)) {
                          that.dragIndex = index;
                      }
                  },
                  //进入拖拽区域,进入时触发一次
                  dragenter(event) {
                      console.log('进入拖拽区域,进入时触发一次');
                      console.log(event);
                  },
                  //进入拖拽区域后多次触发
                  dragover(event) {
                      console.log("进入拖拽区域后多次触发");
                      console.log(event);
                      const that = this;
                      event.preventDefault();
                      let target = event.target;
                      that.dropIndex = that.indexFn(target);
                      let nodeName = target.nodeName;
                      if (nodeName !== 'SPAN') {
                          that.dropIndex = -1;
                      }
                  },
                  //松开鼠标完成拖拽后触发
                  drop(event, target) {
                      console.log('松开鼠标完成拖拽后触发');
                      console.log(event);
                      console.log(target);
                      const that = this;
                      let dragFrom = that.dragFrom;
                      let dragItem = that.dragItem;
                      let dragIndex = that.dragIndex;
                      let dropIndex = that.dropIndex;
                      if (that.isDropToItem) {
                          return;
                      }
                      if (that.dragFrom === 'layer') {
                          that.layer.splice(dragIndex, 1);
                      } else if (that.dragFrom === 'dimensions') {
                          that.dimensions.splice(dragIndex, 1);
                      } else if (that.dragFrom === 'contrasts') {
                          that.contrasts.splice(dragIndex, 1);
                      }
                      if (dragFrom === target && dropIndex > -1) {
                          let targetArr = that[target];
                          targetArr.splice(dropIndex, 0, dragItem);
                          return;
                      }
      
                      if (target === 'layer') {
                          that.layer.push(dragItem);
                      } else if (target === 'dimensions') {
                          that.dimensions.push(dragItem);
                      } else if (target === 'contrasts') {
                          that.contrasts.push(dragItem);
                      }
                  },
                  //拖动到维度第一个字段时触发
                  dropToItem(event, item) {
                      console.log('拖动到维度第一个字段时触发');
                      console.log(event);
                      console.log(item);
                      const that = this;
                      if (that.dragFrom !== 'list') {
                          that.isDropToItem = false;
                          return;
                      } else {
                          that.isDropToItem = true
                      }
                      if (that.showLayer) {
                          that.layer.push(this.dragItem);
                      } else {
                          that.showLayer = true;
                          that.layer.push(item);
                          that.layer.push(this.dragItem);
                      }
                  },
                  //拖拽结束后触发,不管是否拖拽成功
                  dragend(event, item) {
                      console.log('拖拽结束后触发,不管是否拖拽成功');
                      console.log(event);
                      console.log(item);
                      const that = this;
                      that.isDropToItem = false
                  },
                  //判断拖动字段的所以,用于排序
                  indexFn(el) {
                      let index = 0;
                      if (!el || !el.parentNode) {
                          return -1;
                      }
                      while (el && (el = el.previousElementSibling)) {
                          index++;
                      }
                      return index;
                  },
              }
          }
      </script>
      <style scoped lang="less">
          /* css部分 */
          .drag-container {
               66px;
              height: 500px;
              float: left;
              background-color: #BAB5F5;
              p {
                  line-height: 40px;
                  text-align: center;
                  cursor: pointer;
              }
          }
          .drop-container {
              margin-left: 120px;
              float: left;
              height: 500px;
               600px;
              p {
                  color: #fff;
                  line-height: 40px;
              }
              .drop-area {
                  height: 80px;
                   600px;
                  background-color: #4c72ff;
                  padding: 10px;
                  p {
                      display: inline-block;
                      margin: 0;
                  }
                  span {
                      display: inline-block;
                      min- 50px;
                      line-height: 40px;
                      margin-right: 5px;
                      background-color: #5a3e99;
                      text-align: center;
                      cursor: pointer;
                  }
              }
          }
      </style>
    3. touch:移动端的触摸事件,触发的条件是手指按在屏幕上并且移动(手指不能离开屏幕)
      (1)、touchstart:当手指触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发。
      (2)、touchmove:当手指在屏幕上滑动时连续的触发。在这个事件发生期间,调用preventDefault()可阻止滚动。
      (3)、touchend:当手指从屏幕上移开时触发。
      (4)、touchcancel:当系统停止跟踪触摸时触发。关于此事件的确切触发事件,文档中没有明确说明。
      3.1、以上event对象都包含以下属性:
      (1)、touches:表示当前跟踪的触摸操作的Touch对象的数组。

      (2)、targetTouches:特定于事件目标的Touch对象的数组。
      (3)、changeTouches:表示自上次触摸以来发生了什么改变的Touch对象的数组。
      3.2、每个Touch对象包含下列属性:
      (1)、clientX:触摸目标在视口中的X坐标。
      (2)、clientY:触摸目标在视口中的Y坐标。

      (3)、identifier:表示触摸的唯一ID。
      (4)、pageX:触摸目标在页面中的x坐标。
      (5)、pageY:触摸目标在页面中的y坐标。
      (6)、screenX:触摸目标在屏幕中的x坐标。
      (7)、screenY:触摸目标在屏幕中的y坐标。
      (8)、target:触摸的DOM节点坐标

    二、运用touch实现图片手势推拽、缩放裁剪图片

    1. 通过touchstart和touchmove实现拖拽图片:
      (1)、touchstart:获取touches[0]的pageX,pageY来更新scxscy以及更新iXiY
      (2)、touchmovw:获取touches[0]的pageX,声明变量f1x存放,移动后的x坐标等于iX + f1x - scx,y坐标同理,最后调用_drawImage来更新图片

    2. 通过event.touches的数量判断是否是单指或双指实现图片缩放:
      (1)、缩放后图片的宽高:图片初始宽度*缩放倍率和图片初始高度*缩放倍率
      (1)、缩放倍率:首先在touchstart事件上求取两手指间的距离d1;然后在touchmove事件上继续求取两手指间的距离d2当前缩放倍率= 初始缩放倍率 + (d2-d1) / 步长
      (1)、缩放后图片左上角的坐标值:首先要找到一个缩放中心(先取双指的中点坐标,但是这个坐标必须要位于图片上,如果不在图片上,则取图片上离该中点坐标最近的点),通过等式(缩放中心x坐标 - 缩放后图片左上角x坐标)/ 缩放后图片的宽度 = (缩放中心x坐标 - 缩放前图片左上角x坐标)/ 缩放前图片的宽度;(y坐标同理)

    3. 通过canvas画布截取画布中的图片
      <template>
          <div class="clipper-container" ref="clipper">
              <canvas ref="canvas"></canvas>
              <!-- 裁剪部分 -->
              <div class="clipper-part">
                  <div class="pCanvas-container">
                      <canvas ref="pCanvas"></canvas>
                  </div>
              </div>
              <!-- 底部操作栏 -->
              <div class="action-bar">
                  <button class="btn-cancel" @click="cancel">取消</button>
                  <button class="btn-ok" @click="clipper">确认</button>
              </div>
              <!-- 背景遮罩 -->
              <div class="mask" :class="{opacity: maskShow}"></div>
              <!-- 手势操作层 -->
              <div class="gesture-mask" ref="gesture" @touchstart="getTouchstart" @touchmove="getTouchmove" @touchend="getTouchend"></div>
          </div>
      </template>
      
      <style lang="less">
          .position() {
              position: absolute;
              top: 0;
              bottom: 0;
              left: 0;
              right: 0;
              z-index: 100;
          }
          .clipper-container {
              .position();
              line-height: 0;
              background-color: #000;
              .clipper-part {
                  .position();
                  bottom: 61px;
                  z-index: 102;
                  .pCanvas-container {
                      position: absolute;
                      top: 50%;
                      left: 50%;
                      transform: translate(-50%, -50%);
                      border: 2px solid #fff;
                  }
              }
              .action-bar {
                  box-sizing: content-box;
                  .position();
                  top: auto;
                  z-index: 103;
                  height: 60px;
                  line-height: 60px;
                  border-top: 1px solid rgba(256, 256, 256, 0.3);
                  button {
                      display: block;
                      padding: 0 15px;
                      line-height: 60px;
                      font-size: 16px;
                      color: #fff;
                      background: none;
                      border: none;
                      outline: 0;
                      &.btn-cancel {
                          float: left;
                      }
                      &.btn-ok {
                          float: right;
                      }
                  }
              }
              .mask {
                  .position();
                  z-index: 101;
                  transition: opacity 500ms;
                  background-color: #000;
                  opacity: 0;
                  &.opacity {
                      opacity: 0.8;
                  }
              }
              .gesture-mask {
                  .position();
                  bottom: 61px;
                  z-index: 103;
              }
          }
      </style>
      
      <script>
          export default {
              name: 'imageTailor',
              props: {
                  img: String, //url或dataUrl
                  clipperImgWidth: {
                      type: Number,
                      default: 500
                  },
                  clipperImgHeight: {
                      type: Number,
                      default: 200
                  }
              },
              watch: {
                  img() {
                      const that = this;
                      that.loadImgQueue.push(that.img);
                      that.loadImg();
                  }
              },
              data() {
                  return {
                      originXDiff: 0, //裁剪canvas与原图canvas坐标原点上的差值
                      originYDiff: 0,
                      maskShow: true,
                      maskShowTimer: null,
                      ctx: null,
                      pCtx: null,
                      actionBarHeight: 61,
                      loadImgQueue: [], //加载图片队列
                      imageData: null,
                      imgLoaded: false,
                      imgLoading: false,
                      imgStartWidth: null,
                      imgStartHeight: null,
                      imgCurrentWidth: null,
                      imgCurrentHeight: null,
                      imgX: null, //img对于canvas的坐标
                      imgY: null,
                      imgScale: 1, //图片目前的缩放倍数 范围是1-5
                      imgMinScale: 1,
                      imgMaxScale: 5,
                      imgScaleStep: 60, //缩放步长,每60px加减0.1
                      //图片canvas宽高
                      cWidth: 0,
                      cHeight: 0,
                      scx:0,//对于单手操作是移动的起点坐标,对于缩放是图片距离两手指的中点最近的图标。
                      scy:0,
                      iX:0,
                      iY:0,
                  }
              },
              mounted() {
                  setTimeout(() => {
                      this.initClipper();
                  }, 10);
              },
              beforeDestroy() {
                  let getGesture = this.$refs.gesture;
                  getGesture.ontouchstart = null;
                  getGesture.ontouchmove = null;
                  getGesture.outouchend = null;
              },
              methods: {
                  initClipper() {
                      const that = this;
                      that.loadImgQueue.push(that.img);
                      that.initCanvas();
                      that.loadImg();
                      // that.initCanvas();
                  },
                  initCanvas() {
                      const that = this;
                      let getCanvas = that.$refs.canvas,
                          getPCanvas = that.$refs.pCanvas,
                          clipperClientRect = that.$refs.clipper.getBoundingClientRect(),
                          clipperWidth = parseInt(that.clipperImgWidth / window.devicePixelRatio),
                          clipperHeight = parseInt(that.clipperImgHeight / window.devicePixelRatio);
                      that.ctx = getCanvas.getContext('2d');
                      that.pCtx = getPCanvas.getContext('2d');
                      //判断clipperWidth与clipperHeight有没有超过容器值
                      if (clipperWidth < 0 || clipperWidth > clipperClientRect.width) {
                          clipperWidth = 250
                      }
                      if (clipperHeight < 0 || clipperHeight > clipperClientRect.height) {
                          clipperHeight = 100
                      }
                      //因为canvas在手机上会被放大,因此里面的内容会模糊,这里根据手机的devicePixelRatio来放大canvas,然后再通过设置css来收缩,因此关于canvas的所有值或坐标都要乘以devicePixelRatio
                      getCanvas.style.width = clipperClientRect.width + 'px';
                      getCanvas.style.height = clipperClientRect.height-50 + 'px';
                      getCanvas.width = that.ratio(clipperClientRect.width);
                      getCanvas.height = that.ratio(clipperClientRect.height-50);
                      getPCanvas.style.width = clipperWidth + 'px';
                      getPCanvas.style.height = clipperHeight-50 + 'px';
                      getPCanvas.width = that.ratio(clipperWidth);
                      getPCanvas.height = that.ratio(clipperHeight-50);
                      //计算两个canvas原点的x y差值
                      let cClientRect = getCanvas.getBoundingClientRect(),
                          pClientRect = getPCanvas.getBoundingClientRect();
                      that.originXDiff = pClientRect.left - cClientRect.left;
                      that.originYDiff = pClientRect.top - cClientRect.top;
                      that.cWidth = cClientRect.width;
                      that.cHeight = cClientRect.height;
                  },
                  getTouchstart(event){
                      const that = this;
                      let cClientRect = this.$refs.canvas.getBoundingClientRect(),
                          fingers = {}; //记录当前有多少只手指在触控屏幕
                      event.preventDefault();
                      //two finger
                      let figureDistance = 0;
                      if (!that.imgLoaded) {
                          return;
                      }
                      if (event.touches.length === 1) {
                          let finger = event.touches[0];
      
                          that.scx = finger.pageX;
                          that.scy = finger.pageY;
                          that.iX = that.imgX;
                          that.iY = that.imgY;
                          fingers[finger.identifier] = finger;
                      } else if (event.touches.length === 2) {
                          let finger1 = event.touches[0],
                              finger2 = event.touches[1],
                              f1x = finger1.pageX - cClientRect.left,
                              f1y = finger1.pageY - cClientRect.top,
                              f2x = finger2.pageX - cClientRect.left,
                              f2y = finger2.pageY - cClientRect.top;
      
                          that.scx = parseInt((f1x + f2x) / 2);
                          that.scy = parseInt((f1y + f2y) / 2);
                          figureDistance = that.pointDistance(f1x, f1y, f2x, f2y);
                          fingers[finger1.identifier] = finger1;
                          fingers[finger2.identifier] = finger2;
      
                          //判断变换中点是否在图片中,如果不是则去离图片最近的点
                          if (that.scx < that.imgX) {
                              that.scx = that.imgX;
                          }
                          if (that.scx > that.imgX + that.imgCurrentWidth) {
                              that.scx = that.imgX + that.imgCurrentHeight;
                          }
                          if (that.scy < that.imgY) {
                              that.scy = that.imgY;
                          }
                          if (that.scy > that.imgY + that.imgCurrentHeight) {
                              that.scy = that.imgY + that.imgCurrentHeight;
                          }
                      }
                  },
                  getTouchmove(event){
                      const that = this;
                      let cClientRect = that.$refs.canvas.getBoundingClientRect(),
                          fingers = {}; //记录当前有多少只手指在触控屏幕
                      //two finger
                      let figureDistance = 0,
                          pinchScale = that.imgScale;
                      event.preventDefault();
                      if (!that.imgLoaded) {
                          return;
                      }
                      that.maskShowTimer && clearTimeout(that.maskShowTimer);
                      that.maskShow = false;
      
                      if (event.touches.length === 1) {
                          let f1x = event.touches[0].pageX,
                              f1y = event.touches[0].pageY;
                          that.drawImage(that.iX + f1x - that.scx, that.iY + f1y - that.scy, that.imgCurrentWidth, that.imgCurrentHeight);
                      } else if (event.touches.length === 2) {
                          let finger1 = event.touches[0],
                              finger2 = event.touches[1],
                              f1x = finger1.pageX - cClientRect.left,
                              f1y = finger1.pageY - cClientRect.top,
                              f2x = finger2.pageX - cClientRect.left,
                              f2y = finger2.pageY - cClientRect.top,
                              newFigureDistance = that.pointDistance(f1x, f1y, f2x, f2y),
                              scale = that.imgScale + parseFloat(((newFigureDistance - figureDistance) / that.imgScaleStep).toFixed(1));
      
                          fingers[finger1.identifier] = finger1;
                          fingers[finger2.identifier] = finger2;
      
                          if (scale !== pinchScale) {
                              //目前缩放的最小比例是1,最大是5
                              if (scale < that.imgMinScale) {
                                  scale = that.imgMinScale;
                              } else if (scale > that.imgMaxScale) {
                                  scale = that.imgMaxScale;
                              }
      
                              pinchScale = scale;
                              that.scale(that.scx, that.scy, scale);
                          }
                      }
                  },
                  getTouchend(event){
                      const that = this;
                      let fingers = {}; //记录当前有多少只手指在触控屏幕
                      //two finger
                      let pinchScale = that.imgScale;
                      if (!that.imgLoaded) {
                          return;
                      }
                      that.imgScale = pinchScale;
      
                      //从finger删除已经离开的手指
                      let touches = Array.prototype.slice.call(event.changedTouches, 0);
      
                      touches.forEach(item => {
                          delete fingers[item.identifier];
                      });
      
                      //迭代fingers,如果存在finger则更新scx,scy,iX,iY,因为可能缩放后立即单指拖动
                      let i,
                          fingerArr = [];
      
                      for(i in fingers) {
                          if (fingers.hasOwnProperty(i)) {
                              fingerArr.push(fingers[i]);
                          }
                      }
      
                      if (fingerArr.length > 0) {
                          that.scx = fingerArr[0].pageX;
                          that.scy = fingerArr[0].pageY;
                      } else {
                          that.maskShowTimer = setTimeout(() => {
                              that.maskShow = true;
                          }, 300);
                      }
      
                      //做边界值检测
                      let x = that.imgX,
                          y = that.imgY,
                          pClientRect = that.$refs.pCanvas.getBoundingClientRect();
      
                      if (x > pClientRect.left + pClientRect.width) {
                          x = pClientRect.left
                      } else if (x + that.imgCurrentWidth < pClientRect.left) {
                          x = pClientRect.left + pClientRect.width - that.imgCurrentWidth;
                      }
      
                      if (y > pClientRect.top + pClientRect.height) {
                          y = pClientRect.top;
                      } else if (y + that.imgCurrentHeight < pClientRect.top) {
                          y = pClientRect.top + pClientRect.height - that.imgCurrentHeight;
                      }
      
                      if (that.imgX !== x || that.imgY !== y) {
                          that.drawImage(x, y, that.imgCurrentWidth, that.imgCurrentHeight);
                      }
                  },
                  loadImg() {
                      const that = this;
                      if (that.imgLoading || that.loadImgQueue.length === 0) {
                          return;
                      }
                      let img = that.loadImgQueue.shift();
      
                      if (!img) {
                          return;
                      }
                      let newImage = new Image(),
                          onLoad = e => {
                              newImage.removeEventListener('load', onLoad, false);
                              that.imageData = newImage;
                              that.imgLoaded = true;
                              that.imgLoading = false;
                              that.initImg(newImage.width, newImage.height);
                              that.loadImg();
                          },
                          onError = e => {
                              newImage.removeEventListener('error', onError, false);
                              that.imageData = newImage = null;
                              that.imgLoading = false;
                              that.loadImg();
                          };
                      that.imgLoading = true;
                      that.imgLoaded = false;
                      newImage.src = that.img;
                      newImage.crossOrigin = 'Anonymous'; //因为canvas toDataUrl不能操作未经允许的跨域图片,这需要服务器设置Access-Control-Allow-Origin头
                      newImage.addEventListener('load', onLoad, false);
                      newImage.addEventListener('error', onError, false);
                  },
                  initImg(w, h) {
                      const that = this;
                      let eW = null,
                          eH = null,
                          maxW = that.cWidth,
                          maxH = that.cHeight - that.actionBarHeight;
      
                      //如果图片的宽高都少于容器的宽高,则不做处理
                      if (w <= maxW && h <= maxH) {
                          eW = w;
                          eH = h;
                      } else if (w > maxW && h <= maxH) {
                          eW = maxW;
                          eH = parseInt(h / w * maxW);
                      } else if (w <= maxW && h > maxH) {
                          eW = parseInt(w / h * maxH);
                          eH = maxH;
                      } else {
                          //判断是横图还是竖图
                          if (h > w) {
                              eW = parseInt(w / h * maxH);
                              eH = maxH;
                          } else {
                              eW = maxW;
                              eH = parseInt(h / w * maxW);
                          }
                      }
      
                      if (eW <= maxW && eH <= maxH) {
                          //记录其初始化的宽高,日后的缩放功能以此值为基础
                          that.imgStartWidth = eW;
                          that.imgStartHeight = eH;
                          that.drawImage((maxW - eW) / 2, (maxH - eH) / 2, eW, eH);
                      } else {
                          that.initImg(eW, eH);
                      }
                  },
                  drawImage(x, y, w, h) {
                      const that = this;
                      that.clearCanvas();
                      that.imgX = parseInt(x);
                      that.imgY = parseInt(y);
                      that.imgCurrentWidth = parseInt(w);
                      that.imgCurrentHeight = parseInt(h);
      
                      //更新canvas
                      that.ctx.drawImage(that.imageData, that.ratio(x), that.ratio(y), that.ratio(w), that.ratio(h));
      
                      //更新pCanvas,只需要减去两个canvas坐标原点对应的差值即可
                      this.pCtx.drawImage(this.imageData, this.ratio(x - this.originXDiff), this.ratio(y - this.originYDiff), this.ratio(w), this.ratio(h));
                  },
                  clearCanvas() {
                      const that = this;
                      let getCanvas = that.$refs.canvas,
                          getPCanvas = that.$refs.pCanvas;
                      getCanvas.width = getCanvas.width;
                      getCanvas.height = getCanvas.height;
                      getPCanvas.width = getPCanvas.width;
                      getPCanvas.height = getPCanvas.height;
                  },
                  ratio(size) {
                      return parseInt(window.devicePixelRatio * size);
                  },
                  pointDistance(x1, y1, x2, y2) {
                      return parseInt(Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
                  },
                  scale(x, y, scale) {
                      const that = this;
                      let newPicWidth = parseInt(that.imgStartWidth * scale),
                          newPicHeight = parseInt(that.imgStartHeight * scale),
                          newIX = parseInt(x - newPicWidth * (x - that.imgX) / that.imgCurrentWidth),
                          newIY = parseInt(y - newPicHeight * (y - that.imgY) / that.imgCurrentHeight);
                      that.drawImage(newIX, newIY, newPicWidth, newPicHeight);
                  },
                  clipper() {
                      const that = this;
                      let imgData = null;
                      try {
                          imgData = that.$refs.pCanvas.toDataURL();
                      } catch (e) {
                          console.error('请在response header加上Access-Control-Allow-Origin,否则canvas无法裁剪未经许可的跨域图片');
                      }
                      this.$emit('getNewImage', imgData);
                  },
                  cancel() {
                      this.$emit('cancel');
                  },
                  getBase64(dataURL) {
                      return dataURL.replace(/^data:image/(png|jpg);base64,/, '');
                  }
              }
          }
      </script>

    最后,ε=(´ο`*)))唉路漫漫其修远兮,我这只后端的小菜鸟在前端的路上还要奋力向前,不说了接着接收运营大佬的神仙建议去了~~

  • 相关阅读:
    ubuntu 14.04 下试用Sublime Text 3
    闲来无事,温习一下快速排序法
    学艺不精,又被shell的管道给坑了
    ssh登录失败处理步骤
    linux文件权限整理
    使用ssh远程执行命令批量导出数据库到本地
    leetcode-easy-design-384 Shuffle an Array
    leetcode-easy-dynamic-198 House Robber-NO
    leetcode-easy-dynamic-53 Maximum Subarray
    leetcode-easy-dynamic-121 Best Time to Buy and Sell Stock
  • 原文地址:https://www.cnblogs.com/dinghaoran/p/14212237.html
Copyright © 2011-2022 走看看