vue自定义组件——split-pane

科技资讯 投稿 6700 0 评论

vue自定义组件——split-pane

组件介绍

    props:
    • splitCount: 分割数量, default: 2
    • direction: 分割方向, 'vertical' or 'horizontal', default: 'horizontal'
    • defaultRatio: 默认比例, 类型为数组, default: [1/spiltCount, 1/spiltCount, ...]
  • slots:
  • ...
  • events:
      @resize: 拖动分割条时触发, 参数为分割线两侧的div
  • @resize-stop: 拖动分割条结束时触发
  • methods:
      changeItemSize(index, itemSize, dire='next' 改变第item个pane的大小, dire为next或prev, 表示修改当前pane时连带修改前一个pane还是后一个
  • 效果展示

    设计思路

    flex-direction控制分割方向,通过修改每个pane的style.flex控制每个pane的大小。

    <div class="split-main" ref="splitMain"
         :class="direction === 'vertical' ? 'split-vertical' : 'split-horizontal'">
      <template v-if="direction === 'vertical'">
        <div v-for="i in splitCount" :key="i" ref="splitItem"
             class="split-vertical-item">
          <div class="split-vertical-line" v-if="i < splitCount"
               @mousedown="_startDrag(i"
               @touchstart="_startDrag(i"></div>
          <div class="split-vertical-content">
            <slot :name="`pane${i}`"></slot>
          </div>
        </div>
      </template>
      <template v-else>
        <div v-for="i in splitCount" :key="i" ref="splitItem"
             class="split-horizontal-item">
          <div class="split-horizontal-line" v-if="i < splitCount"
               @mousedown="_startDrag(i"
               @touchstart="_startDrag(i"></div>
          <div class="split-horizontal-content">
            <slot :name="`pane${i}`"></slot>
          </div>
        </div>
      </template>
    </div>
    

    通过v-for循环生成分割数量的pane,每个pane中间插入分割线,分割线通过@mousedown@touchstart事件绑定_startDrag方法,该方法用于监听鼠标或手指的移动事件,从而实现拖动分割线改变pane大小的功能。

    _startDrag (index {
      this.dragIndex = index - 1
    },
    _onMouseMove (e {
      if (this.dragIndex === -1 {
        return
      }
      let items = this.$refs.splitItem
      let item1 = items[this.dragIndex]
      let item2 = items[this.dragIndex + 1]
      let rect1 = item1.getBoundingClientRect(
      let rect2 = item2.getBoundingClientRect(
      let ratio1, ratio2
      let minLen = this.minLen
      if (this.direction === 'vertical' {
        let height = this.$refs.splitMain.clientHeight
        let tempY = e.clientY - rect1.top > minLen ? e.clientY : rect1.top + minLen
        tempY = rect2.bottom - tempY > minLen ? tempY : rect2.bottom - minLen
        ratio1 = (tempY - rect1.top / height
        ratio2 = (rect2.bottom - tempY / height
      } else {
        let width = this.$refs.splitMain.clientWidth
        let tempX = e.clientX - rect1.left > minLen ? e.clientX : rect1.left + minLen
        tempX = rect2.right - tempX > minLen ? tempX : rect2.right - minLen
        ratio1 = (tempX - rect1.left / width
        ratio2 = (rect2.right - tempX / width
      }
      item1.style.flex = ratio1
      item2.style.flex = ratio2
      e.preventDefault(
      this.$emit('resize', item1, item2
    },
    _onMouseUp ( {
      if (this.dragIndex === -1 {
        return
      }
      this.dragIndex = -1
      this.$emit('resize-stop'
    }
    

    完整代码在github上。https://github.com/lxmghct/my-vue-components

    编程笔记 » vue自定义组件——split-pane

    赞同 (40) or 分享 (0)
    游客 发表我的评论   换个身份
    取消评论

    表情
    (0)个小伙伴在吐槽