超碰人人人人人,色婷婷综合久久久久中文一区二区,国产-第1页-浮力影院,欧美老妇另类久久久久久

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

【W(wǎng)EB開(kāi)發(fā)】輕松搞定自定義對(duì)話框窗口拖拽縮放、移動(dòng)

admin
2025年3月31日 18:17 本文熱度 227

經(jīng)常會(huì)碰到需要拖拽縮放的情況,只要有思路,實(shí)現(xiàn)起來(lái)會(huì)非常順暢。
功能的核心是鼠標(biāo)放在四個(gè)邊和角上,拖拽把容器放大或縮小

功能演示

縮放:

?

移動(dòng):

演示網(wǎng)址:寶藏導(dǎo)航?


縮放設(shè)計(jì)思路

  1. 使用css繪制四條邊和四個(gè)角
  2. 通過(guò)css定位,控制四根線和四個(gè)角在對(duì)應(yīng)的位置
  3. 監(jiān)聽(tīng)鼠標(biāo)點(diǎn)擊和移動(dòng)事件
  4. 在移動(dòng)的過(guò)程中,改變?nèi)萜鞯拇笮?/li>

核心設(shè)計(jì)

基礎(chǔ)html結(jié)構(gòu)

<template>
  <!-- 使用 v-if 判斷是否插入到 body 中 -->
  <!-- 創(chuàng)建一個(gè)容器,支持拖拽,使用 ref 引用該容器 -->
  <div
    ref="draggableContainer"
    class="draggable-container"
    @mousedown="startDrag"
    :style="containerStyle"
  >
    <!-- 插槽,用戶可以將其他內(nèi)容插入到這個(gè)容器中 -->
    <slot></slot>

    <!-- 創(chuàng)建縮放控制點(diǎn),每個(gè)控制點(diǎn)代表一個(gè)邊角,使用 v-for 循環(huán)渲染 -->
    <span
      v-for="type in resizeTypes"
      :key="type"
      :class="`${type}-resize`"
      @mousedown="startResize($event, type)"
    ></span>
  </div>
</template>

基礎(chǔ)data數(shù)據(jù):

data: {
      // 定義可縮放的邊和角的類型
      resizeTypes: ["lt", "t", "rt", "r", "rb", "b", "lb", "l"],
      // 定義容器位置和大小的響應(yīng)式數(shù)據(jù)
      position: { x: this.left, y: this.top }, // 容器的位置
      size: { width: this.width, height: this.height }, // 容器的尺寸
  }

核心代碼和思路

容器新寬度 = 容器初始寬度 + 鼠標(biāo)移動(dòng)距離

通過(guò)上面公式,我們需要記錄

  1. 容器的初始寬度
  2. 鼠標(biāo)移動(dòng)距離 = 鼠標(biāo)新位置 - 鼠標(biāo)初始距離

1. 記錄容器和鼠標(biāo)初始狀態(tài)

// 鼠標(biāo)按下,開(kāi)始拖拽
startResize(event) {
    // 記錄鼠標(biāo)初始位置
    this.originMouseX = event.clientX;
    this.originMouseY = event.clientY;

    // 記錄容器初始寬高
    this.originWidth = this.size.width;
    this.originHeight = this.size.height;
},

2. 計(jì)算拖拽后新寬度

根據(jù):容器新寬度 = 容器初始寬度 + 鼠標(biāo)移動(dòng)距離

拖拽容器右邊:

// 計(jì)算鼠標(biāo)的移動(dòng)距離 deltaX
const deltaX = event.clientX - this.originMouseX; 
// 容器新寬度 = 初始寬度 + 鼠標(biāo)移動(dòng)距離
newWidth = this.originWidth + deltaX; 

拖拽容器右下角:
當(dāng)我們拖拽容器右下角,容器的寬和高都會(huì)改變。我們需要把這個(gè)拆分成兩個(gè)步驟來(lái)解決。

// 獲取新寬度
const deltaX = event.clientX - this.originMouseX; 
newWidth = this.originWidth + deltaX;

// 獲取新高度
const deltaY = event.clientY - this.originMouseY; // 計(jì)算鼠標(biāo)的縱向位移
newHeight = this.originHeight + deltaY;

拖拽左邊和上邊:
拖拽左邊的時(shí)候,左邊的定位不能始終都是在原來(lái)的位置。
假設(shè):
    我們的初始位置是 left: 200px。左邊向左拖拽50px后,需要變?yōu)?code>left: 150px 首先我們需要在開(kāi)始的時(shí)候記錄容器的初始位置

// 鼠標(biāo)按下,開(kāi)始拖拽
startResize(event) {
    // 記錄鼠標(biāo)初始位置
    this.originMouseX = event.clientX;
    this.originMouseY = event.clientY;

    // 記錄容器初始寬高
    this.originWidth = this.size.width;
    this.originHeight = this.size.height;
    
    // 記錄容器初始位置
    this.originContainX = this.position.x;
    this.originContainY = this.position.y;
}

改變寬高的同時(shí),改變?nèi)萜髯笊辖堑奈恢?/p>

// 改變高度
const deltaX = event.clientX - this.originMouseX; 
newWidth = this.originWidth - deltaX;

// 改變左邊的位置
this.position.x = this.originContainX + deltaX;

3. 確定拖拽的是哪條邊

我們?cè)邳c(diǎn)擊的時(shí)候會(huì)傳遞type,使用變量把type記錄下。

<span
  v-for="type in resizeTypes"
  :key="type"
  :class="`${type}-resize`"
  @mousedown="startResize($event, type)"
></span>
// 鼠標(biāo)按下,開(kāi)始拖拽
startResize(event, type) {
  this.resizeType = type; // 記錄拖拽的邊角的類型
  ......
}

// 開(kāi)始拖拽的過(guò)程中,改變?nèi)萜鳡顟B(tài)
handleResize() {
const deltaX = event.clientX - this.originMouseX; // 計(jì)算鼠標(biāo)的橫向位移
const deltaY = event.clientY - this.originMouseY; // 計(jì)算鼠標(biāo)的縱向位移

let newWidth = this.originWidth;
let newHeight = this.originHeight;

// 根據(jù)縮放類型計(jì)算新的容器尺寸
switch (this.resizeType) {
    case "lt": // 左上角
      newWidth = this.originWidth - deltaX;
      this.size.width = newWidth;
      this.position.x = this.originContainX + deltaX;
      
      newHeight = this.originHeight - deltaY;
      this.size.height = newHeight;
      this.position.y = this.originContainY + deltaY;
      break;
      
    case "t": // 上邊
      newHeight = this.originHeight - deltaY;
      this.size.height = newHeight;
      this.position.y = this.originContainY + deltaY;
      break;

      右邊,右下角同理......
}

4.設(shè)置最小的拖拽寬和高

如果新拖拽的寬度,已經(jīng)小于最小寬度。拖拽時(shí)不進(jìn)行任何改動(dòng)。

switch (this.resizeType) {
    case "lt": // 左上角
      newWidth = this.originWidth - deltaX;
      newHeight = this.originHeight - deltaY;
      if (newWidth >= this.minWidth) {
        this.position.x = this.originContainX + deltaX;
        this.size.width = newWidth;
      }
      if (newHeight >= this.minHeight) {
        this.position.y = this.originContainY + deltaY;
        this.size.height = newHeight;
      }
      break;
    case "t": // 上邊
      newHeight = this.originHeight - deltaY;
      if (newHeight >= this.minHeight) {
        this.position.y = this.originContainY + deltaY;
        this.size.height = newHeight;
      }
      break;
      
      右邊邊,右下角同理......
}

5.添加拖拽移動(dòng)

拖拽移動(dòng)的詳細(xì)內(nèi)容,筆者寫(xiě)的另一篇文章:拖拽移動(dòng)詳細(xì)思路
下面的完整代碼是結(jié)合了拖拽移動(dòng)和縮放整合在一起,一個(gè)較為完整的拖拽組件


完整代碼

<template>
  <!-- 使用 v-if 判斷是否插入到 body 中 -->
  <!-- 創(chuàng)建一個(gè)容器,支持拖拽,使用 ref 引用該容器 -->
  <div
    ref="draggableContainer"
    class="draggable-container"
    @mousedown="startDrag"
    :style="containerStyle"
  >
    <!-- 插槽,用戶可以將其他內(nèi)容插入到這個(gè)容器中 -->
    <slot></slot>

    <!-- 創(chuàng)建縮放控制點(diǎn),每個(gè)控制點(diǎn)代表一個(gè)邊角,使用 v-for 循環(huán)渲染 -->
    <span
      v-for="type in resizeTypes"
      :key="type"
      :class="`${type}-resize`"
      @mousedown="startResize($event, type)"
    ></span>
  </div>
</template>

<script>
export default {
  props: {
    zIndex: { type: Number, default: 1 }, // 層級(jí),控制顯示順序
    left: { type: Number, default: 0 }, // 容器的初始 X 位置
    top: { type: Number, default: 0 }, // 容器的初始 Y 位置
    width: { type: Number, default: 300 }, // 容器的初始寬度
    height: { type: Number, default: 300 }, // 容器的初始高度
    minWidth: { type: Number, default: 100 }, // 容器的最小寬度
    minHeight: { type: Number, default: 100 }, // 容器的最小高度
  },
  data() {
    return {
      // 定義可縮放的邊和角的類型
      resizeTypes: ["lt", "t", "rt", "r", "rb", "b", "lb", "l"],
      // 定義容器位置和大小的響應(yīng)式數(shù)據(jù)
      position: { x: this.left, y: this.top }, // 容器的位置
      size: { width: this.width, height: this.height }, // 容器的尺寸
      originMouseX: 0, // 鼠標(biāo)初始 X 坐標(biāo)
      originMouseY: 0, // 鼠標(biāo)初始 Y 坐標(biāo)
      originContainX: 0, // 容器初始 X 坐標(biāo)
      originContainY: 0, // 容器初始 Y 坐標(biāo)
      originWidth: 0, // 容器初始寬度
      originHeight: 0, // 容器初始高度
      resizeType: "", // 當(dāng)前縮放類型
    };
  },
  computed: {
    // 計(jì)算容器的樣式
    containerStyle() {
      return {
        top: `${this.position.y}px`, // 設(shè)置容器的 top 樣式
        left: `${this.position.x}px`, // 設(shè)置容器的 left 樣式
        width: `${this.size.width}px`, // 設(shè)置容器的寬度
        height: `${this.size.height}px`, // 設(shè)置容器的高度
        zIndex: this.zIndex, // 設(shè)置容器的層級(jí)
      };
    },
  },
  methods: {
    /**
     * 拖拽邏輯
     */
    startDrag(event) {
      // 記錄鼠標(biāo)初始位置
      this.originMouseX = event.clientX;
      this.originMouseY = event.clientY;

      // 記錄容器初始位置
      this.originContainX = this.position.x;
      this.originContainY = this.position.y;

      // 添加鼠標(biāo)移動(dòng)和鼠標(biāo)松開(kāi)事件監(jiān)聽(tīng)
      document.addEventListener("mousemove", this.handleDrag);
      document.addEventListener("mouseup", this.stopDrag);
    },

    handleDrag(event) {
      this.position.x = this.originContainX + event.clientX - this.originMouseX;
      this.position.y = this.originContainY + event.clientY - this.originMouseY;
    },

    /**
     * 縮放邏輯
     */
    startResize(event, type) {
      this.resizeType = type; // 記錄拖拽的邊角的類型

      // 記錄鼠標(biāo)初始位置
      this.originMouseX = event.clientX;
      this.originMouseY = event.clientY;

      // 記錄容器初始寬高
      this.originWidth = this.size.width;
      this.originHeight = this.size.height;

      // 記錄容器初始位置
      this.originContainX = this.position.x;
      this.originContainY = this.position.y;
      

      event.stopPropagation(); // 阻止事件傳播,防止觸發(fā)拖拽

      // 添加鼠標(biāo)移動(dòng)和鼠標(biāo)松開(kāi)事件監(jiān)聽(tīng)
      document.addEventListener("mousemove", this.handleResize);
      document.addEventListener("mouseup", this.stopDrag);
    },

    handleResize(event) {
      const deltaX = event.clientX - this.originMouseX; // 計(jì)算鼠標(biāo)的橫向位移
      const deltaY = event.clientY - this.originMouseY; // 計(jì)算鼠標(biāo)的縱向位移

      let newWidth = this.originWidth;
      let newHeight = this.originHeight;

      // 根據(jù)縮放類型計(jì)算新的容器尺寸
      switch (this.resizeType) {
        case "lt": // 左上角
          newWidth = this.originWidth - deltaX;
          newHeight = this.originHeight - deltaY;
          if (newWidth >= this.minWidth) {
            this.position.x = this.originContainX + deltaX;
            this.size.width = newWidth;
          }
          if (newHeight >= this.minHeight) {
            this.position.y = this.originContainY + deltaY;
            this.size.height = newHeight;
          }
          break;
        case "t": // 上邊
          newHeight = this.originHeight - deltaY;
          if (newHeight >= this.minHeight) {
            this.position.y = this.originContainY + deltaY;
            this.size.height = newHeight;
          }
          break;
        case "rt": // 右上角
          newWidth = this.originWidth + deltaX;
          newHeight = this.originHeight - deltaY;
          if (newWidth >= this.minWidth) {
            this.size.width = newWidth;
          }
          if (newHeight >= this.minHeight) {
            this.position.y = this.originContainY + deltaY;
            this.size.height = newHeight;
          }
          break;
        case "r": // 右邊
          newWidth = this.originWidth + deltaX;
          if (newWidth >= this.minWidth) {
            this.size.width = newWidth;
          }
          break;
        case "rb": // 右下角
          newWidth = this.originWidth + deltaX;
          newHeight = this.originHeight + deltaY;
          if (newWidth >= this.minWidth) {
            this.size.width = newWidth;
          }
          if (newHeight >= this.minHeight) {
            this.size.height = newHeight;
          }
          break;
        case "b": // 下邊
          newHeight = this.originHeight + deltaY;
          if (newHeight >= this.minHeight) {
            this.size.height = newHeight;
          }
          break;
        case "lb": // 左下角
          newWidth = this.originWidth - deltaX;
          newHeight = this.originHeight + deltaY;
          if (newWidth >= this.minWidth) {
            this.position.x = this.originContainX + deltaX;
            this.size.width = newWidth;
          }
          if (newHeight >= this.minHeight) {
            this.size.height = newHeight;
          }
          break;
        case "l": // 左邊
          newWidth = this.originWidth - deltaX;
          if (newWidth >= this.minWidth) {
            this.position.x = this.originContainX + deltaX;
            this.size.width = newWidth;
          }
          break;
      }
    },

    /**
     * 停止拖拽或縮放
     * 清除事件監(jiān)聽(tīng)器
     */
    stopDrag() {
      document.removeEventListener("mousemove", this.handleDrag);
      document.removeEventListener("mousemove", this.handleResize);
      document.removeEventListener("mouseup", this.stopDrag);
    },
  },

  // 組件銷毀時(shí)移除事件監(jiān)聽(tīng)
  beforeDestroy() {
    this.stopDrag();
  },
};
</script>
<style lang="scss" scoped>
$lineOffset: -6px;
$cornerOffset: -8px;
/* 拖拽容器的樣式 */
.draggable-container {
  position: fixed; /* 絕對(duì)定位 */
  cursor: move; /* 鼠標(biāo)移動(dòng)時(shí)顯示抓手指針 */
  user-select: none; /* 禁止選中文本 */
  background-color: #ccc;
  span {
    position: absolute;
    display: block;
  }
  /* 左邊和右邊 */
  .l-resize,
  .r-resize {
    width: 8px;
    height: 100%;
    top: 0;
    cursor: w-resize;
  }
  .l-resize {
    left: $lineOffset;
  }
  .r-resize {
    right: $lineOffset;
  }

  /* 上邊和下邊 */
  .t-resize,
  .b-resize {
    width: 100%;
    height: 8px;
    left: 0;
    cursor: s-resize;
  }
  .t-resize {
    top: $lineOffset;
  }
  .b-resize {
    bottom: $lineOffset;
  }
  /* 四個(gè)角 */
  .lt-resize,
  .rt-resize,
  .rb-resize,
  .lb-resize {
    width: 15px;
    height: 15px;
    z-index: 10;
  }
  .lt-resize,
  .lb-resize {
    left: $cornerOffset;
  }
  .lt-resize,
  .rt-resize {
    top: $cornerOffset;
  }
  .rt-resize,
  .rb-resize {
    right: $cornerOffset;
  }
  .rb-resize,
  .lb-resize {
    bottom: $cornerOffset;
  }

  .lt-resize,
  .rb-resize {
    cursor: se-resize;
  }
  .rt-resize,
  .lb-resize {
    cursor: sw-resize;
  }
}
</style>

組件引用

<DraggableContainer
  :width="400"
  :height="400"
  :min-height="300"
  :min-width="300"
>
  <div>能拖動(dòng)我了</div>
</DraggableContainer>

總結(jié)

部分代碼設(shè)計(jì)參考了著名第三方庫(kù)vxe-modal的設(shè)計(jì)思路:vxe-modal

本文實(shí)現(xiàn)了拖拽移動(dòng)和縮放的功能,同學(xué)們也可以根據(jù)需要往上面添加自己的改動(dòng)。希望對(duì)您有所幫助!


作者:前端金熊
鏈接:https://juejin.cn/post/7451927213435093033
來(lái)源:稀土掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

該文章在 2025/4/1 13:03:47 編輯過(guò)
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開(kāi)發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved