拖拽: 做个指令美美哒

0. 缘起

不太开心,以为闲着了又改了,心情不好,不过组长啪啪就把这个写好了,我可以抄一抄。虽然遇到了蜜汁的问题!

1. 指令

这里写了个指令,指令的官网文档说道

除了核心功能默认内置的指令 (v-modelv-show),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令

自定义指令 — Vue.js (vuejs.org)

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

指令钩子函数会被传入以下参数:

  • el:指令所绑定的元素,可以用来直接操作 DOM。

  • binding
    

    :一个对象,包含以下 property:

    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue:指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }

2. 拖拽的指令版实现

2.1 A split B样式

注意A与split必须绝对定位,B的左边距即为A宽度

A{
      position: absolute;
      height: calc(100vh - 230px);
      padding: 10px;
      overflow-y: auto;
      box-sizing: border-box;
}
split{
      position: absolute;
      left: 307px;
      height: calc(100vh - 220px);
      background-color: #87c1db;
      width: 2px;
      cursor: move;
}
B{
	  width: calc(100% - 300px);
      box-sizing: border-box;
      height: 100% !important;
      flex: 1;
      padding: 30px;
      font-size: 12px;
      margin-left: 300px;
}

2.2 局部指令v-move

  directives: {
    move: {
      // 指令的定义
      inserted: function (el) {},
      bind: function (el) {
        el.onmousedown = (event) => {
          event.stopPropagation();
          event.preventDefault();
          const left = document.getElementsByClassName("A")[0];
          const right = document.getElementsByClassName("B")[0];
          // 记录下初始位置的值
          let disX = event.clientX;
          el.left = el.offsetLeft;

          document.onmousemove = function (e) {
            let moveX = e.clientX - disX; // 鼠标拖动的偏移距离
            let iT = el.left + moveX ; // 分隔条相对父级定位的 left 值

            el.style.left = `${iT}px`;
            left.style.width = `${iT - 2}px`;
            right.style.width = `calc(100% - ${iT}px)`;
            right.style.marginLeft = `${iT}px`;
            return false;
          };

          // 鼠标放开的时候取消操作
          document.onmouseup = function () {
            document.onmousemove = null;
            document.onmouseup = null;
          };
        };
      },
    },
  },

2.3 挂载在split上

<div class="spilt" v-move></div>

3. 原版的mousedown\mousemove\mouseup

Js利用拖拽实现的改变大小 - 简书 (jianshu.com)

首先鼠标按下(onmousedown

  • 记录目标元素当前的 lefttop

鼠标移动(onmousemove

  • 计算每次移动的横向距离 (disX) 和纵向距离 (disY
  • 并改变元素的leftleft = left + disX)和toptop = top + disY)值

鼠标松开(onmouseup

  • 完成一次拖拽,做一些收尾工作

作者:Essentric
链接:https://juejin.cn/post/6844903958633267208
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

4. HTML5的拖拽事件

HTML5拖放API Drag and Drop - 掘金 (juejin.cn)

详解javascript拖拽(一)基础介绍 - 掘金 (juejin.cn)

preventDefault

拖动文件到浏览器中,浏览器会默认打开该文件,需要手动阻止该默认行为。在dragoverdrop中阻止默认行为:preventDefault.

详解javascript拖拽(二)拖拽的应用及示例 - 掘金 (juejin.cn)

后期修复的一个BUG

有一个更新数据获取的操作,如果拖拽后点更新数据,会有左右两侧重叠的奇怪样子(因为width和margin-left未能随着数据更新改变)
。这个问题我的解决方法是重置初始状态,每次获取新数据就都挪到一开始的位置。原来的想法是记录当前位置,可是自定义指令都是只读值,没法出来,而且computed的也没法实时记录宽度。

      let left = document.getElementsByClassName("tree")[0];
      let right = document.getElementsByClassName("table-footer")[0];
      let splitLine = document.getElementsByClassName("split-div")[0];
      left.style.width = "300px";
      right.style.marginLeft = "300px";
      splitLine.style.left = "327px";

参考

自定义指令 — Vue.js (vuejs.org)

撸一个 Vue 自定义指令实现一键 Copy的功能 - 掘金 (juejin.cn)

posted @ 2022-03-30 14:15  乐盘游  阅读(64)  评论(0编辑  收藏  举报