0


vue3 图片放大缩小、拖拽功能(自定义指令)

效果

请添加图片描述

自定义 拖拽指令

vDrag.js 参考来源 https://github.com/sunzsh
exportconstinitVDrag=(Vue)=>{
  Vue.directive("drag",(el)=>{const oDiv = el // 当前元素const minTop = oDiv.getAttribute("drag-min-top")const ifMoveSizeArea =20
    oDiv.onmousedown=(e)=>{let target = oDiv
      while(
        window.getComputedStyle(target).position !=="absolute"&&
        target !== document.body
      ){
        target = target.parentElement
      }

      document.onselectstart=()=>{returnfalse}if(!target.getAttribute("init_x")){
        target.setAttribute("init_x", target.offsetLeft)
        target.setAttribute("init_y", target.offsetTop)}const initX =parseInt(target.getAttribute("init_x"))const initY =parseInt(target.getAttribute("init_y"))// 鼠标按下,计算当前元素距离可视区的距离const disX = e.clientX - target.offsetLeft
      const disY = e.clientY - target.offsetTop
      document.onmousemove=(e)=>{// 通过事件委托,计算移动的距离// 因为浏览器里并不能直接取到并且使用clientX、clientY,所以使用事件委托在内部做完赋值const l = e.clientX - disX
        const t = e.clientY - disY
        // 计算移动当前元素的位置,并且给该元素样式中的left和top值赋值
        target.style.left = l +"px"// target.style.top = (t < minTop ? minTop : t) + "px"
        target.style.top = t +"px"if(
          Math.abs(l - initX)> ifMoveSizeArea ||
          Math.abs(t - initY)> ifMoveSizeArea
        ){
          target.setAttribute("dragged","")}else{
          target.removeAttribute("dragged")}}
      document.onmouseup=(e)=>{
        document.onmousemove =null
        document.onmouseup =null
        document.onselectstart =null}// return false不加的话可能导致黏连,拖到一个地方时div粘在鼠标上不下来,相当于onmouseup失效returnfalse}})}
使用
//main.tsimport{ createApp }from"vue"import App from"./App.vue"const app =createApp(App)import{ initVDrag }from"@/utils/xxxx/vDrag.js"initVDrag(app)// env.d.ts 声明一下 js文件 不然报错
declare module "@/utils/xxxx/vDrag.js"//组件中// img 父元素需要设置  absolute<img
  v-drag
  oncontextmenu="return false;"
  onselectstart="return false;"class="select-none w-full h-full object-contain"
  src="https://picx.zhimg.com/80/v2-b97b167e582d72cd0afb78ad53a688a1_720w.webp?source=1940ef5c"
  alt=""/>

自定义 拖拽指令 写法二 (带传参及回调写法)

vDrag.js

// html 使用// binding.arg 传参// x x轴相对当前位置偏移量// y y轴相对当前位置偏移量{/* <img src="" v-drag:[initDrag]="dragHandle" alt="" /> 
const initDrag = reactive({ x: 0, y: 0 }) */}exportconstinitVDrag=(Vue)=>{
  Vue.directive("drag",{mounted(el, binding){const oDiv = el // 当前元素const minTop = oDiv.getAttribute("drag-min-top")const ifMoveSizeArea =20const{ x =0, y =0}= binding.arg ||{}const initOffsetLeft = el.offsetLeft ||0const initoffsetTop = el.offsetTop ||0initOffset(el, binding, x, y, initOffsetLeft, initoffsetTop)// 初始化 x y 偏移量 数据
      oDiv.onmousedown=(e)=>{let target = oDiv
        while(
          window.getComputedStyle(target).position !=="absolute"&&
          target !== document.body
        ){
          target = target.parentElement
        }

        document.onselectstart=()=>{returnfalse}// if (!target.getAttribute("init_x")) {//   target.setAttribute("init_x", target.offsetLeft)//   target.setAttribute("init_y", target.offsetTop)// }// const initX = parseInt(target.getAttribute("init_x"))// const initY = parseInt(target.getAttribute("init_y"))const initX =parseInt(target.offsetLeft)const initY =parseInt(target.offsetTop)// 鼠标按下,计算当前元素距离可视区的距离const disX = e.clientX - target.offsetLeft
        const disY = e.clientY - target.offsetTop
        document.onmousemove=(e)=>{// 通过事件委托,计算移动的距离// 因为浏览器里并不能直接取到并且使用clientX、clientY,所以使用事件委托在内部做完赋值const l = e.clientX - disX
          const t = e.clientY - disY
          // 计算移动当前元素的位置,并且给该元素样式中的left和top值赋值
          target.style.left = l +"px"// target.style.top = (t < minTop ? minTop : t) + "px"
          target.style.top = t +"px"// 拖拽改变回调函数dragCallBack(target, binding, l, t, initOffsetLeft, initoffsetTop)if(
            Math.abs(l - initX)> ifMoveSizeArea ||
            Math.abs(t - initY)> ifMoveSizeArea
          ){
            target.setAttribute("dragged","")}else{
            target.removeAttribute("dragged")}}
        document.onmouseup=(e)=>{
          document.onmousemove =null
          document.onmouseup =null
          document.onselectstart =null}// return false不加的话可能导致黏连,拖到一个地方时div粘在鼠标上不下来,相当于onmouseup失效returnfalse}},})}// 拖拽改变回调constdragCallBack=(el, binding, x, y, initOffsetLeft, initoffsetTop)=>{const dragHandle = binding.value ||nullif(dragHandle instanceofFunction){dragHandle({
      el,
      x,
      y,
      initOffsetLeft,
      initoffsetTop,setOffset:(x, y)=>{setOffset(el, binding, x, y, initOffsetLeft, initoffsetTop)},
      binding,})}}// 设置偏移量constsetOffset=(target, binding, x, y, initOffsetLeft, initoffsetTop)=>{// 计算移动当前元素的位置,并且给该元素样式中的left和top值赋值
  target.style.left = x +"px"
  target.style.top = y +"px"dragCallBack(target, binding, x, y, initOffsetLeft, initoffsetTop)}constinitOffset=(target, binding, x, y, initOffsetLeft, initoffsetTop)=>{const initX =(target.offsetLeft ||0)*1+ x *1const initY =(target.offsetTop ||0)*1+ y *1setOffset(target, binding, initX, initY, initOffsetLeft, initoffsetTop)}
使用
//main.tsimport{ createApp }from"vue"import App from"./App.vue"const app =createApp(App)import{ initVDrag }from"@/utils/xxxx/vDrag.js"initVDrag(app)// env.d.ts 声明一下 js文件 不然报错
declare module "@/utils/xxxx/vDrag.js"//组件中<script setup lang="ts">//初始化拖拽数据const initDrag =reactive({x:0,//x轴偏移量  单位pxy:0,//y轴偏移量  单位px})// 拖拽元素 信息const dragInfo =ref({}as any)// 拖拽事件回调constdragHandle=(options: any)=>{
  dragInfo.value = options
}</script>//写法一 v-drag:[initDrag]="dragHandle"//写法二 v-drag:[initDrag]  //写法三 v-drag// img 父元素需要设置  absolute<img
  v-drag
  oncontextmenu="return false;"
  onselectstart="return false;"class="select-none w-full h-full object-contain"
  src="https://picx.zhimg.com/80/v2-b97b167e582d72cd0afb78ad53a688a1_720w.webp?source=1940ef5c"
  alt=""/>

自定义 缩放指令

vWheelScale.js

根据项目需要 我指令加了 动态参数 及 回调函数 不需要自行修改

// html 使用// maxScale 缩放最大倍速  默认5// minScale 最小倍速 默认0.5{/* <img src="" v-wheelScale:[initWheelScale]="wheelScaleChange" alt="" /> 
const initWheelScale = reactive({ maxScale: 5, minScale: 0.5 }) */}exportconstinitVWheelScale=(Vue)=>{let oldScale =null//记录 上一次 scale 值
  Vue.directive("wheelScale",(el, binding)=>{if(el){
      el.onwheel=(e)=>{const{ maxScale =5, minScale =0.5}= binding.arg ||{}const cssVarName ="--scale"let _scale = el.style.getPropertyValue(cssVarName)||1if(e.wheelDelta >0){
          _scale = _scale *1+0.1}else{
          _scale = _scale *1-0.1}// 现在缩放范围if(_scale > maxScale){
          _scale = maxScale
        }elseif(_scale < minScale){
          _scale = minScale
        }// 设置 --scale 变量 缩放比例constsetVarScale=(el, cssVarName)=>{let cssText = el.style.cssText
          let cssTextList = cssText.split(";")let isExist =falselet isExistIndex =-1for(let index =0; index < cssTextList.length; index++){const element = cssTextList[index]if(element.includes(cssVarName +":")){
              isExist =true
              isExistIndex = index
              break}}if(isExist){
            cssTextList[isExistIndex]=`--scale: ${_scale}`}else{
            cssTextList.push(`--scale: ${_scale}`)//   el.setAttribute("style", `--scale: ${_scale}`)}
          cssText = cssTextList.join(";")
          el.style.cssText = cssText
        }// 设置 style.transformconstsetTransformCss=(el, cssVarName)=>{let transformCssString = el.style.transform
          let regScaleGlobal =/scale\(.*?[ )]*[)]+[ ]*/g//匹配 Scale属性 全局if(regScaleGlobal.test(transformCssString)){
            transformCssString = transformCssString.replace(
              regScaleGlobal,` scale(var(${cssVarName})) `)}else{
            transformCssString +=" "+`scale(var(${cssVarName}))`}
          el.style.transform = transformCssString
        }setVarScale(el, cssVarName)setTransformCss(el, cssVarName)// 缩放改变回调函数const wheelScaleChange = binding.value ||nullif(wheelScaleChange instanceofFunction&& _scale != oldScale){
          oldScale = _scale
          wheelScaleChange({
            cssVarName,currentScale: _scale,
            maxScale,
            minScale,})}}}})}
使用
//main.tsimport{ createApp }from"vue"import App from"./App.vue"const app =createApp(App)import{ initVWheelScale}from"@/utils/xxxx/vWheelScale.js"initVWheelScale(app)// env.d.ts 声明一下 js文件 不然报错
declare module "@/utils/xxxx/vWheelScale.js"//组件中<script setup lang="ts">const initWheelScale =reactive({maxScale:5,minScale:0.5})constwheelScaleChange=(el: any)=>{
  console.log("wheelScaleChange el", el)}</script>//写法一 v-wheelScale:[initWheelScale]="wheelScaleChange"//写法二 v-wheelScale:[initWheelScale]  //写法三 v-wheelScale<img
    v-drag
    v-wheelScale:[initWheelScale]="wheelScaleChange"
    oncontextmenu="return false;"
    onselectstart="return false;"class="select-none w-full h-full object-contain"
    src="https://picx.zhimg.com/80/v2-b97b167e582d72cd0afb78ad53a688a1_720w.webp?source=1940ef5c"
    alt=""/>

自定义 缩放指令 写法二(带传参及回调写法)

vWheelScale.js
// html 使用// maxScale 缩放最大倍速  默认5// minScale 最小倍速 默认0.5// initScale 默认倍速// cssVarName css scale 变量名{/* <img src="" v-wheelScale:[initWheelScale]="wheelScaleHandle" alt="" /> 
const initWheelScale = reactive({ maxScale: 5, minScale: 0.5 }) */}exportconstinitVWheelScale=(Vue)=>{
  Vue.directive("wheelScale",(el, binding)=>{const{
      maxScale =5,
      minScale =0.5,
      initScale =1,
      cssVarName ="--scale",}= binding.arg ||{}let currentScale = initScale || el.style.getPropertyValue(cssVarName)||1setWheelScale(binding,{
      el,
      cssVarName,
      currentScale,
      minScale,
      maxScale,})if(el){
      el.onwheel=(e)=>{
        currentScale = el.style.getPropertyValue(cssVarName)||1if(e.wheelDelta >0){
          currentScale = currentScale *1+0.1}else{
          currentScale = currentScale *1-0.1}setWheelScale(binding,{
          el,
          cssVarName,
          currentScale,
          minScale,
          maxScale,})}}})}// 设置 --scale 变量 缩放比例constsetVarScale=(el, cssVarName, currentScale, minScale, maxScale)=>{// 现在缩放范围if(currentScale > maxScale){
    currentScale = maxScale
  }elseif(currentScale < minScale){
    currentScale = minScale
  }let cssText = el.style.cssText
  let cssTextList = cssText.split(";")let isExist =falselet isExistIndex =-1for(let index =0; index < cssTextList.length; index++){const element = cssTextList[index]if(element.includes(cssVarName +":")){
      isExist =true
      isExistIndex = index
      break}}if(isExist){
    cssTextList[isExistIndex]=`--scale: ${currentScale}`}else{
    cssTextList.push(`--scale: ${currentScale}`)//   el.setAttribute("style", `--scale: ${currentScale}`)}
  cssText = cssTextList.join(";")
  el.style.cssText = cssText
  return currentScale
}// 设置 style.transformconstsetTransformCss=(el, cssVarName)=>{let transformCssString = el.style.transform
  let regScaleGlobal =/scale\(.*?[ )]*[)]+[ ]*/g//匹配 Scale属性 全局if(regScaleGlobal.test(transformCssString)){
    transformCssString = transformCssString.replace(
      regScaleGlobal,` scale(var(${cssVarName})) `)}else{
    transformCssString +=" "+`scale(var(${cssVarName}))`}
  el.style.transform = transformCssString
}exportconstsetWheelScale=(binding ={}, options)=>{const{ el, cssVarName, currentScale, minScale, maxScale }= options
  const nowScale =setVarScale(el, cssVarName, currentScale, minScale, maxScale)setTransformCss(el, cssVarName)// 缩放改变回调函数const wheelScaleHandle = binding.value ||nullif(wheelScaleHandle instanceofFunction){wheelScaleHandle({
      el,
      cssVarName,
      maxScale,
      minScale,currentScale: nowScale,setScale:(_scale)=>{setWheelScale(binding,{...options,currentScale: _scale })},
      binding,})}}
使用
//main.tsimport{ createApp }from"vue"import App from"./App.vue"const app =createApp(App)import{ initVWheelScale}from"@/utils/xxxx/vWheelScale.js"initVWheelScale(app)// env.d.ts 声明一下 js文件 不然报错
declare module "@/utils/xxxx/vWheelScale.js"//组件中<script setup lang="ts">const initWheelScale =reactive({maxScale:5,minScale:0.5,initScale:1,cssVarName:"--scale",})const wheelScaleDomInfo =ref({}as any)constwheelScaleHandle=(options: any)=>{
  wheelScaleDomInfo.value = options
}// 函数调用修改 缩放const scaleModified =(type ="add", addNum =0.2)=>{if(wheelScaleDomInfo.value?.setScale){let{ currentScale, setScale }= wheelScaleDomInfo.value
    switch(type){case"add":setScale(currentScale *1+ addNum)breakcase"subtract":setScale(currentScale *1- addNum)break}}}//scaleModified("add") //放大//scaleModified("subtract") //缩小</script>//写法一 v-wheelScale:[initWheelScale]="wheelScaleHandle"//写法二 v-wheelScale:[initWheelScale]  //写法三 v-wheelScale<img
    v-drag
    v-wheelScale:[initWheelScale]="wheelScaleHandle"
    oncontextmenu="return false;"
    onselectstart="return false;"class="select-none w-full h-full object-contain"
    src="https://picx.zhimg.com/80/v2-b97b167e582d72cd0afb78ad53a688a1_720w.webp?source=1940ef5c"
    alt=""/>

本文转载自: https://blog.csdn.net/weixin_43245095/article/details/128468656
版权归原作者 HHH 917 所有, 如有侵权,请联系我们删除。

“vue3 图片放大缩小、拖拽功能(自定义指令)”的评论:

还没有评论