小程序自定义拖拽及裁剪

 背景需求

 当时做小程序时 遇到一个场景 用户拍摄照片=>智能解析题目=>页面回显框选

回显后,可能不是用户想要的某一区域或某一题,此时就需要用户手动编辑裁剪。先看下图片效果及视频演示

查看视频演示

看完后 我们来分析一下 

做的时候 我的第一反应就是canvas和movable-area的组合 但是怎么尝试都没有成功。然后去百度查看,各种杂七乱八的,都没有达到自己想要实现的效果。然后我就请教之前有做过的大佬,他给的答案是vanvas结合movable-area组合

先聊一下框选回显的问题吧 

误区

动态获取放图片盒子的大小 然后比上手机屏幕的大小得到比例 根据返回的坐标点*比例 画出所有框选位置

纠正

动态获取盒子的高度(目的是后续裁剪使用)把对放图片盒子的操作 给Image操作 

看下页面使用代码

    <view v-if="vdata.selectBox" class="photographMain">
      <view class="swiperMain">
        <view class="handelImg" v-if="!vdata.imgList.length">
          <nut-button loading type="warning"></nut-button>
          <view>图片处理中</view>
        </view>

        <swiper
          v-else
          @change="getCurrent"
          class="swiper"
          indicator-color="#999"
          indicator-active-color="#333"
          :circular="false"
          :indicator-dots="false"
          :current="vdata.current - 1"
        >
          <swiper-item v-for="(item, i) in vdata.imgList" :key="i">
            <view class="list-item">
              <image :src="item.originUrl" class="imageContent" :mode="computedFixed">
                <view class="mc">
                  <template v-if="item.contentListInfoList && item.contentListInfoList.length">
                    <view
                      class="mc-item"
                      v-for="(bg, key) in item.contentListInfoList"
                      :style="handlePosition(item, bg.point2dXYList)"
                      :key="key"
                    >
                      <view class="bj" @tap="editBox(item, bg.point2dXYList, bg)">编辑</view>
                      <view class="jj" v-show="!bg.isCheck">
                        <image
                          @tap="changeIsCheck(i, key, true)"
                          src="https://dcg-c-system.obs.cn-east-3.myhuaweicloud.com/ctb/69ddc2a38118419eb6815bb37f6fee70/addPot.png"
                          mode="scaleToFill"
                        />
                      </view>
                      <view class="jy" v-show="bg.isCheck">
                        <image
                          @tap="changeIsCheck(i, key, false)"
                          src="https://dcg-c-system.obs.cn-east-3.myhuaweicloud.com/ctb/5fb2d6d087aa44b1b42c405f364610ca/commit.png"
                          mode="scaleToFill"
                        />
                      </view>
                    </view>
                  </template>
                </view>
              </image>
            </view>
          </swiper-item>
        </swiper>
        <view class="current"> {
   
   { vdata.current }}/{
   
   { vdata.imgUrl.length }} </view>
      </view>
    </view>
    <view v-else class="welMain">
      <welCropper @cropdown="cropdown" :cropperOptions="vdata.cropperOptions" />
    </view>

然后看下 welCropper 有两个版本 一个vue的版本 一个react的版本 

就以vue版本为例吧

<template>
  <scroll-view :class="['cropper_main_container', data.cropperData.hidden ? 'hidden' : '']">
    <view
      class="cropper_container"
      :style="{ width: data.cropperData.W + 'px', height: data.cropperData.H + 'px' }"
    >
      <canvas
        class="original_canvas"
        canvas-id="originalCanvas"
        :style="{
          width: data.changableData.originalSize.width + 'px',
          height: data.changableData.originalSize.height + 'px',
        }"
      ></canvas>

      <image
        :src="data.cropperData.imageInfo.path"
        class="scale-image cropper_canvas_container_item"
        mode="aspectFill"
        :style="{
          left: data.changableData.previewImageInfo.x + 'px',
          top: data.changableData.previewImageInfo.y + 'px',
          width: data.changableData.previewImageInfo.w + 'px',
          height: data.changableData.previewImageInfo.h + 'px',
          transform: `rotate(${data.changableData.rotateDegree}deg)`,
        }"
      ></image>
      <!-- transform:rotate() -->

      <view
        :class="['cropper_canvas_container', data.cropperData.canvasType ? 'isOpacity' : '']"
        :style="{
          width: data.changableData.scaleSize.width + 'px',
          height: data.changableData.scaleSize.height + 'px',
        }"
      >
        <canvas
          :type="data.cropperData.canvasType || ''"
          :canvas-id="data.canvasId"
          class="move_canvas cropper_canvas_container_item"
        ></canvas>

        <template v-if="data.cropperData.drawSign == 1">
          <movable-area
            class="cropper_movable_area_container"
            :style="{
              width: data.changableData.scaleSize.width + 'px',
              height: data.changableData.scaleSize.height + 'px',
            }"
          >
            <template v-if="data.moveItems">
              <template v-for="(item, i) in data.moveItems" :key="i">
                <movable-view
                  class="move_item"
                  :style="{
                    width: data.cropperData.itemLength + 'px',
                    height: data.cropperData.itemLength + 'px',
                  }"
                  direction="all"
                  :x="item.x - data.cropperData.itemLength / 2"
                  :y="item.y - data.cropperData.itemLength / 2"
                  @touchmove="moveEvent"
                  @touchend="endEvent"
                  @touchcancel="touchcancelEvent"
                  :data-key="i"
                ></movable-view>
              </template>
            </template>
          </movable-area>
        </template>
        <template v-else>
          <movable-area
            class="cropper_movable_area_container"
            :style="{
              width: data.changableData.scaleSize.width + 'px',
              height: data.changableData.scaleSize.height + 'px',
            }"
          >
            <template v-if="data.moveItems">
              <template v-for="(item, i) in data.moveItems" :key="i">
                <movable-view
                  class="move_item"
                  style="width:{
   
   {data.cropperData.itemLength}}px; height:{
   
   {data.cropperData.itemLength}}px;"
                  direction="all"
                  :x="item.x - data.cropperData.itemLength / 2"
                  :y="item.y - data.cropperData.itemLength / 2"
                  @touchmove="moveEvent"
                  @touchend="endEvent"
                  @touchcancel="touchcancelEvent"
                  data-key="{
   
   {index}}"
                ></movable-view>
              </template>
            </template>
          </movable-area>
        </template>
      </view>
    </view>
  </scroll-view>
</template>

遇到的坑及注意事项

1.封装组件时 外围盒子要定位

2.移动时,移动点位有偏差 (这里是100%等比例缩放的 如果自定义navbar需要减去所有以外的padding,margin,height)

3.一个页面反反复复使用 会遇到报错(canvas id已经使用了 不能再次使用) 动态设置cancasId

4.框选回显,坐标点位有偏差(始终保持图片大小等比例缩放 回显坐标不能使用px 最好使用%)

5.通过createSelectorQuery获取高度时,没有获取到 设置setTimerOut获取

这是welCropper所有的template代码 可以尝试根据代码去反推逻辑,有兴趣的小伙伴可以私信我或加wx:Darren_jm  备注csdn 获取全部代码

猜你喜欢

转载自blog.csdn.net/xy19950125/article/details/129712765