自定义拖拽证书模板

在这里插入图片描述

//html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script src="./drag.js"></script>
    <link
      rel="stylesheet"
      href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"
    />
    <style>
      .cert-wrap {
        position: relative;
        width: 375px;
        min-width: 375px;
      }
      .bg {
        width: 100%;
        pointer-events: none;
        user-select: none;
      }
      .word {
        position: absolute;
      }
      .el-form-item__content {
        display: flex;
        align-items: center;
      }
      .el-form-item__content > div {
        margin-right: 10px;
      }
      .vdr {
        position: absolute;
        box-sizing: border-box;
        cursor: move;
      }
      .vdr.active:before {
        content: "";
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
        box-sizing: border-box;
        outline: 1px dashed #d6d6d6;
      }
      .vdr-stick {
        box-sizing: border-box;
        position: absolute;
        font-size: 1px;
        background: #ffffff;
        border: 1px solid #6c6c6c;
        box-shadow: 0 0 2px #bbb;
      }
      .inactive .vdr-stick {
        display: none;
      }
      .vdr-stick-tl,
      .vdr-stick-br {
        cursor: nwse-resize;
      }
      .vdr-stick-tm,
      .vdr-stick-bm {
        left: 50%;
        cursor: ns-resize;
      }
      .vdr-stick-tr,
      .vdr-stick-bl {
        cursor: nesw-resize;
      }
      .vdr-stick-ml,
      .vdr-stick-mr {
        top: 50%;
        cursor: ew-resize;
      }
      .vdr-stick.not-resizable {
        display: none;
      }
    </style>
  </head>
  <body>
    <div id="root">
      <el-row style="margin-bottom: 20px">
        <el-radio-group v-model="template" @change="onChange">
          <el-radio label="0">预设模板1</el-radio>
          <el-radio label="1">预设模板2</el-radio>
          <el-radio label="2">预设模板3</el-radio>
          <el-radio label="3">预设模板4</el-radio>
          <el-radio label="4">预设模板5</el-radio>
          <el-radio label="custom">自定义</el-radio>
        </el-radio-group>
      </el-row>
      <el-row type="flex" v-if="Object.keys(form).length">
        <div class="cert-wrap" v-if="template === 'custom'">
          <img :src="form.empower_template" alt="" class="bg" />
          <vue-drag-resize
            @dragging="onDragging"
            @clicked="onActivated"
            w="80"
            :h="form.wx_nickname.style.fontSize * 2"
            :x="form.wx_nickname.style.x"
            :y="form.wx_nickname.style.y"
          >
            <div
              class="word wx_nickname"
              data-key="wx_nickname"
              :style="{...form.wx_nickname.style, fontSize: form.wx_nickname.style.fontSize + 'px'}"
            >
              {{form.wx_nickname.value}}
            </div>
          </vue-drag-resize>
          <vue-drag-resize
            @dragging="onDragging"
            w="80"
            :h="form.agent_name.style.fontSize * 2"
            :x="form.agent_name.style.x"
            :y="form.agent_name.style.y"
          >
            <div
              class="word agent_name"
              :style="{...form.agent_name.style, fontSize: form.agent_name.style.fontSize + 'px'}"
            >
              {{form.agent_name.value}}
            </div>
          </vue-drag-resize>
          <vue-drag-resize
            @dragging="onDragging"
            w="80"
            :h="form.time.style.fontSize * 2"
            :x="form.time.style.x"
            :y="form.time.style.y"
          >
            <div
              class="word time"
              :style="{...form.time.style, fontSize: form.time.style.fontSize + 'px'}"
            >
              {{form.time.value}}
            </div>
          </vue-drag-resize>
          <vue-drag-resize
            @dragging="onDragging"
            w="80"
            :h="form.certificate_no.style.fontSize * 2"
            :x="form.certificate_no.style.x"
            :y="form.certificate_no.style.y"
          >
            <div
              class="word certificate_no"
              :style="{...form.certificate_no.style, fontSize: form.certificate_no.style.fontSize + 'px'}"
            >
              {{form.certificate_no.value}}
            </div>
          </vue-drag-resize>
          <vue-drag-resize
            @dragging="onDragging"
            w="80"
            :h="form.company_name.style.fontSize * 2"
            :x="form.company_name.style.x"
            :y="form.company_name.style.y"
          >
            <div
              class="word company_name"
              :style="{...form.company_name.style, fontSize: form.company_name.style.fontSize + 'px'}"
            >
              {{form.company_name.value}}
            </div>
          </vue-drag-resize>
        </div>
        <div class="cert-wrap" v-else>
          <img :src="form.empower_template" alt="" class="bg" />
          <div
            class="word wx_nickname"
            data-key="wx_nickname"
            :style="{...form.wx_nickname.style, fontSize: form.wx_nickname.style.fontSize + 'px', top:form.wx_nickname.style.y+'px',left:form.wx_nickname.style.x+'px'}"
          >
            {{form.wx_nickname.value}}
          </div>
          <div
            class="word agent_name"
            :style="{...form.agent_name.style, fontSize: form.agent_name.style.fontSize + 'px',top:form.agent_name.style.y+'px',left:form.agent_name.style.x+'px'}"
          >
            {{form.agent_name.value}}
          </div>
          <div
            class="word time"
            :style="{...form.time.style, fontSize: form.time.style.fontSize + 'px',top:form.time.style.y+'px',left:form.time.style.x+'px'}"
          >
            {{form.time.value}}
          </div>
          <div
            class="word certificate_no"
            :style="{...form.certificate_no.style, fontSize: form.certificate_no.style.fontSize + 'px',top:form.certificate_no.style.y+'px',left:form.certificate_no.style.x+'px'}"
          >
            {{form.certificate_no.value}}
          </div>
          <div
            class="word company_name"
            :style="{...form.company_name.style, fontSize: form.company_name.style.fontSize + 'px',top:form.company_name.style.y+'px',left:form.company_name.style.x+'px'}"
          >
            {{form.company_name.value}}
          </div>
        </div>
        <el-form
          v-if="template === 'custom'"
          ref="form"
          :model="form.empower_template"
          label-width="6em"
        >
          <el-form-item label="背景:">
            <el-upload
              class="upload"
              drag
              action="http://test.lojangcc.com/api/common/upload"
              name="file"
              headers="{
                token: '27a4a2de-ac63-4f9b-948d-76e5d07be416',
                appid: '1001'
              }"
            >
              <i class="el-icon-upload"></i>
              <div class="el-upload__text">
                将jpg/png文件拖到此处,或<em>点击上传</em>
              </div>
            </el-upload>
          </el-form-item>
          <el-form-item label="被授予人">
            <el-input-number
              size="mini"
              v-model="form.wx_nickname.style.fontSize"
            ></el-input-number>
            <el-select
              size="mini"
              v-model="form.wx_nickname.style.fontWeight"
              placeholder="请选择"
            >
              <el-option v-for="item in fontWeight" :key="item" :value="item">
              </el-option>
            </el-select>
            <el-color-picker
              size="mini"
              v-model="form.wx_nickname.style.color"
            ></el-color-picker>
          </el-form-item>
          <el-form-item label="授予等级">
            <el-input-number
              size="mini"
              v-model="form.agent_name.style.fontSize"
            ></el-input-number>
            <el-select
              size="mini"
              v-model="form.agent_name.style.fontWeight"
              placeholder="请选择"
            >
              <el-option v-for="item in fontWeight" :key="item" :value="item">
              </el-option>
            </el-select>
            <el-color-picker
              size="mini"
              v-model="form.agent_name.style.color"
            ></el-color-picker>
          </el-form-item>
          <el-form-item label="授权日期">
            <el-input-number
              size="mini"
              v-model="form.time.style.fontSize"
            ></el-input-number>
            <el-select
              size="mini"
              v-model="form.time.style.fontWeight"
              placeholder="请选择"
            >
              <el-option v-for="item in fontWeight" :key="item" :value="item">
              </el-option>
            </el-select>
            <el-color-picker
              size="mini"
              v-model="form.time.style.color"
            ></el-color-picker>
          </el-form-item>
          <el-form-item label="授权编号">
            <el-input-number
              size="mini"
              v-model="form.certificate_no.style.fontSize"
            ></el-input-number>
            <el-select
              size="mini"
              v-model="form.certificate_no.style.fontWeight"
              placeholder="请选择"
            >
              <el-option v-for="item in fontWeight" :key="item" :value="item">
              </el-option>
            </el-select>
            <el-color-picker
              size="mini"
              v-model="form.certificate_no.style.color"
            ></el-color-picker>
          </el-form-item>
          <el-form-item label="公司名称">
            <el-input-number
              size="mini"
              v-model="form.company_name.style.fontSize"
            ></el-input-number>
            <el-select
              size="mini"
              v-model="form.company_name.style.fontWeight"
              placeholder="请选择"
            >
              <el-option v-for="item in fontWeight" :key="item" :value="item">
              </el-option>
            </el-select>
            <el-color-picker
              size="mini"
              v-model="form.company_name.style.color"
            ></el-color-picker>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="onSubmit">确认</el-button>
          </el-form-item>
        </el-form>
      </el-row>
    </div>
  </body>
  <script>
    const templates = [
      {
        wx_nickname: {
          value: "被授予人",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#333",
            y: 200,
            x: 166
          }
        },
        agent_name: {
          value: "授予等级",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#333",
            y: 225,
            x: 166
          }
        },
        certificate_no: {
          value: "授权编号",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#333",
            y: 332,
            x: 150
          }
        },
        time: {
          value: "授权日期",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#333",
            y: 354,
            x: 150
          }
        },
        company_name: {
          value: "公司名称",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#333",
            y: 460,
            x: 155
          }
        },
        empower_template:
          "https://lejiangkeji.oss-cn-beijing.aliyuncs.com/uploads/sqmb/1.png"
      },
      {
        wx_nickname: {
          value: "被授予人",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#333",
            y: 200,
            x: 166
          }
        },
        agent_name: {
          value: "授予等级",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#333",
            y: 235,
            x: 166
          }
        },
        certificate_no: {
          value: "授权编号",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#333",
            y: 310,
            x: 135
          }
        },
        time: {
          value: "授权日期",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#333",
            y: 330,
            x: 135
          }
        },
        company_name: {
          value: "公司名称",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#333",
            y: 460,
            x: 155
          }
        },
        empower_template:
          "https://lejiangkeji.oss-cn-beijing.aliyuncs.com/uploads/sqmb/2.png"
      },
      {
        wx_nickname: {
          value: "被授予人",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#fff",
            y: 200,
            x: 166
          }
        },
        agent_name: {
          value: "授予等级",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#fff",
            y: 222,
            x: 166
          }
        },
        certificate_no: {
          value: "授权编号",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#fff",
            y: 337,
            x: 140
          }
        },
        time: {
          value: "授权日期",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#fff",
            y: 359,
            x: 140
          }
        },
        company_name: {
          value: "公司名称",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#fff",
            y: 460,
            x: 155
          }
        },
        empower_template:
          "https://lejiangkeji.oss-cn-beijing.aliyuncs.com/uploads/sqmb/3.jpg"
      },
      {
        wx_nickname: {
          value: "被授予人",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#f0e9b0",
            y: 210,
            x: 166
          }
        },
        agent_name: {
          value: "授予等级",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#f0e9b0",
            y: 249,
            x: 166
          }
        },
        certificate_no: {
          value: "授权编号",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#f0e9b0",
            y: 335,
            x: 130
          }
        },
        time: {
          value: "授权日期",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#f0e9b0",
            y: 355,
            x: 130
          }
        },
        company_name: {
          value: "公司名称",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#f0e9b0",
            y: 440,
            x: 160
          }
        },
        empower_template:
          "https://lejiangkeji.oss-cn-beijing.aliyuncs.com/uploads/sqmb/4.png"
      },
      {
        wx_nickname: {
          value: "被授予人",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#333",
            y: 225,
            x: 166
          }
        },
        agent_name: {
          value: "授予等级",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#333",
            y: 251,
            x: 166
          }
        },
        certificate_no: {
          value: "授权编号",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#333",
            y: 303,
            x: 155
          }
        },
        time: {
          value: "授权日期",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#333",
            y: 320,
            x: 155
          }
        },
        company_name: {
          value: "公司名称",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#333",
            y: 460,
            x: 155
          }
        },
        empower_template:
          "https://lejiangkeji.oss-cn-beijing.aliyuncs.com/uploads/sqmb/5.png"
      },
      {
        wx_nickname: {
          value: "被授予人",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#333",
            y: 225,
            x: 155
          }
        },
        agent_name: {
          value: "授予等级",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#333",
            y: 251,
            x: 155
          }
        },
        certificate_no: {
          value: "授权编号",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#333",
            y: 303,
            x: 155
          }
        },
        time: {
          value: "授权日期",
          style: {
            fontSize: "10",
            fontWeight: "normal",
            color: "#333",
            y: 320,
            x: 155
          }
        },
        company_name: {
          value: "公司名称",
          style: {
            fontSize: "14",
            fontWeight: "normal",
            color: "#333",
            y: 460,
            x: 155
          }
        },
        empower_template: ""
      }
    ];
    new Vue({
      el: "#root",
      data() {
        return {
          template: "0",
          fontWeight: ["lighter", "normal", "bold"],
          form: {},
          activeEle: ""
        };
      },
      mounted() {
        this.form = templates[this.template];
      },
      methods: {
        onChange(index) {
          if (index === "custom") {
            this.form = templates[5];
          } else {
            this.form = templates[Number(index)];
          }
          document.querySelector(".cert-wrap").style.background =
            index === "custom" && !this.form.empower_template ? "skyblue" : "";
        },
        onActivated(ele) {
          this.activeEle = ele.target.dataset.key;
        },
        onDragging(ele) {
          this.$nextTick().then(() => {
            this.form[this.activeEle].style.x = ele.left;
            this.form[this.activeEle].style.y = ele.top;
          });
        },
        onSubmit() {
          // 提交保存自定义内容,this.form
          console.log(this.form);
        }
      }
    });
  </script>
</html>

/单页面无法npm装包,又引不进来,所以扒源码搬了进来
var VueDragResize = `
<div class="vdr"
  :style="style"
  :class="active || isActive ? 'active' : 'inactive'"
  @mousedown.stop.prevent="bodyDown($event)"
  @touchstart.stop.prevent="bodyDown($event)">
  <slot></slot>
  <div
    v-for="stick in sticks"
    class="vdr-stick"
    :class="['vdr-stick-' + stick, isResizable ? '' : 'not-resizable']"
    @mousedown.stop.prevent="stickDown(stick, $event)"
    @touchstart.stop.prevent="stickDown(stick, $event)"
    :style="vdrStick(stick)">
  </div>
</div>
`
const stickSize = 8;
const styleMapping = {
  y: {
    t: 'top',
    m: 'marginTop',
    b: 'bottom',
  },
  x: {
    l: 'left',
    m: 'marginLeft',
    r: 'right',
  }
};
Vue.component('vue-drag-resize', {
    template: VueDragResize,
    props: {
      parentScaleX: {
        type: Number, default: 1,
      },
      parentScaleY: {
        type: Number, default: 1,
      },
      isActive: {
          type: Boolean, default: false
      },
      preventActiveBehavior: {
          type: Boolean, default: false
      },
      isDraggable: {
          type: Boolean, default: true
      },
      isResizable: {
          type: Boolean, default: false
      },
      aspectRatio: {
          type: Boolean, default: false
      },
      parentLimitation: {
          type: Boolean, default: true
      },
      parentW: {
          type: Number,
          default: 0,
          validator: function (val) {
              return val >= 0
          }
      },
      parentH: {
          type: Number,
          default: 0,
          validator: function (val) {
              return val >= 0
          }
      },
      w: {
          type: Number,
          default: 100,
          validator: function (val) {
              return val > 0
          }
      },
      h: {
          type: Number,
          default: 100,
          validator: function (val) {
              return val > 0
          }
      },
      minw: {
          type: Number,
          default: 50,
          validator: function (val) {
              return val > 0
          }
      },
      minh: {
          type: Number,
          default: 50,
          validator: function (val) {
              return val > 0
          }
      },
      x: {
          type: Number,
          default: 0,
          validator: function (val) {
              return typeof val === 'number'
          }
      },
      y: {
          type: Number,
          default: 0,
          validator: function (val) {
              return typeof val === 'number'
          }
      },
      z: {
          type: [String, Number],
          default: 'auto',
          validator: function (val) {
              let valid = (typeof val === 'string') ? val === 'auto' : val >= 0;
              return valid
          }
      },
      dragHandle: {
          type: String,
          default: null
      },
      dragCancel: {
          type: String,
          default: null
      },
      sticks: {
          type: Array,
          default: function () {
              return ['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml']
          }
      },
      axis: {
          type: String,
          default: 'both',
          validator: function (val) {
              return ['x', 'y', 'both', 'none'].indexOf(val) !== -1
          }
      }
  },

  data: function () {
      return {
          active: this.isActive,
          rawWidth: this.w,
          rawHeight: this.h,
          rawLeft: this.x,
          rawTop: this.y,
          rawRight: null,
          rawBottom: null,
          zIndex: this.z,
          aspectFactor: this.w / this.h,
          parentWidth: null,
          parentHeight: null,
          left: this.x,
          top: this.y,
          right: null,
          bottom: null,
          minWidth: this.minw,
          minHeight: this.minh
      }
  },

  created: function () {
      this.stickDrag = false;
      this.bodyDrag = false;
      this.stickAxis = null;
      this.stickStartPos = {mouseX: 0, mouseY: 0, x: 0, y: 0, w: 0, h: 0};
      this.limits = {
          minLeft: null,
          maxLeft: null,
          minRight: null,
          maxRight: null,
          minTop: null,
          maxTop: null,
          minBottom: null,
          maxBottom: null
      };

      this.currentStick = [];
  },

  mounted: function () {
      this.parentElement = this.$el.parentNode;
      this.parentWidth = this.parentW ? this.parentW : this.parentElement.clientWidth;
      this.parentHeight = this.parentH ? this.parentH : this.parentElement.clientHeight;

      this.rawRight = this.parentWidth - this.rawWidth - this.rawLeft;
      this.rawBottom = this.parentHeight - this.rawHeight - this.rawTop;

      document.documentElement.addEventListener('mousemove', this.move);
      document.documentElement.addEventListener('mouseup', this.up);
      document.documentElement.addEventListener('mouseleave', this.up);

      document.documentElement.addEventListener('mousedown', this.deselect);

      document.documentElement.addEventListener('touchmove', this.move, true);
      document.documentElement.addEventListener('touchend touchcancel', this.up, true);
      document.documentElement.addEventListener('touchstart', this.up, true);

      if (this.dragHandle) {
          let dragHandles = Array.prototype.slice.call(this.$el.querySelectorAll(this.dragHandle));
          for (let i in dragHandles) {
              dragHandles[i].setAttribute('data-drag-handle', this._uid);
          }
      }

      if (this.dragCancel) {
          let cancelHandles = Array.prototype.slice.call(this.$el.querySelectorAll(this.dragCancel));
          for (let i in cancelHandles) {
              cancelHandles[i].setAttribute('data-drag-cancel', this._uid);
          }
      }
  },

  beforeDestroy: function () {
      document.documentElement.removeEventListener('mousemove', this.move);
      document.documentElement.removeEventListener('mouseup', this.up);
      document.documentElement.removeEventListener('mouseleave', this.up);

      document.documentElement.removeEventListener('mousedown', this.deselect);

      document.documentElement.removeEventListener('touchmove', this.move, true);
      document.documentElement.removeEventListener('touchend touchcancel', this.up, true);
      document.documentElement.removeEventListener('touchstart', this.up, true);
  },

  methods: {
      deselect() {
          if (this.preventActiveBehavior) {
              return
          }
          this.active = false
      },

      move(ev) {
          if (!this.stickDrag && !this.bodyDrag) {
              return
          }

          ev.stopPropagation();

          if (this.stickDrag) {
              this.stickMove(ev);
          }
          if (this.bodyDrag) {
              this.bodyMove(ev)
          }
      },

      up(ev) {
          if (this.stickDrag) {
              this.stickUp(ev);
          }
          if (this.bodyDrag) {
              this.bodyUp(ev)
          }
      },

      bodyDown: function (ev) {
          let target = ev.target || ev.srcElement;

          if (!this.preventActiveBehavior) {
              this.active = true;
          }

          if (ev.button && ev.button !== 0) {
              return
          }

          this.$emit('clicked', ev);

          if (!this.isDraggable || !this.active) {
              return
          }

          if (this.dragHandle && target.getAttribute('data-drag-handle') !== this._uid.toString()) {
              return
          }

          if (this.dragCancel && target.getAttribute('data-drag-cancel') === this._uid.toString()) {
              return
          }

          this.bodyDrag = true;

          this.stickStartPos.mouseX = ev.pageX || ev.touches[0].pageX;
          this.stickStartPos.mouseY = ev.pageY || ev.touches[0].pageY;

          this.stickStartPos.left = this.left;
          this.stickStartPos.right = this.right;
          this.stickStartPos.top = this.top;
          this.stickStartPos.bottom = this.bottom;

          if (this.parentLimitation) {
              this.limits = this.calcDragLimitation();
          }
      },

      calcDragLimitation() {
          const parentWidth = this.parentWidth;
          const parentHeight = this.parentHeight;

          return {
              minLeft: 0,
              maxLeft: parentWidth - this.width,
              minRight: 0,
              maxRight: parentWidth - this.width,
              minTop: 0,
              maxTop: parentHeight - this.height,
              minBottom: 0,
              maxBottom: parentHeight - this.height
          }
      },

      bodyMove(ev) {
          const stickStartPos = this.stickStartPos;

          let delta = {
              x: (this.axis !== 'y' && this.axis !== 'none' ? stickStartPos.mouseX - (ev.pageX || ev.touches[0].pageX) : 0) / this.parentScaleX,
              y: (this.axis !== 'x' && this.axis !== 'none' ? stickStartPos.mouseY - (ev.pageY || ev.touches[0].pageY) : 0) / this.parentScaleY
          };

          this.rawTop = stickStartPos.top - delta.y;
          this.rawBottom = stickStartPos.bottom + delta.y;
          this.rawLeft = stickStartPos.left - delta.x;
          this.rawRight = stickStartPos.right + delta.x;
          this.$emit('dragging', this.rect);
      },

      bodyUp() {
          this.bodyDrag = false;
          this.$emit('dragging', this.rect);
          this.$emit('dragstop', this.rect);

          this.stickStartPos = {mouseX: 0, mouseY: 0, x: 0, y: 0, w: 0, h: 0};
          this.limits = {
              minLeft: null,
              maxLeft: null,
              minRight: null,
              maxRight: null,
              minTop: null,
              maxTop: null,
              minBottom: null,
              maxBottom: null
          };
      },

      stickDown: function (stick, ev) {
          if (!this.isResizable || !this.active) {
              return
          }

          this.stickDrag = true;
          this.stickStartPos.mouseX = ev.pageX || ev.touches[0].pageX;
          this.stickStartPos.mouseY = ev.pageY || ev.touches[0].pageY;
          this.stickStartPos.left = this.left;
          this.stickStartPos.right = this.right;
          this.stickStartPos.top = this.top;
          this.stickStartPos.bottom = this.bottom;
          this.currentStick = stick.split('');
          this.stickAxis = null;

          switch (this.currentStick[0]) {
              case 'b':
                  this.stickAxis = 'y';
                  break;
              case 't':
                  this.stickAxis = 'y';
                  break;
          }
          switch (this.currentStick[1]) {
              case 'r':
                  this.stickAxis = this.stickAxis === 'y' ? 'xy' : 'x';
                  break;
              case 'l':
                  this.stickAxis = this.stickAxis === 'y' ? 'xy' : 'x';
                  break;
          }


          this.limits = this.calcResizeLimitation();
      },

      calcResizeLimitation() {
          let minw = this.minWidth;
          let minh = this.minHeight;
          const aspectFactor = this.aspectFactor;
          const width = this.width;
          const height = this.height;
          const bottom = this.bottom;
          const top = this.top;
          const left = this.left;
          const right = this.right;
          const stickAxis = this.stickAxis;

          const parentLim = this.parentLimitation ? 0 : null;

          if (this.aspectRatio) {
              if (minw / minh > aspectFactor) {
                  minh = minw / aspectFactor;
              } else {
                  minw = aspectFactor * minh;
              }
          }

          let limits = {
              minLeft: parentLim,
              maxLeft: left + (width - minw),
              minRight: parentLim,
              maxRight: right + (width - minw),
              minTop: parentLim,
              maxTop: top + (height - minh),
              minBottom: parentLim,
              maxBottom: bottom + (height - minh)
          };

          if (this.aspectRatio) {
              const aspectLimits = {
                  minLeft: left - (Math.min(top, bottom) * aspectFactor) * 2,
                  maxLeft: left + ((((height - minh) / 2) * aspectFactor) * 2),

                  minRight: right - (Math.min(top, bottom) * aspectFactor) * 2,
                  maxRight: right + ((((height - minh) / 2) * aspectFactor) * 2),

                  minTop: top - (Math.min(left, right) / aspectFactor) * 2,
                  maxTop: top + ((((width - minw) / 2) / aspectFactor) * 2),

                  minBottom: bottom - (Math.min(left, right) / aspectFactor) * 2,
                  maxBottom: bottom + ((((width - minw) / 2) / aspectFactor) * 2)
              };

              if (stickAxis === 'x') {
                  limits = {
                      minLeft: Math.max(limits.minLeft, aspectLimits.minLeft),
                      maxLeft: Math.min(limits.maxLeft, aspectLimits.maxLeft),
                      minRight: Math.max(limits.minRight, aspectLimits.minRight),
                      maxRight: Math.min(limits.maxRight, aspectLimits.maxRight)
                  }
              } else if (stickAxis === 'y') {
                  limits = {
                      minTop: Math.max(limits.minTop, aspectLimits.minTop),
                      maxTop: Math.min(limits.maxTop, aspectLimits.maxTop),
                      minBottom: Math.max(limits.minBottom, aspectLimits.minBottom),
                      maxBottom: Math.min(limits.maxBottom, aspectLimits.maxBottom)
                  }
              }
          }


          return limits;
      },

      stickMove(ev) {
          const stickStartPos = this.stickStartPos;

          const delta = {
              x: (stickStartPos.mouseX - (ev.pageX || ev.touches[0].pageX)) / this.parentScaleX,
              y: (stickStartPos.mouseY - (ev.pageY || ev.touches[0].pageY)) / this.parentScaleY
          };

          switch (this.currentStick[0]) {
              case 'b':
                  this.rawBottom = stickStartPos.bottom + delta.y;
                  break;
              case 't':
                  this.rawTop = stickStartPos.top - delta.y;
                  break;
          }

          switch (this.currentStick[1]) {
              case 'r':
                  this.rawRight = stickStartPos.right + delta.x;
                  break;
              case 'l':
                  this.rawLeft = stickStartPos.left - delta.x;
                  break;
          }

          this.$emit('resizing', this.rect);
      },

      stickUp() {
          this.stickDrag = false;
          this.stickStartPos = {
              mouseX: 0,
              mouseY: 0,
              x: 0,
              y: 0,
              w: 0,
              h: 0
          };
          this.limits = {
              minLeft: null,
              maxLeft: null,
              minRight: null,
              maxRight: null,
              minTop: null,
              maxTop: null,
              minBottom: null,
              maxBottom: null
          };
          this.rawTop = this.top;
          this.rawBottom = this.bottom;
          this.rawLeft = this.left;
          this.rawRight = this.right;

          this.stickAxis = null;

          this.$emit('resizing', this.rect);
          this.$emit('resizestop', this.rect);
      },

      aspectRatioCorrection() {
          if (!this.aspectRatio) {
              return
          }

          const bottom = this.bottom;
          const top = this.top;
          const left = this.left;
          const right = this.right;
          const width = this.width;
          const height = this.height;
          const aspectFactor = this.aspectFactor;
          const currentStick = this.currentStick;

          if (width / height > aspectFactor) {
              let newWidth = aspectFactor * height;

              if (currentStick[1] === 'l') {
                  this.left = left + width - newWidth;
              } else {
                  this.right = right + width - newWidth;
              }
          } else {
              let newHeight = width / aspectFactor;

              if (currentStick[0] === 't') {
                  this.top = top + height - newHeight;
              } else {
                  this.bottom = bottom + height - newHeight;
              }
          }
      },
  },

  computed: {
      style() {
          return {
              top: this.top + 'px',
              left: this.left + 'px',
              width: this.width + 'px',
              height: this.height + 'px',
              zIndex: this.zIndex
          }
      },

      vdrStick() {
          return (stick) => {
              const stickStyle = {
                  width: `${stickSize / this.parentScaleX}px`,
                  height: `${stickSize / this.parentScaleY}px`,
              };
              stickStyle[styleMapping.y[stick[0]]] = `${stickSize / this.parentScaleX / -2}px`;
              stickStyle[styleMapping.x[stick[1]]] = `${stickSize / this.parentScaleX / -2}px`;
              return stickStyle;
          }
      },

      width() {
          return this.parentWidth - this.left - this.right;
      },

      height() {
          return this.parentHeight - this.top - this.bottom;
      },

      rect() {
          return {
              left: Math.round(this.left),
              top: Math.round(this.top),
              width: Math.round(this.width),
              height: Math.round(this.height)
          }
      }
  },

  watch: {
      rawLeft(newLeft) {
          const limits = this.limits;
          const stickAxis = this.stickAxis;
          const aspectFactor = this.aspectFactor;
          const aspectRatio = this.aspectRatio;
          const left = this.left;
          const bottom = this.bottom;
          const top = this.top;

          if (limits.minLeft !== null && newLeft < limits.minLeft) {
              newLeft = limits.minLeft;
          } else if (limits.maxLeft !== null && limits.maxLeft < newLeft) {
              newLeft = limits.maxLeft;
          }

          if (aspectRatio && stickAxis === 'x') {
              const delta = left - newLeft;
              this.rawTop = top - (delta / aspectFactor) / 2;
              this.rawBottom = bottom - (delta / aspectFactor) / 2;
          }

          this.left = newLeft;
      },

      rawRight(newRight) {
          const limits = this.limits;
          const stickAxis = this.stickAxis;
          const aspectFactor = this.aspectFactor;
          const aspectRatio = this.aspectRatio;
          const right = this.right;
          const bottom = this.bottom;
          const top = this.top;

          if (limits.minRight !== null && newRight < limits.minRight) {
              newRight = limits.minRight;
          } else if (limits.maxRight !== null && limits.maxRight < newRight) {
              newRight = limits.maxRight;
          }

          if (aspectRatio && stickAxis === 'x') {
              const delta = right - newRight;
              this.rawTop = top - (delta / aspectFactor) / 2;
              this.rawBottom = bottom - (delta / aspectFactor) / 2;
          }

          this.right = newRight;
      },

      rawTop(newTop) {
          const limits = this.limits;
          const stickAxis = this.stickAxis;
          const aspectFactor = this.aspectFactor;
          const aspectRatio = this.aspectRatio;
          const right = this.right;
          const left = this.left;
          const top = this.top;

          if (limits.minTop !== null && newTop < limits.minTop) {
              newTop = limits.minTop;
          } else if (limits.maxTop !== null && limits.maxTop < newTop) {
              newTop = limits.maxTop;
          }

          if (aspectRatio && stickAxis === 'y') {
              const delta = top - newTop;
              this.rawLeft = left - (delta * aspectFactor) / 2;
              this.rawRight = right - (delta * aspectFactor) / 2;
          }

          this.top = newTop;
      },

      rawBottom(newBottom) {
          const limits = this.limits;
          const stickAxis = this.stickAxis;
          const aspectFactor = this.aspectFactor;
          const aspectRatio = this.aspectRatio;
          const right = this.right;
          const left = this.left;
          const bottom = this.bottom;

          if (limits.minBottom !== null && newBottom < limits.minBottom) {
              newBottom = limits.minBottom;
          } else if (limits.maxBottom !== null && limits.maxBottom < newBottom) {
              newBottom = limits.maxBottom;
          }

          if (aspectRatio && stickAxis === 'y') {
              const delta = bottom - newBottom;
              this.rawLeft = left - (delta * aspectFactor) / 2;
              this.rawRight = right - (delta * aspectFactor) / 2;
          }

          this.bottom = newBottom;
      },

      width() {
          this.aspectRatioCorrection();
      },

      height() {
          this.aspectRatioCorrection();
      },

      active(isActive) {
          if (isActive) {
              this.$emit('activated');
          } else {
              this.$emit('deactivated');
          }
      },

      isActive(val) {
          this.active = val;
      },

      z(val) {
          if (val >= 0 || val === 'auto') {
              this.zIndex = val
          }
      },

      aspectRatio(val) {
          if (val) {
              this.aspectFactor = this.width / this.height;
          }
      },

      minw(val) {
          if (val > 0 && val <= this.width) {
              this.minWidth = val
          }
      },

      minh(val) {
          if (val > 0 && val <= this.height) {
              this.minHeight = val
          }
      },

      x() {
          if (this.stickDrag || this.bodyDrag) {
              return
          }
          if (this.parentLimitation) {
              this.limits = this.calcDragLimitation();
          }

          let delta = this.x - this.left;
          this.rawLeft = this.x;
          this.rawRight = this.right - delta;
      },

      y() {
          if (this.stickDrag || this.bodyDrag) {
              return
          }

          if (this.parentLimitation) {
              this.limits = this.calcDragLimitation();
          }

          let delta = this.y - this.top;
          this.rawTop = this.y;
          this.rawBottom = this.bottom - delta;
      },

      w() {
          if (this.stickDrag || this.bodyDrag) {
              return
          }

          this.currentStick = ['m', 'r'];
          this.stickAxis = 'x';

          if (this.parentLimitation) {
              this.limits = this.calcResizeLimitation();
          }

          let delta = this.width - this.w;
          this.rawRight = this.right + delta;
      },

      h() {
          if (this.stickDrag || this.bodyDrag) {
              return
          }

          this.currentStick = ['b', 'm'];
          this.stickAxis = 'y';

          if (this.parentLimitation) {
              this.limits = this.calcResizeLimitation();
          }

          let delta = this.height - this.h;
          this.rawBottom = this.bottom + delta;
      },

      parentW(val) {
          this.right = val - this.width - this.left;
          this.parentWidth = val;

      },

      parentH(val) {
          this.bottom = val - this.height - this.top;
          this.parentHeight = val;

      }
  }
})

vue中使用参考文档https://www.npmjs.com/package/vue-draggable-resizable

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 `vxetable` 中,实现表格列宽可以自定义的方式,可以通过配置 `column-resizing` 属性来实现。 具体来说,你需要在 `columns` 属性中为每一列设置 `resizable: true`,以指示该列可以进行列宽调整。然后,在 `tableProps` 属性中,你可以将 `column-resizing` 属性设置为一个对象,该对象包含一个 `handleWidth` 属性(可选),以指定列调整的手柄宽度,和一个 `minWidth` 属性(可选),以指定列的最小宽度。 例如,下面是一个实现了自定义表格列宽的 `vxetable` 示例代码: ```vue <template> <vxe-table :data="tableData" :columns="tableColumns" :table-props="tableProps" /> </template> <script> export default { data() { return { tableData: [ { name: 'John', age: 22, gender: 'Male' }, { name: 'Jane', age: 30, gender: 'Female' }, { name: 'Bob', age: 45, gender: 'Male' } ], tableColumns: [ { field: 'name', title: 'Name', resizable: true }, { field: 'age', title: 'Age', resizable: true }, { field: 'gender', title: 'Gender', resizable: true } ], tableProps: { columnResizing: { handleWidth: 5, minWidth: 50 } } } } } </script> ``` 在上面的代码中,`tableData` 和 `tableColumns` 分别是表格的数据和列定义,其中每一列都设置了 `resizable: true`,以允许列宽调整。在 `tableProps` 中,我们将 `column-resizing` 设置为一个对象,其中 `handleWidth` 属性设置为 `5`,以指定列调整的手柄宽度为 `5px`,并将 `minWidth` 属性设置为 `50`,以指定列的最小宽度为 `50px`。 这样,在 `vxetable` 中,你就可以通过简单的配置实现表格列宽可以自定义了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小曲曲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值