25-vue中实现拖动调整左右两侧盒子的宽度

这里是直接完整一个组件,路由引入即可看到效果。

<template>
  <div class="box" ref="box">
    <div class="left">
      <!--左侧div内容-->
      <h1>到了时间你就一定要上场</h1>
      <h1>当意识到达,那就必须上岸</h1>
    </div>
    <div class="resize" title="收缩侧边栏"></div>
    <div class="mid">
      <!--右侧div内容-->
      <h1>我希望我希望的有希望</h1>
      <h1>想着光向着光</h1>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {};
  },
  methods: {
    dragControllerDiv() {
      var resize = document.getElementsByClassName("resize")[0];
      var left = document.getElementsByClassName("left");
      var mid = document.getElementsByClassName("mid");
      var box = document.getElementsByClassName("box")[0];

      // 鼠标按下事件
      resize.onmousedown = function (e) {
        //颜色改变提醒
        resize.style.background = "#818181";
        var startX = e.clientX;
        resize.left = resize.offsetLeft;
        // 鼠标拖动事件
        document.onmousemove = function (e) {
          var endX = e.clientX;
          var moveLen = resize.left + (endX - startX); // (endx-startx)=移动的距离。resize.left+移动的距离=左边区域最后的宽度
          var maxT = box.clientWidth - resize.offsetWidth; // 容器宽度 - 左边区域的宽度 = 右边区域的宽度

          if (moveLen < 32) moveLen = 32; // 左边区域的最小宽度为32px
          if (moveLen > maxT - 150) moveLen = maxT - 150; //右边区域最小宽度为150px

          resize.style.left = moveLen; // 设置左侧区域的宽度

          for (let j = 0; j < left.length; j++) {
            left[j].style.width = moveLen + "px";
            mid[j].style.width = box.clientWidth - moveLen - 10 + "px";
          }
        };
        // 鼠标松开事件
        document.onmouseup = function () {
          //颜色恢复
          resize.style.background = "#d6d6d6";
          document.onmousemove = null;
          document.onmouseup = null;
          resize.releaseCapture && resize.releaseCapture(); //当你不在需要继续获得鼠标消息就要应该调用ReleaseCapture()释放掉
        };
        resize.setCapture && resize.setCapture(); //该函数在属于当前线程的指定窗口里设置鼠标捕获
        return false;
      };
    },
  },
  mounted() {
    this.dragControllerDiv();
  },
};
</script>

<style scoped>
/* 拖拽相关样式 */
/*包围div样式*/
.box {
  width: 100%;
  height: 50vh;
  margin: 5vh 0px;
  overflow: hidden;
  box-shadow: -1px 9px 10px 3px rgba(0, 0, 0, 0.11);
}
/*左侧div样式*/
.left {
  width: calc(32% - 10px); /*左侧初始化宽度*/
  height: 100%;
  background: #ffffff;
  float: left;
}
/*拖拽区div样式*/
.resize {
  cursor: col-resize;
  float: left;
  position: relative;
  top: 45%;
  background-color: #d6d6d6;
  border-radius: 5px;
  margin-top: -10px;
  width: 10px;
  height: 50px;
  background-size: cover;
  background-position: center;
  /*z-index: 99999;*/
  font-size: 32px;
  color: white;
}
/*拖拽区鼠标悬停样式*/
.resize:hover {
  color: #444444;
}
/*右侧div'样式*/
.mid {
  float: left;
  width: 68%; /*右侧初始化宽度*/
  height: 100%;
  background: #fff;
  box-shadow: -1px 4px 5px 3px rgba(0, 0, 0, 0.11);
}
</style>

 左侧如果有ifame,解决方案参考


 

封装好的组件:(vue文件)

 

<template>
  <div id="dragLayoutBox">
    <div class="left_box">
      <slot name="left-content"></slot>
    </div>
    <div class="right_box">
      <div v-if="iframeIsHave" class="opacity_box"></div>
      <div
        v-show="dragBtnFlag"
        class="drag_btn"
        @mousedown="changeBoxStyleFn('')"
        @onmouseup="changeBoxStyleFn('none')"
      ></div>
      <slot name="right-content"> </slot>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    // 是否默认显示拖拽按钮
    dragBtnFlag: {
      typeof: Boolean,
      default: true
    },
    // 盒子中是否有iframme
    iframeIsHave: {
      typeof: Boolean,
      default: false
    },
    // 配置项 注意:色值暂时只支持16进制写法
    setCssProps: {
      typeof: Object,
      default: () => ({
        // 左右盒子最小拖动宽度
        leftMinWidth: '200px',
        rightMinWidth: '500px',
        dragBtnCss: {
          mousedown: {
            background: '#919191'
          },
          onmouseup: {
            background: '#d6d6d6'
          }
        }
      })
    }
  },
  mounted() {
    if (this.iframeIsHave) {
      this.changeBoxStyleFn('none')
    }
    this.dragChangeLayoutFn()
  },
  methods: {
    getDomFn(name) {
      const ele = document.querySelector(name)
      const ws = new WeakSet()
      ws.add(ele)
      return ele
    },
    changeBoxStyleFn(value) {
      if (this.iframeIsHave) {
        const opacityBox = this.getDomFn('.opacity_box')
        opacityBox.style.display = value
      }
    },
    dragChangeLayoutFn() {
      const that = this
      const dragBtn = this.getDomFn('.drag_btn')
      const left_box = this.getDomFn('.left_box')
      const right_box = this.getDomFn('.right_box')
      const dragLayoutBox = this.getDomFn('#dragLayoutBox')
      dragBtn.onmousedown = function (e) {
        const styleStr = that.handleEleStyleFn(that.setCssProps.dragBtnCss.mousedown)
        dragBtn.style.cssText = `${styleStr}`
        const startPos = e.clientX
        dragBtn.left = dragBtn.offsetLeft
        document.onmousemove = e => {
          const endPos = e.clientX
          let moveW = dragBtn.left - 20 + (endPos - startPos)
          const maxW = dragLayoutBox.clientWidth - dragBtn.offsetWidth
          // 左边区域的最小宽度
          const leftValue = parseInt(that.setCssProps.leftMinWidth)
          if (moveW < leftValue) {
            moveW = leftValue
          }
          // 右边区域最小宽度
          const rightValue = parseInt(that.setCssProps.rightMinWidth)
          if (moveW > maxW - rightValue) {
            moveW = maxW - rightValue
          }
          left_box.style.cssText = `width:${moveW}px`
          right_box.style.width = dragLayoutBox.clientWidth - moveW + 'px'
        }
        document.onmouseup = () => {
          const styleStr = that.handleEleStyleFn(that.setCssProps.dragBtnCss.onmouseup)
          dragBtn.style.cssText = `${styleStr}`
          document.onmousemove = document.onmouseup = null
          if (that.iframeIsHave) {
            that.changeBoxStyleFn('none')
          }
          dragBtn.releaseCapture && dragBtn.releaseCapture()
        }
        dragBtn.setCapture && dragBtn.setCapture()
        return false
      }
    },
    // 处理传来的对象:{k1:"v1",k2:"v2"} => "k1:v1;k2:v2"
    handleEleStyleFn(obj) {
      let str = JSON.stringify(obj)
      const indexstart = str.indexOf('{')
      const indexEnd = str.indexOf('}')
      str = str.slice(indexstart + 1).slice(0, indexEnd - 1)
      const reg1 = /,/g
      const reg2 = /"|'/g
      return str.replace(reg1, ';').replace(reg2, '')
    }
  }
}
</script>

<style scoped>
#dragLayoutBox {
  width: 100%;
  display: flex;
  justify-content: space-between;
  box-shadow: 0px 20px 40px 0px rgba(0, 0, 0, 0.08);
}
.drag_btn {
  position: absolute;
  top: calc((100vh - 50px) / 2);
  width: 8px;
  height: 50px;
  cursor: col-resize;
  background: rgba(0, 0, 0, 0.1);
  border-radius: 5px;
  margin-top: -10px;
  background-size: cover;
  background-position: center;
  font-size: 32px;
  color: white;
  z-index: 1112;
}
.opacity_box {
  width: 100%;
  height: 100%;
  position: absolute;
  margin-top: 30px;
  filter: alpha(opacity=0);
  opacity: 0;
  background: transparent;
  z-index: 1111;
}
</style>

 

使用:

1.引入和注册

const LayoutDrag = () => import('./LayoutDrag/index.vue')
components: {  LayoutDrag }

2.使用:iframeIsHave为true表示右侧区域内有iframe,默认不传则为false,这个的判定就是为了解决当有iframe(比如富文本)拖拽时卡顿问题

 <LayoutDrag :iframeIsHave="true">
    <template v-slot:left-content>
        // 你的左侧盒子的盛放区域
    </template>

    <template v-slot:right-content>
      // 你的右侧盒子盛放区域
    </template>
</LayoutDrag>

 

posted @ 2022-04-12 22:22  猎奇游渔  阅读(954)  评论(0编辑  收藏  举报