vue项目实现左右拖拽改变宽度的组件封装

效果大概时这样,拖动中间区域实现左右宽度的改变

 directive文件

//拖拽改变横向尺寸
export const dragSize = {
    //自定义指令
    bind(el, binding) {
        let endx, differenceX
        el.onmousedown = (e) => {
            if (e.target.className.indexOf('bar') == -1) {
                return
            }
            const X = el.offsetLeft
            const Y = el.offsetTop
            const parentW = el.parentNode.offsetWidth
            var box = document.createElement('div')
            box.style.borderLeft = `1px solid #409eff`
            box.style.width = `0px`
            box.style.height = `${binding.value}`
            box.style.position = `absolute`
            box.style.left = X + 'px';
            box.style.top = Y + 'px';
            box.style.cursor = `w-resize`
            box.style.zIndex = `100000`
            el.parentNode.appendChild(box);
            /*ie9+*/
            /*禁止选择*/
            document.body.onselectstart = function () {
                return false;
            }
            document.onmousemove = (e) => {
                document.body.style.cursor = `w-resize`
                //differenceX为bar的宽度加margin
                differenceX = el.nextElementSibling.getBoundingClientRect().left - el.getBoundingClientRect().left
                endx = e.clientX - el.parentNode.getBoundingClientRect().left;
                //设置边界,根据min-width: 20%;跟max-width: 80%来判断
                if (el.nextElementSibling.className === 'container-right') {
                    if (endx < parentW * 0.2 - differenceX) {
                        endx = parentW * 0.2 - differenceX
                    }
                    if (endx > parentW * 0.8 - differenceX) {
                        endx = parentW * 0.8 - differenceX
                    }
                }
                //设置边界,根据min-width: 14px;跟max-width: 4%来判断
                if (el.nextElementSibling.className === 'container-text') {
                    if (endx > parentW - 14 - differenceX) {
                        endx = parentW - 14 - differenceX
                    }
                    if (endx < parentW * 0.96 - differenceX) {
                        endx = parentW * 0.96 - differenceX
                    }
                }
                box.style.left = endx + 'px';
            }
            document.onmouseup = () => {
                if (endx && differenceX) {
                    el.nextElementSibling.style.width = `${parentW - endx - differenceX}px`
                }
                document.onmousemove = null;
                document.onmouseup = null;
                document.body.onselectstart = null
                endx = null
                differenceX = null
                document.body.style.cursor = `default`
                el.parentNode.removeChild(box);
            }
        }
    },
}

引入layout布局vue组件

<template>
    <el-container class="container" :style="{ height: controlHeight }">
      <div class="container-left">
        <slot name="left-container"></slot>
      </div>
  
      <div class="bar" v-dragSize="controlHeight">
        <div class="aside-control" @click="expandDisplaySidebar">
          <div class="aside-control-button"></div>
          <i class="icon" :class="asideIcon"></i>
        </div>
      </div>
      
      <div class="container-right" v-if="asideIcon == 'el-icon-caret-right'" style="width: 20%;">
        <slot name="right-container" :asideIcon="asideIcon"></slot>
      </div>
      <div v-else class="container-text" @click="expandDisplaySidebar" style="width: 14px;">
        {{ shrinkText }}
      </div>
    </el-container>
  </template>
  
  <script>
import {dragSize} from "@/utils/directives";
  export default {
    name: "Layout",
    data() {
      return {
        asideIcon: "el-icon-caret-right",
        currentHeight: "",
      };
    },
    methods: {
      expandDisplaySidebar() {
        if (this.asideIcon == "el-icon-caret-right") {
          this.asideIcon = "el-icon-caret-left";
        } else {
          this.asideIcon = "el-icon-caret-right";
        }
      },
    },
    props: {
      shrinkText: {
        type: String,
        required: true,
        default: "qwewqewqe",
      },
      controlHeight: {
        type: String,
        required: true,
        default: "calc(100vh - 50px)",
      },
    },
    directives: {
      dragSize,
    }
  };
  </script>
  
  
  <style lang="scss" scoped>
  .container {
    position: relative;
    width: 100%;
    .container-right {
      margin-left: 5px;
      min-width: 20%; /*设置宽度范围*/
      max-width: 80%;
      overflow: auto;
    }
    .container-left {
      flex-grow: 1;
      overflow-x: hidden;
    }
    .bar {
      position: relative;
      cursor: w-resize;
      width: 10px;
      height: 100%;
      border-left: 1px solid rgba(00, 00, 00, 0.5);
      background-color: #e9f0f3;
      .aside-control {
        &:hover {
          cursor: pointer;
        }
        .aside-control-button {
          position: absolute;
          top: 50%;
          transform: translate(-50%);
          width: 7px;
          height: 30px;
          background-color: #eeeef1;
          /*perspective:对元素进行透视操作*/
          /*rotateX:以y轴(横轴)进行旋转(前后仰俯)
    画个梯形出来*/
          transform: translate(105%, -50%) perspective(0.5em) rotateY(20deg);
          text-align: center;
          line-height: 80px;
          color: #909399;
        }
        .icon {
          position: absolute;
          top: 50%;
          transform: translate(-10%, -50%);
        }
      }
    }
    .container-text {
      min-width: 14px; /*设置宽度范围*/
      max-width: 4%;
      text-align: center;
      cursor: pointer;
      word-wrap: break-word;
      word-break: break-all;
    }
  }
  </style>
  

在需要的地方引入传入props跟插槽

     
import Layout from "@/components/Layout";
 <Layout shrinkText="展开吧宝w贝" controlHeight="100%">
        <template slot="left-container">123</template>
        <template #right-container>321</template>
      </Layout>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值