HTML5 拖放(Drag 和 Drop)html排序拖拽案例,vue穿梭框拖拽案例。

 

hTMl 5 拖拽
使用拖拽需要在元素标签上设置 draggable = true
dragover 在可拖动的元素或者被选择的文本被拖进一个有效的放置目标后间隔几百毫秒持续进行触发 (简单来说就是拖拽到指定的目标元素就会就行持续触发,一般绑定到需要拖拽元素最外层的盒子)
dragstart 事件在用户开始拖动元素或被选择的文本时调用
dragleave 事件在拖动的元素或选中的文本离开一个有效的放置目标时被触发
dragend 事件在拖放操作结束时触发(通过释放鼠标按钮或单击 escape 键)。
drop 事件在元素或选中的文本被放置在有效的放置目标上时被触发
drag 事件在用户拖动元素或选择的文本时,每隔几百毫秒就会被触发一次。
dragenter 事件在可拖动的元素或者被选择的文本进入一个有效的放置目标时触发

html5 排序拖拽 

<!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>

<style>
    *{
        margin: 0;
        padding: 0;
    }
    .list{
        width: 400px;
        height: 500px;
        padding: 10px;
         background-color: #ccc;
    }
    .list p {
        width: 100%;
        height: 40px;
        margin: 10px 0 10px 0;
        text-align: center;
        line-height: 40px;
        background-color: #fff;
        box-shadow: 2px  3px 4px #fff;
    }
    li{
        list-style: none;
    }
    .dragging{
        opacity: 0;
    }
    .drag-body {
        display: flex;
        justify-content: space-around;
    }
</style>
<body class="grid_line">
<div class="drag-body">
  <div class="list" style="margin-top: 20px">
  </div>
</div>
</body>
<script>

    ;(()=> {
        let listData = [1,2,4,5,6]

        const init = () =>{
            render()// 渲染dom函数
            bindEvent() // 绑定所有dom事件处理函数

        }

        function render() {
            let list = document.querySelector('.list')
            list.appendChild(renderList())
        }

        function bindEvent() {
           let dragItems = document.querySelectorAll('.dragItem')
            let dragList = document.querySelectorAll('.dragList')
            dragList[0].addEventListener('dragover',dragoverListHandle,false)
            window.addEventListener('dragover',(e) => e.preventDefault(),false)
            dragItems.forEach(ele => {
                ele.addEventListener('dragstart',dragstartHandle,false)
                ele.addEventListener('dragend',dragendHandle,false)
            })
        }


        // 拖拽函数处理
        function dragstartHandle (ev) {
          // 拖拽开始异步执行隐藏元素
          setTimeout(() =>{this.classList.add('dragging')},0)
          // // 你拖拽了哪个元素就给哪个元素设置一个唯一的标识 可以通过 getData 拿到设置标识的元素。
          if(ev.dataeTransfer)  ev.dataeTransfer.setData("Text",ev.target.id);
        }

        function dragendHandle() {
            this.classList.remove('dragging')
        }

        function dragoverListHandle(e){
             e.preventDefault()
             // 根据类名获取当前拖债的元素。
            const dragging = this.querySelector('.dragging')
             // 获取所有非包含当前拖债的元素
            const dragItems = this.querySelectorAll('.dragItem:not(.dragging)')
            /*
            * clientY 事件属性返回当事件被触发时鼠标指针向对于浏览器页面(客户区)的垂直坐标。 客户区指的是当前窗口。
            * offsetTop 返回一个整数,表示该元素的顶部偏移量,单位是像素 px。
            *  offsetHeight 属性是一个只读属性,它返回该元素的像素高度,高度包含内边距(padding)和边框(border),不包含外边距(margin),是一个整数,单位是像素 px。
            * */
            // 假设盒子向上拖拽 e.clientY 获取当前的盒子里面鼠标 y 轴方向移动的位置,当移动的位置小于等于了上一个元素y轴方向的位置(item.offsetTop + item.offsetHeight / 2),交换dom位置
            // 核心逻辑就是拖拽的元素的位置小于等于了上一个元素底部的位置就交换位置
            const dragItme = [...dragItems].find(item => {
               return  e.clientY <= item.offsetTop + item.offsetHeight / 2
            })
            this.insertBefore(dragging,dragItme)
        }

       // 渲染自定义的ui > li
        function renderList( ) {
            let ul = document.createElement('ul')
            ul.className = 'dragList'
            listData.forEach((item,index) => {
                let li = document.createElement('li')
                li.className = 'dragItem'
                li.draggable = true
                li.innerHTML = `<p>${item}</p>`
                li.id = index
                ul.appendChild(li)
            })
            return ul
        }

        init() // 初始化调用函数
    })()

</script>
</html>

vue穿梭框拖拽

左右图标会找不到自行处理

<template>
  <el-dialog
    :title="title"
    :visible.sync="visible"
    width="50%"
    :before-close="handleClose">
    <div id="box">
      <!----start 左侧隐藏区 --start-->
      <div class="box">
        <div class="title">
            <span
            >隐藏字段</span>
          <span>{
   
   {leftList.length}}</span>
        </div>
        <div class="search_parent">
          <input class="search_input"
                 type="text"  placeholder="请输入搜索内容"
                 @input="leftInputChange($event)"
          >
        </div>
        <!--@drop拖放事件 我们需要对被拖放元素添加@dragover.prevent来阻止浏览器执行与事件关联的默认动作. -->
        <div  class="left" @dragover.prevent  @drop="dropHandle($event,2)" @dragover="dragoverHandle($event)">
          <!-- draggable Boolean值
          @dragstart:拖拽开始事件,可绑定于被拖拽元素上
          @dragend:拖拽结束事件,可绑定于被拖拽元素上 -->
          <div
            class="hover-color"
            v-for="(item,index) in leftList"
            :key="item.id"
            @click="leftListHandle(item,index)"
            :class="{active:leftIndexs.includes(item.id)}"
            draggable="true"
            @dragstart="dragStartHandler($event,item)"
          >{
   
   {item.name}}
          </div>
        </div>
      </div>
      <!----end 左侧隐藏区 --end-->
      <div class="middle">
        <div  :class="{active:rightIndex.length > 0 && rightList.length > 0}" @click="leftBtnSend"><i
          class="el-icon-arrow-left"
        ></i></div>
        <div :class="{active:leftIndexs.length > 0 && leftList.length > 0}"  @click="rightBtnSend"><i
          class="el-icon-arrow-right"
        ></i></div>
      </div>
      <!----start 右侧显示区 --start-->
      <div class="box">
        <div class="title">
            <span
            >显示字段</span>
          <span>{
   
   {rightList.length}}</span>
        </div>

        <div class="search_parent">
          <input class="search_input"
                 type="text"
                 placeholder="请输入搜索内容"
                 @input="rightInputChange($event)"
          >
        </div>
        <!-- 我们需要对被拖放元素添加@dragover.prevent来阻止浏览器执行与事件关联的默认动作. -->
        <div class="right"  @dragover.prevent @drop="dropHandle($event,1)">
          <div
            v-for="(item,index) in rightList"
            :key="item.id"
            @click="rightListHandle(item,index)"
            :class="{active:rightIndex.includes(item.id)}"
            class="hover-color"
            draggable="true"
            @dragstart="dragStartHandler($event,item)"
          >{
   
   {item.name}}
          </div>
        </div>
      </div>
      <!----end 右侧显示区 --end-->
    </div>
    <!-- footer -->
    <span slot="footer" class="dialog-footer">
    <el-button @click="handleClose">取 消</el-button>
    <el-button type="primary" @click="saveHandle"> 保存 </el-button>
  </span>
  </el-dialog>
</template>
<script>

export default {
  data() {
    return{
        leftList:[{name:'您的娃昆德拉为你考虑大',id:55456},{name:'ndiwahfwahffwafwa',id:254},{name:'发成v啊',id:266}],
        rightList:[ {name:'的哇哇的',id:332643},{name:'东哥',id:56434},],
        leftIndexs:[],
        rightIndex:[],
        cloneLeftList:[],
        cloneRightList:[],
        isDown:false,
        cacheIndex:[]
    }
  },
  props:{
    visible:false,
    title:''
  },
  created() {
    this.cloneData()
  },
  watch:{
    rightList:{
      handler() {
        // console.log(243,this.leftList)
        // this.cloneLeftList = JSON.parse(JSON.stringify(this.leftList))
      },
      deep:true,
    }
  },
  methods:{
    handleClose() {
       this.$emit('onClose')
    },
    // 左侧列表点击
    leftListHandle(item,index) {
      this.leftIndexs = [item.id]
      this.rightIndex = []
      console.log(this.cacheIndex,index)
       this.keyDowHandle()
         console.log(342,this.cacheIndex[this.cacheIndex.length - 2],this.cacheIndex[this.cacheIndex.length -1])
      // this.keyUpHandle()
    },
    // rightBtnSend 右侧按钮传送
    rightBtnSend() {
      if(!this.leftList.length) return
      let checkedList = this.leftList.find(item => this.leftIndexs.includes(item.id))
      this.rightList = this.rightList.concat([checkedList])
      this.leftList = this.leftList.filter(item => !this.leftIndexs.includes(item.id))

      this.cloneRightList = this.cloneRightList.concat([checkedList])
      this.cloneLeftList = this.cloneLeftList.filter(item => !this.leftIndexs.includes(item.id))
    },
    leftBtnSend() {
      if(!this.rightList.length)return
      let checkedList = this.rightList.find(item => this.rightIndex.includes(item.id))
      this.leftList = this.leftList.concat([checkedList])
      this.rightList = this.rightList.filter(item => !this.rightIndex.includes(item.id))

      this.cloneLeftList = this.cloneLeftList.concat([checkedList])
      this.cloneRightList = this.cloneRightList.filter(item => !this.rightIndex.includes(item.id))
    },
    cloneData() {
      this.cloneLeftList = JSON.parse(JSON.stringify(this.leftList))
      this.cloneRightList = JSON.parse(JSON.stringify(this.rightList))
    },

    keyDowHandle() {
      (document.onkeydown = function( event ) {
        event.stopPropagation(); // 阻止事件冒泡传递
        event.preventDefault(); // 取消默认事件
        if(event.keyCode === 16) this.isDown = true
        console.log(324,this.isDown)
      })
    },

    keyUpHandle() {
      document.onkeyup = function( event ) {
        if(event.key === 'Shift') this.isDown = false
      }
    },




    // 右侧列表点击
    rightListHandle(item,index) {
      this.rightIndex = [item.id]
      this.leftIndexs = []
    },


    // 保存

    saveHandle() {
      this.$emit('onConfirm',this.rightList)
    },

    // 拖拽设置id
    dragStartHandler(ev,item) {
      ev.dataTransfer.setData("id",item.id);
    },

    // 组织默认时间
    allowDrop(ev) {
      ev.preventDefault()
    },


    // 数据需要拖到哪个盒子就给那个盒子绑定 drop 事件,当你拖到指定的盒子就会触发 drop 事件。
    dropHandle(ev,type) {
      let id = ev.dataTransfer.getData("id");
      if(type === 1) {
        let checkedList = this.leftList.find(item => item.id == id)
        this.rightList = this.rightList.concat([checkedList])
        this.leftList =  this.leftList.filter(item => item.id != id)


        this.cloneRightList = this.cloneRightList.concat([checkedList])
        this.cloneLeftList = this.cloneLeftList.filter(item => item.id != id)
      }else {
        let checkedList = this.rightList.find(item => item.id == id)
        this.leftList = this.leftList.concat([checkedList])
        this.rightList =  this.rightList.filter(item => item.id != id)

        this.cloneLeftList = this.cloneLeftList.concat([checkedList])
        this.cloneRightList = this.cloneRightList.filter(item => item.id != id)
      }
    },


    // 右侧边输入框
    rightInputChange(ev) {
      console.log(ev.target.value)
      this.rightList = this.cloneRightList.filter(item => item.name.includes(ev.target.value))
    },

    // 左侧边输入框
    leftInputChange(ev) {
      console.log(ev.target.value)
      this.leftList = this.cloneLeftList.filter(item => item.name.includes(ev.target.value))
    },

    // 拖拽结束
    dragendHandler(ev) {
      console.log(ev)
    },


    // dragoverHandle 排序
    dragoverHandle(ev) {
      let id = ev.dataTransfer.getData("id");
    }

  }
}


</script>
<style>
* {
  margin: 0;
  padding: 0;
}

#box {
  display: flex;
  justify-content: center;
  align-items: center;
}

.box {
  border: 1px solid rgb(235, 238, 245);
}

.shuttleFrame .el-dialog__footer {
  padding: 0px 20px 20px 0px !important;
}

.box .title {
  font-size: 14px;
  box-sizing: border-box;
  padding-right: 10px;
  display: flex;
  justify-content: space-between;
  width: 245px;
  height: 40px;
  line-height: 40px;
  background: #f5f7fa;
}

.box .title span:first-child {
  display: inline-block;
  background: #f5f7fa;
  /* background-image: url(../public/check-box-outline-blank.png); */
  background-image: url(../../../assets/image/checkboxUnchecked.png);
  background-repeat: no-repeat;
  background-position: 10px center;
  background-size: 20px 20px;
  padding-left: 35px;
  cursor: pointer;
}

.box .title span:first-child.active {
  /* background-image: url(../public/check_box.png); */
  background-image: url(../../../assets/image/checkboxCheck.png);
  /* background-color: #409eff; */
}

.left, .right {
  width: 245px;
  height: 250px;
  padding: 5px 0;
  box-sizing: border-box;
  overflow-y: scroll;
  overflow-x: hidden;
}

.left > div, .right > div {
  cursor: pointer;
  text-align: left;
  /* background-image: url(../public/check-box-outline-blank.png); */
  /* background-image: url(../../../assets/image/checkboxUnchecked.png); */
  background-repeat: no-repeat;
  background-position: 10px center;
  background-size: 20px 20px;
  font-size: 14px;
  padding-left: 35px;
  line-height: 30px;
}

.left > div.active, .right > div.active {
  /* background-image: url(../../../assets/image/checkboxCheck.png); */
  background: #409eff;
  color: #ffffff;
}

.left .hover-color.active:hover, .right .hover-color.active:hover {
  color: #ffffff;
}

.left > div.hover-color:hover, .right > div.hover-color:hover {
  color: rgb(64, 158, 255);
}

.middle {
  margin: 0 20px;
}

.middle > div {
  margin: 10px 0;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid #dcdfe6;
  font-size: 12px;
  background-color: #f5f7fa;
  color: #c0c4cc;
}

.middle > div.active {
  background-color: #409eff;
  border-color: #409eff;
  color: #ffffff;
}

.search_parent {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 20px 0;
}

.search_input {
  width: 220px;
  height: 40px;
  border-radius: 50px;
  border: 1px solid #ccc;
  outline: none;
  font-size: 14px;
  text-indent: 20px
}

.search_input_focus {
  border: 1px solid #409eff;
}

::-webkit-input-placeholder { /* WebKit, Blink, Edge */
  color: rgb(192, 196, 204);
}

:-moz-placeholder { /* Mozilla Firefox 4 to 18 */
  color: rgb(192, 196, 204);
}

::-moz-placeholder { /* Mozilla Firefox 19+ */
  color: rgb(192, 196, 204);
}

:-ms-input-placeholder { /* Internet Explorer 10-11 */
  color: rgb(192, 196, 204);
}
</style>

猜你喜欢

转载自blog.csdn.net/qq_54753561/article/details/130626163