美文网首页
Vue实现拖拽穿梭框功能四种方式

Vue实现拖拽穿梭框功能四种方式

作者: 前端末晨曦吖 | 来源:发表于2022-09-28 22:59 被阅读0次

    一、使用原生js实现拖拽

    点击打开视频讲解更加详细

    <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <title>Lazyload</title>
          <style>
            .drag {
              background-color: skyblue;
              position: absolute;
              line-height: 100px;
              text-align: center;
              width: 100px;
              height: 100px;
            }
          </style>
        </head>
        <body>
          <!-- left和top要写在行内样式里面 -->
          <div class="drag" style="left: 0; top: 0">按住拖动</div>
          <script src="./jquery-3.6.0.min.js"></script>
          <script>
            // 获取DOM元素
            let dragDiv = document.getElementsByClassName('drag')[0]
            // 鼠标按下事件 处理程序
            let putDown = function (event) {
              dragDiv.style.cursor = 'pointer'
              let offsetX = parseInt(dragDiv.style.left) // 获取当前的x轴距离
              let offsetY = parseInt(dragDiv.style.top) // 获取当前的y轴距离
              let innerX = event.clientX - offsetX // 获取鼠标在方块内的x轴距
              let innerY = event.clientY - offsetY // 获取鼠标在方块内的y轴距
              // 按住鼠标时为div添加一个border
              dragDiv.style.borderStyle = 'solid'
              dragDiv.style.borderColor = 'red'
              dragDiv.style.borderWidth = '3px'
              // 鼠标移动的时候不停的修改div的left和top值
              document.onmousemove = function (event) {
                dragDiv.style.left = event.clientX - innerX + 'px'
                dragDiv.style.top = event.clientY - innerY + 'px'
                // 边界判断
                if (parseInt(dragDiv.style.left) <= 0) {
                  dragDiv.style.left = '0px'
                }
                if (parseInt(dragDiv.style.top) <= 0) {
                  dragDiv.style.top = '0px'
                }
                if (
                  parseInt(dragDiv.style.left) >=
                  window.innerWidth - parseInt(dragDiv.style.width)
                ) {
                  dragDiv.style.left =
                    window.innerWidth - parseInt(dragDiv.style.width) + 'px'
                }
                if (
                  parseInt(dragDiv.style.top) >=
                  window.innerHeight - parseInt(dragDiv.style.height)
                ) {
                  dragDiv.style.top =
                    window.innerHeight - parseInt(dragDiv.style.height) + 'px'
                }
              }
              // 鼠标抬起时,清除绑定在文档上的mousemove和mouseup事件
              // 否则鼠标抬起后还可以继续拖拽方块
              document.onmouseup = function () {
                document.onmousemove = null
                document.onmouseup = null
                // 清除border
                dragDiv.style.borderStyle = ''
                dragDiv.style.borderColor = ''
                dragDiv.style.borderWidth = ''
              }
            }
            // 绑定鼠标按下事件
            dragDiv.addEventListener('mousedown', putDown, false)
          </script>
        </body>
      </html>
    

    二、VUe使用js实现拖拽穿梭框

    <template>
      <div>
        <h3 style="text-align: center">拖拽穿梭框</h3>
        <div id="home" @mousemove="mousemove($event)">
          <div class="tree-select-content">
            <span
              class="select-content"
              :id="'mouse' + index"
              v-for="(item, index) in leftData"
              :key="item.id"
              @mousedown="mousedown(index, 1)"
              @mouseup="mouseup(item, 1, index)"
            >
              <span class="select-text">{{ item.label }}</span>
              <span class="select-text-X" @click="handerClickX(item, index, 1)"
                >X</span
              >
            </span>
          </div>
          <div class="tree-select-content">
            <span
              class="select-content"
              :id="'deleteMouse' + index"
              v-for="(item, index) in rightData"
              :key="item.id"
              @mousedown="mousedown(index, 2)"
              @mouseup="mouseup(item, 2, index)"
            >
              <span class="select-text">{{ item.label }}</span>
              <span class="select-text-X" @click="handerClickX(item, index, 2)"
                >X</span
              >
            </span>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: "home",
      data() {
        return {
          leftData: [
            { label: "首页", id: 1 },
            { label: "咨询", id: 2 },
            { label: "生活", id: 3 },
            { label: "财富", id: 4 },
            { label: "我的", id: 5 },
          ],
          rightData: [{ label: "世界", id: 6 }],
          isMoveTrue: false,
          isMove: false,
          moveId: "",
        };
      },
      mounted() {},
      components: {},
      methods: {
        mousedown(index, val) {
          this.isMoveTrue = true;
          if (val == 1) {
            this.moveId = "mouse" + index;
          } else {
            this.moveId = "deleteMouse" + index;
          }
        },
        mousemove(event) {
          if (this.isMoveTrue) {
            this.isMove = true;
            document.getElementById(this.moveId).style.position = "absolute";
            document.getElementById(this.moveId).style.top = event.clientY + "px";
            document.getElementById(this.moveId).style.left = event.clientX + "px";
            document.getElementById(this.moveId).style.transform =
              "translate(-50%,-50%)";
          }
        },
        mouseup(item, val, index) {
          if (!this.isMove) {
            this.isMoveTrue = false;
            this.moveId = "";
          }
          if (this.isMoveTrue && val == 2) {
            this.$nextTick(() => {
              this.rightData.splice(index, 1);
              this.leftData.push(item);
            });
          } else if (this.isMoveTrue && val) {
            this.leftData.splice(index, 1);
            this.rightData.push(item);
          }
          document.getElementById(this.moveId).style.display = "none";
          this.isMoveTrue = false;
          this.isMove = false;
          this.moveId = "";
        },
        handerClickX(item, index, val) {
          if (val == 1) {
            this.leftData.splice(index, 1);
            this.rightData.push(item);
          } else {
            this.rightData.splice(index, 1);
            this.leftData.push(item);
          }
        },
      },
    };
    </script>
    
    <style scoped>
    #home {
      display: flex;
      justify-content: space-around;
    }
    .tree-select-content {
      width: 40%;
      height: 300px;
      background: #f9faff;
      border: 1px solid #dee0ec;
      border-radius: 4px;
      display: flex;
      flex-wrap: wrap;
      align-content: baseline;
    }
    .select-content {
      width: max-content;
      height: 20px;
      padding: 1.6%;
      border: 1px solid #d6dbed;
      margin: 2% 1% 0;
      background: #ffffff;
      box-shadow: 0 0 8px 0 rgba(72, 119, 236, 0.1);
      border-radius: 4px;
    }
    .select-content:hover span {
      color: #4877ec;
    }
    .select-content:hover {
      cursor: pointer;
      background: #f8faff;
      border: 1px solid #3e75f4;
    }
    .select-text {
      font-size: 15px;
      color: #2e2f36;
      text-align: center;
      font-weight: 400;
    }
    .select-text-X {
      font-size: 15px;
      color: #4877ec;
      letter-spacing: 0;
      font-weight: 400;
      margin-left: 12px;
      cursor: pointer;
    }
    </style>
    

    效果图:

    屏幕截图 2022-09-28 201708.png

    三、Vue 拖拽组件 vuedraggable

    vuedraggable 是标准的组件式封装,并且将可拖动元素放进了 transition-group 上面,过渡动画都比较好。

    使用方式:

    yarn add vuedraggable
    
    import vuedraggable from 'vuedraggable';
    

    在使用的时候,可以通过 v-model 来双向绑定本地 data,如果需要更新或者是触发父组件监听的事件,可以在 updated() 中去 emit。

    案例:

    <template>
      <div>
        <div>{{ drag ? "拖拽中" : "拖拽停止" }}</div>
        <!--使用draggable组件-->
        <draggable
          v-model="myArray"
          chosenClass="chosen"
          forceFallback="true"
          group="people"
          animation="1000"
          @start="onStart"
          @end="onEnd"
        >
          <transition-group>
            <div class="item" v-for="element in myArray" :key="element.id">
              {{ element.name }}
            </div>
          </transition-group>
        </draggable>
        <div class="color-list">
          <div
            class="color-item"
            v-for="color in colors"
            v-dragging="{ item: color, list: colors, group: 'color' }"
            :key="color.text"
          >
            {{ color.text }}
          </div>
        </div>
      </div>
    </template>
      <style scoped>
    /*被拖拽对象的样式*/
    .item {
      padding: 6px;
      background-color: #fdfdfd;
      border: solid 1px #eee;
      margin-bottom: 10px;
      cursor: move;
    }
    /*选中样式*/
    .chosen {
      border: solid 1px #3089dc !important;
    }
    </style>
      <script>
    //导入draggable组件
    import draggable from "vuedraggable";
    export default {
      //注册draggable组件
      components: {
        draggable,
      },
      data() {
        return {
          drag: false,
          //定义要被拖拽对象的数组
          myArray: [
            { people: "cn", id: 10, name: "www.itxst.com" },
            { people: "cn", id: 20, name: "www.baidu.com" },
            { people: "cn", id: 30, name: "www.taobao.com" },
            { people: "us", id: 40, name: "www.yahoo.com" },
          ],
          colors: [
            {
              text: "Aquamarine",
            },
            {
              text: "Hotpink",
            },
            {
              text: "Gold",
            },
            {
              text: "Crimson",
            },
            {
              text: "Blueviolet",
            },
            {
              text: "Lightblue",
            },
            {
              text: "Cornflowerblue",
            },
            {
              text: "Skyblue",
            },
            {
              text: "Burlywood",
            },
          ],
        };
      },
      methods: {
        //开始拖拽事件
        onStart() {
          this.drag = true;
        },
        //拖拽结束事件
        onEnd() {
          this.drag = false;
        },
      },
    };
    </script>
    

    四、Awe-dnd指令封装

    vue-dragging 的 npm 包的名字是 awe-dnd ,并不是 vue-dragging,这个库的特点是封装了 v-dragging 全局指令,然后通过全局指令去数据绑定等。

    相比及 vuedraggable 来说, awe-dnd 是没有双向绑定(这里没有双向绑定并不是很严谨,准确的来说没有暴露双向绑定的方式),因此提供了事件,在拖拽结束的时候用来更新列表(不需要手动更新列表,其实内部是实现了双向绑定的)或者是去触发父组件监听的事件。

    安装依赖:

    npm install awe-dnd --save
    yarn add awe-and
    

    main.js

    import VueDND from 'awe-dnd'
    
    Vue.use(VueDND)
    

    案例:

    <template>
      <div>
        <div class="color-list">
          <div
            class="color-item"
            v-for="color in colors"
            v-dragging="{ item: color, list: colors, group: 'color' }"
            :key="color.text"
          >
            {{ color.text }}
          </div>
        </div>
      </div>
    </template>
    <style scoped>
    /*被拖拽对象的样式*/
    .item {
      padding: 6px;
      background-color: #fdfdfd;
      border: solid 1px #eee;
      margin-bottom: 10px;
      cursor: move;
    }
    /*选中样式*/
    .chosen {
      border: solid 1px #3089dc !important;
    }
    </style>
    <script>
    export default {
      data() {
        return {
          drag: false,
          colors: [
            {
              text: "Aquamarine",
            },
            {
              text: "Hotpink",
            },
            {
              text: "Gold",
            },
            {
              text: "Crimson",
            },
            {
              text: "Blueviolet",
            },
            {
              text: "Lightblue",
            },
            {
              text: "Cornflowerblue",
            },
            {
              text: "Skyblue",
            },
            {
              text: "Burlywood",
            },
          ],
        };
      },
      methods: {},
    };
    </script>
    

    若对您有帮助,请点击跳转到B站一键三连哦!感谢支持!!!

    相关文章

      网友评论

          本文标题:Vue实现拖拽穿梭框功能四种方式

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