Vue使用iframe内嵌Html页面,操作单个/多个Dom节点进行拖拽排序

目的

Vue项目内嵌Html页面,并且可以操作Dom节点进行拖拽排序

Demo开发步骤

一、单个拖拽

  • 快速搭建Vue2项目
    Vue使用iframe内嵌Html页面,操作单个/多个Dom节点进行拖拽排序_第1张图片
  • public文件夹下创建静态html文件page.html
    Vue使用iframe内嵌Html页面,操作单个/多个Dom节点进行拖拽排序_第2张图片
    输入Demo代码
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>测试静态页面title>
head>
<body>
    <div class="menu_list">
        <div class="menu_wp" style="background: #f00">111div>
        <div class="menu_wp" style="background: #ff0">222div>
        <div class="menu_wp" style="background: #0ff">333div>
        <div class="menu_wp" style="background: #00f">444div>
    div>
    
body>
<style>
    .menu_wp {
        width: 100px;
        height: 100px;
    }
style>
html>

效果图:Vue使用iframe内嵌Html页面,操作单个/多个Dom节点进行拖拽排序_第3张图片

  • Vue页面内嵌Html页面,并允许操作节点拖拽排序*
<template>
  <div class="home">
    <div class="left">
      <iframe id="iFrame" :src="src" frameborder="0" style="width: 100%; height: 100%" />
    div>
    <button @click="handleSubmit">点击获取页面数据排序button>
  div>
template>

<script>
export default {
  name: 'HomeView',
  data () {
    return {
      src: ''
    }
  },
  components: {
  },
  mounted () {
    this.src = '../../page.html';
    this.$nextTick(() => {
      const iframe = window.frames['iFrame']
      const handleLoad = () => {
        setTimeout(() => {
          const Do = (iframe.contentWindow || iframe.contentDocument)
          let menus = Do.document.getElementsByClassName('menu_wp')
          for(var i = 0; i < menus.length; i++) {
            menus[i].setAttribute('draggable', true)
            menus[i].setAttribute('sort', i)
          }
          this.drag(Do.document)
        }, 500)
      }
      iframe.addEventListener('load', handleLoad, true)
    })
  },
  methods: {
    drag (doc) {
      // 获取列表dom
      let list = doc.querySelector('.menu_list');
      // 创建cruentItem存放将要拖动的元素
      let cruentItem
      list.mousedown = e => {
        e.preventDefault();
      }
      // 当某被拖动的对象在另一对象容器范围内拖动时触发此事件
      list.ondragover = e => {
          e.preventDefault();
      }
      // 拖动开始
      list.ondragstart = e => {
          // 此处使用setTimeout延迟被拖动的原始元素的样式
          setTimeout(() => {
              e.target.classList.add("moving");
          },0)
          // 存储被拖动元素
          cruentItem = e.target;
          // 拖动时默认行为是复制,此处可以改为移动
          e.dataTransfer.effectAllowed = 'move';
      }

      // 拖动中
      list.ondragenter = e => {
          // 阻止默认事件,否则元素会先回到拖动开始时的位置,再到拖动结束的位置
          e.preventDefault();
          // 拖动事件期间排除被拖动元素自身,以及事件代理对象ul
          if(e.target == cruentItem || e.target == list) {
              return;
          }
          // list.children获取的是类数组,类数组没有数组的方法,所以要通过Array.from转换为真正的数组
          let itmeList = Array.from(list.children);
          // 获取当前拖动元素位置的下标
          let tiemListIndex = itmeList.indexOf(cruentItem);
          // 获取当前拖动元素所移动到的位置的元素的下标
          let targetIndex = itmeList.indexOf(e.target);
          // 如果当前拖动元素下标小于目标元素下标说明是往下移动,否则网上移动
          if (tiemListIndex < targetIndex) {
              console.log('往下移动');
              // 当前拖动元素插入到目标元素前面,且nextElementSibling目标元素的下一个兄弟元素
              list.insertBefore(cruentItem, e.target.nextElementSibling)
          } else {
              console.log('往上移动');
              list.insertBefore(cruentItem, e.target)
          }
      }

      // 拖动结束
      list.ondragend = e => {
          // 结束后移除虚线样式
          e.target.classList.remove('moving')
      }


    },
    handleSubmit() {
      const iframe = window.frames['iFrame']
      const Do = (iframe.contentWindow || iframe.contentDocument)
      let menus = Do.document.getElementsByClassName('menu_wp')
      let sortArr = []
      for(var i = 0; i < menus.length; i++) {
        const sort = menus[i].getAttribute('sort')
        sortArr.push(sort)
      }
      console.log("排序后的顺序 ==>>", sortArr)
    }
  }
}
script>
<style scoped>
.left {
  margin: 0 auto;
  width: 50%;
  height: 1000px;
  border: 1px solid #000;
}
.moving {
  background-color: transparent;
  color: transparent;
  border: 1px dashed black;
}
style>

二、点击选中多个拖拽

  • public文件夹下创建静态html文件drag-mul.html
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>测试静态页面title>
head>
<body style="zoom: 50%;">
    <div class="fixpage" style="background: rgb(255, 175, 175)"><div>固定页1div>div>
    <div class="activepage 111" style="background: rgb(255, 255, 195)">动态页2div>
    <div class="activepage 222" style="background: rgb(176, 255, 255)">动态页3div>
    <div class="activepage 333" style="background: rgb(186, 186, 255)">动态页4div>
    <div class="activepage 444" style="background: #fbc2ff">动态页5div>
    <div class="activepage 555" style="background: #bbffbf">动态页6div>
    <div class="activepage 666" style="background: #ffc6d7">动态页7div>
body>
<style>
    .activepage {
        width: 2480px;
        height: 3508px;
        font-size: 300px;
        -webkit-user-drag: none;
    }
    .fixpage {
        width: 2480px;
        height: 3508px;
        font-size: 300px;
        -webkit-user-drag: none;
    }
    body::-webkit-scrollbar { width: 0 !important }
    .moving,
    .selected {
        border: 21px solid rgb(255, 81, 0) !important;
        box-sizing: border-box;
    }
style>
html>
  • Vue页面内嵌Html页面,并允许操作节点拖拽排序*
<template>
  <div class="home">
    <div class="left">
      <iframe id="iFrame" ref="iFrame" :src="src" frameborder="0" style="width: 100%; height: 100%" />
    div>
    <button @click="handleSubmit">点击获取页面数据排序button>
  div>
template>

<script>
export default {
  name: 'AboutView',
  data () {
    return {
      src: '',
      iframe: {},
      ratioNum: 100,
      
      parentClassName: 'drag-box',
      selectedClassName: 'selected'
    }
  },
  components: {
  },
  mounted () {
    this.demo();
  },
  methods: {
    demo() {
      this.src = '../../drag-mul.html'
      this.$nextTick(() => {
        const iframe = window.frames['iFrame']
        const handleLoad = () => {
          setTimeout(() => {
            const Do = (iframe.contentDocument || iframe.contentWindow.document )
            // 计算缩放比例
            this.getRatio({Do, offsetWidth: (iframe.offsetWidth - 84 / 100)})

            // 在报告页面外包裹一层拖拽层
            this.appendDragBox({Do})
            
            // 监听拖拽动作
            this.drag({Do})
          }, 500)
        }
        iframe.addEventListener('load', handleLoad, true)
      })
    },

    // 计算缩放比例
    getRatio({Do, offsetWidth}) {
      var ratioNum = offsetWidth / 2480;
      ratioNum = parseInt(ratioNum * 100) < 100 ? parseInt(ratioNum * 100) : 100;
      Do.querySelector('body').style = `zoom:${ratioNum}%`
      this.ratioNum = ratioNum
    },

    // 在每一页的报告页面外包裹一层拖拽层
    appendDragBox({Do}) {
      let bodyNode = Do.querySelector('body')
      let divs = bodyNode.children
      let newNode = Do.createElement('div');//添加元素
      newNode.style = `padding: ${21*100 / this.ratioNum}px 0;border: 21px solid #000;box-sizing: border-box; width: auto;`
      newNode.classList.add('drag-box')
      for(var i = 0; i < divs.length; i++) {
        let div = divs[i]
        if(div.className.indexOf('fixpage') > -1 || div.className.indexOf('activepage') > -1) {
          // 判断是否为报告页
          let elem = newNode.cloneNode(true)
          elem.setAttribute('draggable', true)
          elem.setAttribute('sort', i)
          elem.appendChild(div.cloneNode(true))
          
          div.parentNode.replaceChild(elem, div)
        }
      }
    },

    // 多选拖拽
    drag ({Do}) {
      // 获取列表dom
      let list = Do.querySelector('body');
      // 创建cruentItem存放将要拖动的元素
      let cruentItem, cruentItemList, dragIsSelect

      // 点击选择
      list.onclick = (e) => {
        console.log("点击 ==>> ", e)
        // 此处判断是否所选元素是否被选中
        if(e.target.closest('.drag-box').className.indexOf('selected') > -1) {
          e.target.closest('.drag-box').classList.remove("selected");
        } else {
          e.target.closest('.drag-box').classList.add("selected");
        }
      }
      // 当某被拖动的对象在另一对象容器范围内拖动时触发此事件
      list.ondragover = e => {
          e.preventDefault();
      }
      // 拖动开始
      list.ondragstart = e => {
        console.log('拖动开始', e)
        // 判断当前元素是否被选中,若未被选中,则原来选中的元素(们)清空选中样式
        const selectedItems = Array.from(list.getElementsByClassName('selected'))
        dragIsSelect = selectedItems.includes(e.target);
        
        if(!dragIsSelect) {
          // 拖拽的元素不在选中的元素们中,则清空选中元素(们)的样式
          setTimeout(() => {
              e.target.closest('.drag-box').classList.add("moving");
          },0)
          // 存储被拖动元素
          cruentItem = e.target;
          // 拖动时默认行为是复制,此处可以改为移动
          e.dataTransfer.effectAllowed = 'move';
          selectedItems.map(item => {
            item.classList.remove('selected')
          })
        } else {
          cruentItem = e.target;
          cruentItemList = selectedItems
        }
      }

      // 拖动中
      list.ondragenter = e => {
        console.log('拖动中', e)

        // 阻止默认事件,否则元素会先回到拖动开始时的位置,再到拖动结束的位置
        e.preventDefault();
        
        if(!dragIsSelect) {
          // 拖动事件期间排除被拖动元素自身,以及事件代理对象ul
          if(e.target.closest('.drag-box') == cruentItem || e.target == list) {
              return;
          }
        } else {
          // 拖动事件期间排除被拖动元素自身,以及事件代理对象ul
          if(cruentItemList.includes(e.target.closest('.drag-box')) || e.target == list) {
              return;
          }
        }
        
        // list.children获取的是类数组,类数组没有数组的方法,所以要通过Array.from转换为真正的数组
        let itmeList = Array.from(list.children);
        // 获取当前拖动元素位置的下标
        let tiemListIndex = itmeList.indexOf(cruentItem);
        // 获取当前拖动元素所移动到的位置的元素的下标
        let targetIndex = itmeList.indexOf(e.target.closest('.drag-box'));
        if(!dragIsSelect) {
          // 如果当前拖动元素下标小于目标元素下标说明是往下移动,否则往上移动
          if (tiemListIndex < targetIndex) {
            console.log('往下移动');
            // 当前拖动元素插入到目标元素前面,且nextElementSibling目标元素的下一个兄弟元素
            list.insertBefore(cruentItem, e.target.closest('.drag-box').nextElementSibling)
          } else {
            console.log('往上移动');
              list.insertBefore(cruentItem, e.target.closest('.drag-box'))
          }
        } else {
          // 如果当前拖动元素下标小于目标元素下标说明是往下移动,否则往上移动
          for(var i = 0; i < cruentItemList.length; i++) {
            if (tiemListIndex < targetIndex) {
              console.log('往下移动', e.target.closest('.drag-box').nextElementSibling);
              
              if(i === 0) {
                // 当前拖动元素插入到目标元素前面,且nextElementSibling目标元素的下一个兄弟元素
                list.insertBefore(cruentItemList[i], e.target.closest('.drag-box').nextElementSibling)
              } else {
                list.insertBefore(cruentItemList[i], cruentItemList[i - 1].nextElementSibling)
              }
              
            } else {
              console.log('往上移动', e.target.closest('.drag-box'));
                list.insertBefore(cruentItemList[i], e.target.closest('.drag-box'))
            }
          }
          
        }
          
      }

      // 拖动结束
      list.ondragend = e => {
        console.log("拖拽结束 ==>> ", e)
        // 结束后移除虚线样式
        if(!dragIsSelect) {
          e.target.closest('.drag-box').classList.remove('moving')
        }
      }
    },
	
    handleSubmit() {
      const iframe = window.frames['iFrame']
      const Do = (iframe.contentDocument || iframe.contentWindow.document )
      let bodyNode = Do.querySelector('body')
      let divs = bodyNode.children
      let sortArr = []
      for(var i = 0; i < divs.length; i++) {
        let div = divs[i]
        if(div.getAttribute('draggable')) {
          // 判断是否为报告页
          const sort = div.getAttribute('sort')
          sortArr.push(sort)
        }
      }
      console.log("排序后的顺序 ==>>", sortArr)
    }
  }
}
script>
<style scoped>
.left {
  float: left;
  box-sizing: border-box;
  padding: 10px;
  width: 200px;
  height: calc(100vh - 78px);
  border: 1px solid #000;
  
}
.right {
  float: right;
}
.left iframe {
  /* 隐藏滚动条 */
  scrollbar-width: none; /* firefox */
  -ms-overflow-style: none; /* IE 10+ */
}
.left iframe::-webkit-scrollbar {
    display: none; /* Chrome Safari */
}
style>

简单用原生js做了一个demo,代码还不够优美。

参考文献:《原生Javascript实现拖拽排序》

你可能感兴趣的:(Vue2,Javascript,高级程序设计,vue.js,html,javascript)