当前位置: 首页 > news >正文

图片的拖拽+缩放

效果图:

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import ImgBg from '@/assets/img/bg.jpg'
import Img1 from '@/assets/img/1.jpg'

const innerStyle = ref({
  left: 0,
  top: 0,
  width: 100,
  height: 0
})
const wrapStyle = ref({
  width: 500,
  height: 0,
})
let bgRatio//原始背景图片分辨率比例
let roleRatio: number//原始role图片分辨率比例
onMounted(() => {
  const imageBg = new Image()
  imageBg.src = ImgBg
  imageBg.onload = () => {
    bgRatio = imageBg.width / imageBg.height
    wrapStyle.value.height = wrapStyle.value.width / bgRatio
  }
  const imageRole = new Image()
  imageRole.src = Img1
  imageRole.onload = () => {
    roleRatio = imageRole.width / imageRole.height
    innerStyle.value.height = innerStyle.value.width / roleRatio
  }
})
const isDrag = ref(false)
const isScale = ref(false)
const refBgWrap = ref()
const refRoleWrap = ref()
const direction = ref(['left-top', 'right-top', 'left-bottom', 'right-bottom'])
const directionType = ref('')
onMounted(() => {
  window.addEventListener('mousemove', (e) => {
    const { width: bwidth, height: bheight } = refRoleWrap.value!.getBoundingClientRect()
    const { width: awidth, height: aheight } = refBgWrap.value!.getBoundingClientRect()
    if (!isDrag.value) return
    const { movementX, movementY } = e
    let maxLeft = awidth - bwidth
    let maxTop = aheight - bheight
    let x = Number(innerStyle.value.left) + movementX
    let y = Number(innerStyle.value.top) + movementY
    if (x <= 0) {
      x = 0
    } else if (x >= maxLeft) {
      x = maxLeft
    }
    if (y <= 0) {
      y = 0
    } else if (y >= maxTop) {
      y = maxTop
    }
    if (isDrag.value) {
      if (isScale.value) {
        if (x >= 0 && x < maxLeft && y >= 0 && y < maxTop) {
          switch (directionType.value) {
            case 'left-top':
              //改变x+y+width+height
              innerStyle.value.width = innerStyle.value.width - movementX
              innerStyle.value.height = innerStyle.value.height - movementX / roleRatio
              innerStyle.value.left = x
              innerStyle.value.top = y
              break
            case 'right-top':
              //改变y+width+height
              innerStyle.value.width = innerStyle.value.width + movementX
              innerStyle.value.height = innerStyle.value.height + movementX / roleRatio
              innerStyle.value.top = y
              break
            case 'left-bottom':
              //改变x+width+height
              innerStyle.value.width = innerStyle.value.width - movementX
              innerStyle.value.height = innerStyle.value.height - movementX / roleRatio
              innerStyle.value.left = x
              break
            case 'right-bottom':
              //width+height
              innerStyle.value.width = innerStyle.value.width + movementX
              innerStyle.value.height = innerStyle.value.height + movementX / roleRatio
              break
          }
        }
      } else {
        //只改变位置
        innerStyle.value.left = x
        innerStyle.value.top = y
      }
    }
  })
  window.addEventListener('mouseup', () => {
    isDrag.value = false
    isScale.value = false
  })
})


const mousedownFn = () => {
  isDrag.value = true
}
const scale = (val: string) => {
  directionType.value = val
  isScale.value = true
  isDrag.value = true
}
</script>

<template>
  <routerView />
  <div class="wrap">
    <div class="bg-wrap" ref="refBgWrap" :style="{ width: wrapStyle.width + 'px', height: wrapStyle.height + 'px' }">
      <img :src="ImgBg" class="img-bg" />
      <div class="img-role-wrap" ref="refRoleWrap"
        :style="{ 'left': innerStyle.left + 'px', 'top': innerStyle.top + 'px', width: innerStyle.width + 'px', height: innerStyle.height + 'px', }">
        <img :src="Img1" class="img-role" @mousedown.stop="mousedownFn" draggable="false" />
        <span class="span-dot" :class="item" @mousedown.stop="scale(item)" v-for="(item, index) in direction"
          :key="index">
        </span>
      </div>
    </div>
  </div>
</template>

<style scoped>
.bg-wrap,
.img-bg {
  width: 500px;
  position: relative;
}

.wrap {
  display: flex;
  justify-content: center;
  align-items: center;
}

.img-bg {
  border: 1px solid #000;
}

.wrap {
  width: 500px;
  height: 500px;
  position: relative;
}

.img-role-wrap {
  position: absolute;
  width: 100px;
  border: 1px solid #ccc;
}

.img-role {
  width: 100%;
}

.span-dot {
  width: 10px;
  height: 10px;
  position: absolute;
  border-color: rgb(34 211 238);

  border-style: solid;
}

.left-top {
  left: 0;
  top: 0;
  cursor: nw-resize;
  border-top-width: 3px;
  border-left-width: 3px;
  border-right: none;
  border-bottom: none;
}

.right-top {
  right: 0;
  top: 0;
  cursor: ne-resize;
  border-top-width: 3px;
  border-right-width: 3px;
  border-left: none;
  border-bottom: none;

}

.left-bottom {
  left: 0;
  bottom: 0;
  cursor: ne-resize;
  border-left-width: 3px;
  border-bottom-width: 3px;
  border-right: none;
  border-top: none;
}

.right-bottom {
  right: 0;
  bottom: 0;
  cursor: nw-resize;
  border-right-width: 3px;
  border-bottom-width: 3px;
  border-top: none;
  border-left: none;
}
</style>

相关文章:

  • envsetup和python venv
  • 跟踪性能提高11%|端到端新架构DMAD:通过分离语义-运动学习解决负迁移难题
  • 山东大学离散数学第五章习题解析
  • 理论+实操:MyBlockly 可视化编程工具详解,以及如何基于 pymycobot 库控制ultraArm 机械臂
  • C#-扩展方法-Linq
  • u盘和硬盘的存储结构
  • 拦截器与过滤器
  • LPZero: Language Model Zero-cost Proxy Search from Zero(未更新完预览版本)
  • C++算法——差分
  • 在Vue中 使用 Web Worker
  • 2025-3-9 一周总结
  • 强化学习(赵世钰版)-学习笔记(4.值迭代与策略迭代)
  • 算力100问☞第80问:如何实现算力的弹性伸缩?
  • 配置 Thunderbird 以使用 QQ 邮箱
  • TinyWebServer项目笔记——02 半同步半反应堆线程池
  • FIWARE:开源的物联网平台,支持设备虚拟化和数据管理
  • java后端开发day30--常见算法(二)-------Arrayslambda
  • 每日一练之合并两个有序链表
  • 【0基础学Python】基础语法Part1
  • Next.js Server Action 提交 vs 前端 Fetch 提交:核心区别与优劣分析
  • 手机网站做成app/百度网盘账号登录入口
  • 怎么做福彩网站/最新国内新闻10条
  • php做网站速成/北京计算机培训机构前十名
  • 网站建设 中国移动/拉新推广平台
  • 成都html5网站建设/短视频seo关键词
  • 西安网站建设雄账号/自有品牌如何推广