美文网首页锤子前端
简单实现el-dialog的拖拽功能

简单实现el-dialog的拖拽功能

作者: BeLLESS | 来源:发表于2018-08-18 15:07 被阅读2292次

最近因为业务需求,需要对element的el-dialog组件实现拖拽功能,在网上搜索了下,资料很多,不过这其中也有一些小坑,这里记录下。主要参考以下两篇文章 element-ui dialog组件添加可拖拽位置 可拖拽宽高JavaScript限定范围拖拽及自定义滚动条应用(3)
首先还是要明确几个概念,这里通过修改css并截图给大家介绍下,理解了这几个概念,代码写起来会得心应手许多。

  • clientWidth,clientHeight
  • scrollWidth,scrollHeight
  • offsetWidth,offsetHeight
  • clientLeft,clientTop
  • scrollLeft,scrollTop
  • offsetLeft,offsetTop

1. clientWidth,clientHeight

clientWidth,clientHeight表示对象内容的可视区的宽度,不包括滚动条和边框,会随对象显示大小的变化而改变。



上图中,我给el-scrollbar__view这个div增加了10px的红色边框,整个div的实际高度,宽度变成了3452px,1920px,观察clientWidth,clientHeight的值是3432px,1900px,并没有包含边框和滚动条的宽度。

2. scrollWidth,scrollHeight

scrollWidth,scrollHeight表示对象的实际内容的宽度,不包括边框(但是包括滚动条),会随对象中内容超过可视区后而变大。



上图中,我还是给el-scrollbar__view这个div增加了10px的红色边框,整个div的实际高度,宽度变成了3452px,1920px,观察scrollWidth,scrollHeight的值是3432px,1900px,并没有包含边框的宽度。

3. offsetWidth,offsetHeight

offsetWidth,offsetHeight表示对象整体的实际宽度,包括滚动条和边框,会随对象显示大小的变化而改变。



上图中,我还是给el-scrollbar__view这个div增加了10px的红色边框,整个div的实际高度,宽度变成了3452px,1920px,观察scrollWidth,scrollHeight的值仍然是3452px,1920px,包含滚动条和边框。

4. clientLeft,clientTop

clientLeft,clientTop表示对象边框的宽度。



上图中,我还是给el-scrollbar__view这个div增加了10px的红色边框,观察clientLeft, clientTop均为10px。

5. scrollLeft,scrollTop

scrollLeft,scrollTop表示对象的显示(可见)的内容与该对象实际的内容的距离。



上图中,我们给content这个section设置了宽高均是300px,并设置显示滚动条,将滚动条拖动一部分,观察scrollLeft,scrollTop的值分别是164px,204px,这对应着当前内容距离原来实际内容的距离(假设蓝色框是实际内容的距离)。

6. offsetLeft,offsetTop

offsetLeft,offsetTop表示对象边框的外边缘距离与已定位的父容器(offsetparent)的内边距离(不包括元素的边框和父容器的边框)。



上图中,el-dialog这个div距离已定位的父容器(这里是el-dialog__wrapper)的宽高分别是672px,61px,与offsetLeft,offsetTop值一致。



我们给el-dialog__wrapper加上一个20px的黄色边框,给el-dialog加上一个10px的蓝色边框,再来观察offsetLeft,offsetTop的值,发现在计算时,是从黄色边框的内边距到蓝色边框的外边距,不包括边框。

7. coding

明确上述概念之后,我们来着手写代码,先说下我的业务场景。
有一个dialog弹框,弹框的背景并不是全屏的,只在除header,sidebar的地方显示,要求拖拽dialog弹框不能超过背景。
我们在main.js同级目录创建directives.js,具体代码如下。

// directives.js
import Vue from 'vue';
 
// v-dialogDrag: 弹窗拖拽
Vue.directive('dialogDrag', {
  bind(el, binding, vnode, oldVnode) {
    // 获取拖拽内容头部
    const dialogHeaderEl = el.querySelector('.el-dialog__header');
    // 获取拖拽内容整体 这个rrc-dialog是我自己封装的组件 如果使用element的组件应写成.el-dialog
    const dragDom = el.querySelector('.rrc-dialog');
    dialogHeaderEl.style.cursor = 'move';
 
    // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
    const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);
 
    // 鼠标按下事件
    dialogHeaderEl.onmousedown = (e) => {
      // 鼠标按下,计算当前元素距离可视区的距离 (鼠标点击位置距离可视窗口的距离)
      const disX = e.clientX - dialogHeaderEl.offsetLeft;
      const disY = e.clientY - dialogHeaderEl.offsetTop;

      // 获取到的值带px 正则匹配替换
      let styL, styT;
 
      // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
      if (sty.left.includes('%')) {
        styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100);
        styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100);
      } else {
        styL = +sty.left.replace(/\px/g, '');
        styT = +sty.top.replace(/\px/g, '');
      };
 
      // 鼠标拖拽事件
      document.onmousemove = function (e) {
        // 通过事件委托,计算移动的距离 (开始拖拽至结束拖拽的距离)
        const l = e.clientX - disX;
        const t = e.clientY - disY;

        let finallyL = l + styL
        let finallyT = t + styT

        // 边界值判定 注意clientWidth scrollWidth区别 要减去之前的top left值
        // dragDom.offsetParent表示弹窗阴影部分
        if (finallyL < 0) {
          finallyL = 0
        } else if (finallyL > dragDom.offsetParent.clientWidth - dragDom.clientWidth - dragDom.offsetParent.offsetLeft) {
          finallyL = dragDom.offsetParent.clientWidth - dragDom.clientWidth - dragDom.offsetParent.offsetLeft
        }

        if (finallyT < 0) {
          finallyT = 0
        } else if (finallyT > dragDom.offsetParent.clientHeight - dragDom.clientHeight - dragDom.offsetParent.offsetLeft) (
          finallyT = dragDom.offsetParent.clientHeight - dragDom.clientHeight - dragDom.offsetParent.offsetLeft
        )
 
        // 移动当前元素
        dragDom.style.left = `${finallyL}px`;
        dragDom.style.top = `${finallyT}px`;
 
        //将此时的位置传出去
        //binding.value({x:e.pageX,y:e.pageY})
      };
 
      document.onmouseup = function (e) {
        document.onmousemove = null;
        document.onmouseup = null;
      };
    }
  }
})

然后在main.js去引入我们刚才创建的directives.js文件。

// main.js
import './directives'

最后找到我们需要拖拽的组件,在其标签上加上v-dialogDrag即可(自定义指令)。

// call.center.detail.vue
<rrc-dialog v-dialogDrag title="呼出结果" :visible.sync="dialogOutVisible">
  ...
</rrc-dialog>

以上是我对简单实现el-dialog拖拽功能的一些看法,感谢上面提到的两篇文章的作者,码字不易,请尊重作者版权,转载注明出处。七夕表白被拒,特地写下此文。
By BeLLESS 2018.8.18 12:08

相关文章

  • 简单实现el-dialog的拖拽功能

    最近因为业务需求,需要对element的el-dialog组件实现拖拽功能,在网上搜索了下,资料很多,不过这其中也...

  • element-ui——el-dialog

    el-dialog实现拖拽功能 1. 在utils中创建el-dragDialog文件夹 2.创建drag.js添...

  • JS实现拖拽功能

    拖拽功能是我们日常项目中常用的效果,今天我们就来研究一下如何实现简单的拖拽功能。想实现拖拽功能其实很简单,主要需要...

  • 百度地图web--拖拽选址

    实现地图拖拽选址功能,百度地图并未像高德地图拖拽选址功能 。由于项目需要,在百度地图的基础上实现简单的拖拽功能。大...

  • POS-2017

    拖拽排序功能 实现方法: 使用jquery的Sortable功能可以实现拖拽功能 index页面 html部分 商...

  • vue中实现element-UI的el-dialog拖拽

    感谢网友的分享实现在vue中element-ui的el-dialog弹框拖拽! 在 utils 中新建 direc...

  • vdesjs实现原理

    拖拽功能实现 vdesjs的拖拽功能使用到了vuedraggble,vuedragable的实现是基于sortab...

  • HTML5 拖拽事件

    HTML5 拖拽事件图片自带拖拽功能其他元素也通过设置 draggable=true属性 实现拖拽功能 垃圾(拖拽...

  • ItemTouchHelper 实现交互动画

    目录介绍 01.拖拽需要实现功能 02.几个重要的方法说明 03.简单实现思路 04.拖拽效果上优化 05.完整代...

  • 仿网易新闻添加栏目和拖拽栏目效果(一)

    今天偶然在apkbus上看到了以下栏目拖拽功能,我们也化繁为简,一步一步来简单实现。第一步,实现拖拽;第二步,拖拽...

网友评论

    本文标题:简单实现el-dialog的拖拽功能

    本文链接:https://www.haomeiwen.com/subject/qwazbftx.html