首先说一下自定义指令的使用

日程开发中会遇到操作 dom 元素,如果只是个别需要操作 dom 元素,可以通过 ref 获取当前 dom 元素,并对其进行操作,但是需要操作的dom比较复杂或者多的话,需要每次都去写一遍 ref 或者直接获取dom操作,所以这时候自定义指令就可以解决这个问题;

首先自定义指令分为全局的和局部的;

自定义指令有5个钩子函数:

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。

每个钩子函数中都有4个参数

el:指令所绑定的元素,可以用来直接操作 DOM,就是放置指令的那个元素。
binding: 一个对象,里面包含了几个属性:value:指令的绑定值,name:指令名等;
vnode:Vue 编译生成的虚拟节点。
oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

先简单介绍一下这次要实现的功能:就是需要在后台中实现一个自定义模板的功能,可以对每行的每个格子的宽高进行自定义拖拽和输入;下面先看一下实现后的一个效果。

在这里插入图片描述

下面是具体的实现代码

<template>
  <div class="innerLayer">
    <ul class="tem-grid-list">
      <li :style="{ width: maxW / 2 + 'px', 'max-width': maxW / 2 + 'px' }">
        <div
          class="tem-grid-item"
          v-for="(item, index) in gridData"
          :key="index"
          :style="{
            width: item.width / 2 + 'px',
            height: item.height / 2 + 'px',
            'line-height': item.height / 2 + 'px',
          }"
        >
          {{ item.navName }}
          <!-- 左右拖拽条 -->
          <div
            v-dragAbout
            :key="index"
            v-if="gridData.length - 1 !== index"
            class="drag-right"
            :style="{ height: item.height / 2 + 'px' }"
          >
            <p :style="{ height: item.height / 2 + 'px' }"></p>
          </div>
        </div>
      </li>
      <!-- 底部拖拽条 -->
      <li v-dragDown :style="{ width: maxW / 2 + 'px', 'max-width': maxW / 2 + 'px' }" class="drag-bottom"></li>
    </ul>
  </div>
</template>
export default {
  name: "tem",
  data() {
    return {
      gridData: [], // 选中行的格子数据
      startY: 0, // 移动前的Y轴坐标
      startX: 0, // 移动前的X轴坐标
      leftDragW: null, // 拖拽宽度的时候,当前拖拽条左边元素的宽度
      rightDragW: null, // 当前拖拽条右边元素的宽度
    };
  },
  directives: {
    dragDown: {
      inserted(el,binding,vNode) {
        el.style.cursor = 'n-resize';
        const that = vNode.context;
        document.addEventListener('selectstart', function (e) {
          e.preventDefault(); // 阻止右键选中文本,避免在拖拽的时候不小心复制内容
        })
        el.onmousedown = function (e) {
          that.startY = e.clientY; // 获取第一次拖动的坐标
          document.onmousemove = function (e) {
            let moveH = e.clientY - that.startY; // 通过移动的坐标 - 第一次拖动的坐标获取移动的距离
            let lastHeight = that.dragHeight + moveH; // 初始的高度加上移动后的距离就是最终的高度
            if (lastHeight <= 74 || lastHeight >= 751) return; // 设置可拖拽的最高和最低高度
            that.lineHeight = lastHeight;
            // 给每一项设置高度跟行高
            that.gridData.forEach(item => {
              item.height = lastHeight;
              item.lineHeight = lastHeight;
            })
          }
          // 最后让他的鼠标按下和移动都为null,防止继续执行
          document.onmouseup = function () {
            document.onmousemove = document.onmousedown = null
          }
        }
      }
    },
    dragAbout: {
      inserted(el,binding,vNode) {
        el.style.cursor = 'e-resize';
        const that = vNode.context;
        document.addEventListener('selectstart', function (e) {
          e.preventDefault(); //阻止默认行为
        })
        el.onmousedown = function (e) {
          let index = vNode.key;
          that.startX = e.clientX; // 获取第一次拖动的坐标
          that.leftDragW = that.gridData[index].width; // 获取拖拽条的父级也就是左边的
          that.rightDragW = that.gridData[index + 1].width;
          document.onmousemove = function (e) {
            let moveW = e.clientX - that.startX; // 通过移动的坐标 - 第一次拖动的坐标获取移动的距离
            if (moveW < 0) {
              if (that.leftDragW + moveW <= 74) return;
              // 拖拽条左边的宽度就相当于,左边宽度加移动的距离,如果是负数,就让左边宽度+负的移动距离算出他减少了多少
              that.gridData[index].width = that.leftDragW + moveW;
              // 如果是负数,就让左边宽度-负的移动距离算出他增加了多少
              that.gridData[index + 1].width = that.rightDragW - moveW;
            } else {
              if (that.rightDragW - moveW <= 74) return;
              that.gridData[index].width = that.leftDragW + moveW;
              that.gridData[index + 1].width = that.rightDragW - moveW;
            }
          }
          // 最后让他的鼠标按下和移动都为null,防止继续执行
          document.onmouseup = function () {
            document.onmousemove = document.onmousedown = null;
          }
        }
      }
    },
  },
};
<style scoped lang="less">
.tem-grid-list {
  li {
    display: flex;
    border: 1px solid #aaa;
    border-bottom: none;
    position: relative;
    box-sizing: border-box;
    margin: 0 auto;
    .tem-grid-item {
      text-align: center;
      position: relative;
      min-height: 37.5px;
      max-height: 750px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      // border-right: 1px solid red;
      .drag-right {
        width: 10px;
        position: absolute;
        top: 0;
        right: -5px;
        cursor: e-resize;
        p {
          width: 4px;
          background: #aaa;
          margin: 0 auto;
          background: #5babff;
        }
      }
    }
  }
  .drag-bottom {
    width: 100%;
    height: 3px;
    background: #5babff;
    cursor: n-resize;
  }
  li:nth-child(1) {
    border-top: 1px solid #aaa;
  }
}
</style>

PS:因为全部功能代码有点多,所以只显示中间拖拽部分的。

Logo

前往低代码交流专区

更多推荐