vue自定义指令,让元素可以随意移动

在项目中有遇到需要随意移动容器的需求,容器里面可以是图片、表格、拨号盘等,任意内容。

用到了鼠标事件
onmousedown // 当按下鼠标按钮时运行
onmousemove // 当鼠标指针移动时运行
onmouseup // 当松开鼠标按钮时运行

自定义局部指令v-move,代码如下

directives: {
    move(el) {
      console.log(el)
      console.dir(el)
      el.onmousedown = function (e) {

        //获取鼠标点击处分别与div左边和div上边的距离:鼠标位置-div位置
        let startX = e.clientX - el.offsetLeft,
          startY = e.clientY - el.offsetTop;

        throttle(
          (document.onmousemove = function (ev) {
            let event = ev || window.event;
            let moveX = event.clientX - startX,
              moveY = event.clientY - startY;
            el.style.left = moveX + "px";
            el.style.top = moveY + "px";
          }),
          500
        );

        // 鼠标弹起时不再移动
        document.onmouseup = function () {
          document.onmousemove = null;
        };
      };
    },
  },

demo完整代码如下:
父组件index.vue代码

<!-- 父组件 -->
<template> 
  <div class="abutton">
    <!-- <el-button type="primary" @click="clicked">点击</el-button> -->
    <ModeOne ref="firstDom" v-move class="mode"></ModeOne>
  </div>
</template>

<script>
import ModeOne from './modeOne.vue'
import throttle from "@/utils/throttle";
export default {
  components: { ModeOne },
  data(){
    return{}
  },
  created(){
    
  },
  methods:{
    clicked(){
    }

  },
  directives: {
    move(el) {
      console.log(el)
      console.dir(el)
      el.onmousedown = function (e) {

        //获取鼠标点击处分别与div左边和div上边的距离:鼠标位置-div位置
        let startX = e.clientX - el.offsetLeft,
          startY = e.clientY - el.offsetTop;

        throttle(
          (document.onmousemove = function (ev) {
            let event = ev || window.event;
            let moveX = event.clientX - startX,
              moveY = event.clientY - startY;
            el.style.left = moveX + "px";
            el.style.top = moveY + "px";
          }),
          500
        );

        // 鼠标弹起时不再移动
        document.onmouseup = function () {
          document.onmousemove = null;
        };
      };
    },
  },
}
</script>
<style lang="less" scoped>
.mode{
  position: fixed;
  left: ~"calc(100% - 1300px)";
  bottom: ~"calc(100% - 500px)";
  z-index: 99;
}
</style>

子组件modeOne.vue代码

<!-- 子组件 -->
<template> 
  <div class="childModel">
    子组件内容
  </div>
</template>

<script>
export default {
  data(){
    return{
    }
  },
  methods:{
  }
}  
</script>
<style lang="less" scoped>
.childModel{
  width: 300px;
  height: 400px;
  background: aquamarine;
}
</style>

在src文件下新建utils文件夹(此文件夹一般存放自己封装的公共的工具类函数),新建throttle.js文件。因为在按住鼠标拖动的时候会多次的触发onmousemove事件,比较消耗性能,函数节流所做的工作就是每隔一段时间去执行一次原本需要无时不刻地在执行的函数,所以在鼠标指针移动的事件中引入函数的节流。代码如下:

// 节流函数: 连续不断地触发某事件(如点击),只在单位时间内只触发一次
// throttle和debounce均是通过减少实际逻辑处理过程的执行来提高事件处理函数运行性能的手段,并没有实质上减少事件的触发次数。

export default function throttle(fun, delay=2000) {
    let last, deferTimer
    return function (args) {
        let that = this;
        let _args = arguments;

        let now = +new Date();
        
        if(last && now < last + delay) {
            clearTimeout(deferTimer);
            deferTimer = setTimeout(function () {
                last = now;
                fun.apply(that, _args);
            },delay)
        } else {
            last = now;
            fun.apply(that,_args);
        }
    }
}

在main.js里面引入函数节流方法,代码如下

// 函数节流
import throttle from "@/utils/throttle";
Vue.prototype.$throttle = throttle;
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容