手写分屏插件(VUE版)

国外基于vue的分屏插件

Splitpanes:https://antoniandre.github.io/splitpanes/

自己手写一个简易版的分屏组件

为什么不用Splitpanes?在具体项目中,我发现Splitpanes存在bug,在使用Splitpanes时,如果里面的其中一个分屏出现iframe,则每次调整中间的分屏条都会很卡顿,貌似官方也没给具体的解决方案(查了很多种原因,试了很多种方解决都不行)。所以我这边又找网上资料,参照的写了个基于vue2版本的分屏组件。

具体实现

废话不多说,直接上代码

<template>
  <div class="pane" :style="{ flexDirection: direction }" ref="pane">
    <div class="left" :style="lengthType + paneLengthValue" v-show="leftVisable">
      <slot name="left">
      </slot>
    </div>
    <div
      class="trigger"
      :style="lengthType + triggerLengthValue"
      @mousedown="handleMouseDown"
      title="拖动调整"
    ></div>
    <div class="iframeDiv" ref="iframeDiv" v-show="leftVisable && rightVisable"></div>
    <div class="right" v-show="rightVisable">
      <slot name="right">
      </slot>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    direction: {
      //切屏方向
      type: String,
      default: "row",
    },
    paneLengthPercent: {
      //左侧切屏宽度%
      type: Number,
      default: 50,
    },
    triggerLength: {
      //滑块宽度px
      type: Number,
      default: 10,
    },
    leftVisable: {
      type: Boolean,
      default: ()=>true
    },
    rightVisable: {
      type: Boolean,
      default: ()=>true
    },
    triggerClick:{
      
    }
  },
  components: {},
  data() {
    return {
      triggerLeftOffset: 0, //鼠标距离滑轮左侧顶边距离
    };
  },
  computed: {
    lengthType() {
      if (this.direction === "row") {
        return "height:100%;width:";
      } else {
        return "width:100%;height:";
      }
    },
    paneLengthValue() {
      return `calc(${this.paneLengthPercent}% - ${
        this.triggerLength / 2 + "px"
      })`;
    },
    triggerLengthValue() {
      return `${this.triggerLength + "px"}`;
    },
    pane() {
      return this.$refs.pane;
    },
    iframeDiv() {
      return this.$refs.iframeDiv;
    },
  },
  watch:{
    leftVisable(val){
      console.log('leftVisable:',val)
      if(val){
        if(this.rightVisable){
          this.paneLengthPercent = 50
          this.triggerLength = 10  
        }else{
          this.paneLengthPercent = 100
          this.triggerLength = 0  
        }
      }else{
        this.paneLengthPercent = 0
        this.triggerLength = 0
      }
    },
    rightVisable(val){
      console.log('rightVisable:',val)
      if(val){
        if(this.leftVisable){
          this.paneLengthPercent = 50
          this.triggerLength = 10
        }else{
          this.paneLengthPercent = 0
          this.triggerLength = 0
        }
      }else{
        if(this.leftVisable){
          this.paneLengthPercent = 100
          this.triggerLength = 0
        }else{
          this.paneLengthPercent = 0
          this.triggerLength = 0
        }
      }
    }
  },
  methods: {
    // 按下滑动器后
    handleMouseDown(e) {
      console.log(e)
      document.addEventListener("mousemove", this.handleMouseMove);
      document.addEventListener("mouseup", this.handleMouseUp);
      //计算滑轮宽度
      if (this.direction === "row") {
        this.triggerLeftOffset =
          e.pageX - e.srcElement.getBoundingClientRect().left;
      } else {
        this.triggerLeftOffset =
          e.pageY - e.srcElement.getBoundingClientRect().top;
      }
      this.changeIframeDivStyle("");
    },
    // 按下滑动器后移动
    handleMouseMove(e) {
      const clientRect = this.pane.getBoundingClientRect(); //容器dom
      if (this.direction == "row") {
        const offset =
          e.pageX -
          clientRect.left -
          this.triggerLeftOffset +
          this.triggerLength / 2;
        this.paneLengthPercent = (offset / clientRect.width) * 100;
      } else {
        const offset =
          e.pageY -
          clientRect.height -
          this.triggerLeftOffset +
          this.triggerLength / 2;
        this.paneLengthPercent = (offset / clientRect.height) * 100;
      }
    },
    //鼠标松开
    handleMouseUp() {
      this.changeIframeDivStyle("none");
      document.removeEventListener("mousemove", this.handleMouseMove);
    },
    changeIframeDivStyle(display) {
      this.iframeDiv.style.display = display;
    },
  },
  mounted() {
    this.changeIframeDivStyle("none");
  },
};
</script>

<style>
.pane {
  display: flex;
  height: 100vh;
  position: relative;
}

.trigger {
  background-color: rgb(166, 175, 184);
  user-select: none;
}

.trigger:hover {
  cursor: col-resize;
  background-color: rgb(112, 126, 141);
}

.left {
  position: relative;
}

.right {
  flex: 1;
}

.iframeDiv {
  width: 100%;
  height: 100%;
  position: absolute;
  z-index: 9999;
  filter: alpha(opacity=0);
  opacity: 0;
  background: transparent;
}
</style>

注意:上面的iframeDiv遮罩层就可以解决卡顿问题

具体使用

import SplitPane from '~/SplitPane'
<SplitPane :leftVisable="iframeCertShow" :rightVisable="iframeOriginShow">
    <template v-slot:left>
      <div >
        <iframe
          ref="cert"
          :src="iframeSrcCert"
          frameborder="0"
          width="100%"
          style="height: 98vh; overflow-x: auto"
        />
      </div>

    </template>
    <template v-slot:right >
      <div >
        <iframe
          ref="orgin"
          :src="iframeSrcOrigin"
          frameborder="0"
          style="height: 98vh; overflow-x: auto"
          width="100%"
        />
      </div>
    </template>
  </SplitPane>

实际效果在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值