效果
自定义 拖拽指令
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 所有, 如有侵权,请联系我们删除。
版权归原作者 HHH 917 所有, 如有侵权,请联系我们删除。