欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue3使用自定義指令實(shí)現(xiàn)el dialog拖拽功能示例詳解

 更新時(shí)間:2022年09月03日 15:14:20   作者:金色海洋  
這篇文章主要為大家介紹了vue3使用自定義指令實(shí)現(xiàn)el dialog拖拽功能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

實(shí)現(xiàn)el-dialog的拖拽功能

這里指的是 element-plus 的el-dialog組件,一開始該組件并沒有實(shí)現(xiàn)拖拽的功能,當(dāng)然現(xiàn)在可以通過設(shè)置屬性的方式實(shí)現(xiàn)拖拽。

自帶的拖拽功能非常嚴(yán)謹(jǐn),拖拽時(shí)判斷是否拖拽出窗口,如果出去了會(huì)阻止拖拽。

如果自帶的拖拽功能可以滿足需求的話,可以跳過本文。

通過自定義指令實(shí)現(xiàn)拖拽功能

因?yàn)橐约翰僮鱠om(設(shè)置事件),所以感覺還是使用自定義指令更直接一些,而且對(duì)原生組件的影響更小。

我們先定義一個(gè)自定義指令 _dialogDrag:

import dialogDrag from './_dialog-drag'
import { watch } from 'vue'
const _dialogDrag = {
  // mounted 
  mounted (el: any, binding: any) {
    // 監(jiān)聽 dialog 是否顯示的狀態(tài)
    watch (binding.value, () => {
      // dialog 不可見,退出
      if (!binding.value.visible) return
      // 尋找 el-dialog 組件
      const container = el.firstElementChild.firstElementChild
      // 已經(jīng)設(shè)置拖拽事件,退出
      if (container.onmousemove) return
      // 等待 DOM 渲染完畢
      setTimeout(() => {
        // 拖拽的 “句柄”
        const _dialogTitle = el.getElementsByClassName('el-dialog__header')
        if (_dialogTitle.length === 0) {
          // 還沒有渲染完畢,或則其他原因
          console.warn('沒有找到要拖拽的 el-dialog', el)
        } else {
          const { setDialog } = dialogDrag()
          const dialogTitle = _dialogTitle[0]
          // 彈窗
          const dialog = el.firstElementChild.firstElementChild.firstElementChild
          // 通過 css 尋找 el-dialog 設(shè)置的寬度
          const arr = dialog.style.cssText.split(';')
          const width = arr[0].replace('%', '').replace('--el-dialog-width:', '') //
          // 設(shè)置 el-dialog 組件、彈窗、句柄、寬度
          setDialog(container, dialog, dialogTitle, width)
        }
      },300)
    })
  },
}
/**
 * 注冊(cè)拖拽 dialog 的自定義指令
 * @param app 
 * @param options 
 */
const install = (app: any, options: any) => {
  app.directive('dialogDrag', _dialogDrag)
}
export {
  _dialogDrag,
  install
}

這里有兩個(gè)比較煩人的地方:

  • DOM渲染完畢的時(shí)機(jī)。執(zhí)行 mounted 的時(shí)候,DOM不一定渲染完畢,如果不使用 setTimeout 的話,就會(huì)找不到DOM,所以用了這種笨辦法。
  • dialog 的隱藏。一般情況下,el-dialog 初始是隱藏狀態(tài),隱藏了就意味著DOM并不會(huì)被渲染出來??墒亲远x指令會(huì)在一開始即被執(zhí)行,這時(shí) setTimeout 的等待時(shí)間再長(zhǎng)也無用,所以只好監(jiān)聽dialog的狀態(tài)。
  • ref 通過 template 傳遞后,再次傳入組件的話,就會(huì)失去ref的那一層的響應(yīng)性,所以只能傳入reactive才行,這樣調(diào)用指令的組件,就會(huì)比較別扭,目前沒有想到更好的實(shí)現(xiàn)方式。

實(shí)現(xiàn)拖拽功能

定義指令和實(shí)現(xiàn)拖拽,我分成了兩個(gè)文件,我想,盡量解耦一下。

定義一個(gè)拖拽函數(shù)(dialogDrag):

/**
 * 拖拽 dialog 的函數(shù),目前支持 element-plus
 */
export default function dialogDrag () {
  /**
   * 設(shè)置拖拽事件
   * @param container 大容器,比如蒙版。
   * @param dialog 被拖拽的窗口
   * @param dialogTitle 拖拽的標(biāo)題
   * @param width 寬度比例
   */
  const setDialog = (container: any, dialog: any, dialogTitle: any, width: number) => {
    const oldCursor = dialogTitle.style.cursor
    // 可視窗口的寬度
    const clientWidth = document.documentElement.clientWidth
    // 可視窗口的高度
    const clientHeight = document.documentElement.clientHeight
    // 根據(jù)百分?jǐn)?shù)計(jì)算寬度
    const tmpWidth = clientWidth * (100 - width) / 200
    // 默認(rèn)寬度和高度
    const domset = {
      x: tmpWidth,
      y: clientHeight * 15 / 100 // 根據(jù) 15vh 計(jì)算
    }
    // 查看dialog 當(dāng)前的寬度和高低
    if (dialog.style.marginLeft === '') {
      dialog.style.marginLeft = domset.x + 'px'
    } else {
      domset.x = dialog.style.marginLeft.replace('px','') * 1
    }
    if (dialog.style.marginTop === '') {
      dialog.style.marginTop = domset.y + 'px'
    } else {
      domset.y = dialog.style.marginTop.replace('px','') * 1
    }
    // 記錄拖拽開始的光標(biāo)坐標(biāo),0 表示沒有拖拽
    const start = { x: 0, y: 0 }
    // 移動(dòng)中記錄偏移量
    const move = { x: 0, y: 0 }
    // 經(jīng)過時(shí)改變鼠標(biāo)指針形狀
    dialogTitle.onmouseover = () => {
      dialogTitle.style.cursor = 'move' // 改變光標(biāo)形狀
    }
    // 鼠標(biāo)按下,開始拖拽
    dialogTitle.onmousedown = (e: any) => {
      start.x = e.clientX
      start.y = e.clientY
      dialogTitle.style.cursor = 'move' // 改變光標(biāo)形狀
    }
    // 鼠標(biāo)移動(dòng),實(shí)時(shí)跟蹤 dialog
    container.onmousemove = (e: any) => {
      if (start.x === 0) { // 不是拖拽狀態(tài)
        return
      }
      move.x = e.clientX - start.x
      move.y = e.clientY - start.y
      // 初始位置 + 拖拽距離
      dialog.style.marginLeft = (domset.x + move.x) + 'px'
      dialog.style.marginTop = (domset.y + move.y) + 'px'
    }
    // 鼠標(biāo)抬起,結(jié)束拖拽
    container.onmouseup = (e: any) => {
      if (start.x === 0) { // 不是拖拽狀態(tài)
        return
      }
      move.x = e.clientX - start.x
      move.y = e.clientY - start.y
      // 記錄新坐標(biāo),作為下次拖拽的初始位置
      domset.x += move.x
      domset.y += move.y
      dialogTitle.style.cursor = oldCursor
      dialog.style.marginLeft = domset.x + 'px'
      dialog.style.marginTop = domset.y + 'px'
      // 結(jié)束拖拽
      start.x = 0
    }
  }
  return {
    setDialog // 設(shè)置
  }
}

首先觀察el-dialog渲染后的DOM結(jié)構(gòu),發(fā)現(xiàn)是通過 marginLeft、marginTop 這兩個(gè)css 的屬性,那么我們的拖拽也可以通過修改這兩個(gè)屬性來實(shí)現(xiàn)。

然后就是古老的拖拽思路:按下鼠標(biāo)的時(shí)候,記錄光標(biāo)的初始坐標(biāo),抬起鼠標(biāo)的時(shí)候,記錄光標(biāo)的結(jié)束坐標(biāo),然后計(jì)算一下得到x、y的“偏移量”,進(jìn)而修改 marginLeft、marginTop 這兩個(gè)屬性,即可實(shí)現(xiàn)拖拽的效果。

核心思路就是這樣,剩下的就是細(xì)節(jié)完善了。

還有一個(gè)小問題,拖拽后關(guān)閉,然后再次打開,希望可以在拖拽結(jié)束的地方打開,而不是默認(rèn)的位置。所以又想了個(gè)辦法記錄這個(gè)位置。

還是要觀察 el-dialog 的行為,最后發(fā)現(xiàn)規(guī)律,一開始 marginLeft 是空的,而拖拽后會(huì)保留位置。所以,判斷一下就好。

使用方式

原本想直接給el-dialog 設(shè)置自定義指令,但是發(fā)現(xiàn)“無效”,所以只好在外面套個(gè)div。

<template>
  <!--拖拽-->
  <el-button @click="dialog.visible = true">打開</el-button>
  <div v-dialog-drag="dialog" >
    <el-dialog
      v-model="dialog.visible"
      title="自定義拖拽2"
      width="25%"
    >
      <span>拖拽測(cè)試</span>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialog.visible = false">Cancel</el-button>
          <el-button type="primary" @click="dialog.visible = false">Confirm</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script lang="ts">
  import { defineComponent, ref, reactive } from 'vue'
  import { _dialogDrag } from '../../../lib/main'
  export default defineComponent({
    name: 'nf-dialog-move',
    directives: {
      dialogDrag: _dialogDrag
    },
    props: {
    },
    setup(props, context) {
      const dialog = reactive({
        visible: false
      })
      return {
        meta,
        dialog
      }
    }
  })
</script>

如果全局注冊(cè)了自定義指令,那么組件里面就不用注冊(cè)了。

dialog 的 visible: visible 這個(gè)屬性的名稱被寫死了,不能用其他名稱。這是一個(gè)偷懶的設(shè)定。

源碼

gitee.com/naturefw-co…

在線演示

naturefw-code.gitee.io/nf-rollup-u…

以上就是vue3使用自定義指令實(shí)現(xiàn)el dialog拖拽功能示例詳解的詳細(xì)內(nèi)容,更多關(guān)于vue3指令el dialog拖拽的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 區(qū)分vue-router的hash和history模式

    區(qū)分vue-router的hash和history模式

    這篇文章主要介紹了區(qū)分vue-router的hash和history模式,幫助大家更好的理解和學(xué)習(xí)vue路由,感興趣的朋友可以了解下
    2020-10-10
  • 基于vue項(xiàng)目設(shè)置resolves.alias: ''@''路徑并適配webstorm

    基于vue項(xiàng)目設(shè)置resolves.alias: ''@''路徑并適配webstorm

    這篇文章主要介紹了基于vue項(xiàng)目設(shè)置resolves.alias: '@'路徑并適配webstorm,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12
  • 詳解VUE Element-UI多級(jí)菜單動(dòng)態(tài)渲染的組件

    詳解VUE Element-UI多級(jí)菜單動(dòng)態(tài)渲染的組件

    這篇文章主要介紹了VUE Element-UI多級(jí)菜單動(dòng)態(tài)渲染的組件,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • vue-cli3.0 環(huán)境變量與模式配置方法

    vue-cli3.0 環(huán)境變量與模式配置方法

    vue-cli3.0移除了配置文件目錄: config和build文件夾??梢哉f是非常的精簡(jiǎn)了,那移除了配置文件目錄后如何自定義配置環(huán)境變量和模式呢?這篇文章主要介紹了vue-cli3.0 環(huán)境變量與模式 ,需要的朋友可以參考下
    2018-11-11
  • 前端框架Vue.js構(gòu)建大型應(yīng)用淺析

    前端框架Vue.js構(gòu)建大型應(yīng)用淺析

    這篇文章主要為大家詳細(xì)介紹了前端框架Vue.js構(gòu)建大型應(yīng)用的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • vue2.x中monaco-editor的使用說明

    vue2.x中monaco-editor的使用說明

    這篇文章主要介紹了vue2.x中monaco-editor的使用說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • vue循環(huán)數(shù)組改變點(diǎn)擊文字的顏色

    vue循環(huán)數(shù)組改變點(diǎn)擊文字的顏色

    這篇文章主要為大家詳細(xì)介紹了vue循環(huán)數(shù)組改變點(diǎn)擊文字的顏色,非常實(shí)用的切換效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • vue實(shí)現(xiàn)選擇商品規(guī)格功能

    vue實(shí)現(xiàn)選擇商品規(guī)格功能

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)選擇商品規(guī)格功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • 關(guān)于vue3 vuex4 store的響應(yīng)式取值問題解決

    關(guān)于vue3 vuex4 store的響應(yīng)式取值問題解決

    這篇文章主要介紹了vue3 vuex4 store的響應(yīng)式取值問題,在實(shí)際生活中遇到這樣一個(gè)問題:在頁面中點(diǎn)擊按鈕,數(shù)量增加,值是存在store中的,點(diǎn)擊事件值沒變,如何解決這個(gè)問題,本文給大家分享解決方法,需要的朋友可以參考下
    2022-08-08
  • vue中如何下載excel流文件及設(shè)置下載文件名

    vue中如何下載excel流文件及設(shè)置下載文件名

    這篇文章主要介紹了vue中如何下載excel流文件及設(shè)置下載文件名,對(duì)vue感興趣的同學(xué),可以參考下
    2021-05-05

最新評(píng)論