index.js 4.34 KB
Newer Older
乐宝呗666's avatar
乐宝呗666 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
import { throttle } from 'lodash'
import { mapState } from 'vuex'
import menuMixin from '../mixin/menu'
import { createMenu } from '../libs/util.menu'

export default {
  name: 'd2-layout-header-aside-menu-header',
  mixins: [
    menuMixin
  ],
  render (h) {
    return <div
      flex="cross:center"
      class={ { 'd2-theme-header-menu': true, 'is-scrollable': this.isScroll } }
      ref="page">
      <div
        ref="content"
        class="d2-theme-header-menu__content"
        flex-box="1"
        flex>
        <div
          class="d2-theme-header-menu__scroll"
          flex-box="0"
          style={ { transform: `translateX(${this.currentTranslateX}px)` } }
          ref="scroll">
          <el-menu
            mode="horizontal"
            defaultActive={ this.active }
            onSelect={ this.handleMenuSelect }>
            { this.header.map(menu => createMenu.call(this, h, menu)) }
          </el-menu>
        </div>
      </div>
      {
        this.isScroll
          ? [
            <div
              class="d2-theme-header-menu__prev"
              flex="main:center cross:center"
              flex-box="0"
              onClick={ () => this.scroll('left') }>
              <i class="el-icon-arrow-left"></i>
            </div>,
            <div
              class="d2-theme-header-menu__next"
              flex="main:center cross:center"
              flex-box="0"
              onClick={ () => this.scroll('right') }>
              <i class="el-icon-arrow-right"></i>
            </div>
          ]
          : []
      }
    </div>
  },
  computed: {
    ...mapState('d2admin/menu', [
      'header'
    ])
  },
  data () {
    return {
      active: '',
      isScroll: false,
      scrollWidth: 0,
      contentWidth: 0,
      currentTranslateX: 0,
      throttledCheckScroll: null
    }
  },
  watch: {
    '$route.matched': {
      handler (val) {
        this.active = val[val.length - 1].path
      },
      immediate: true
    }
  },
  methods: {
    scroll (direction) {
      if (direction === 'left') {
        // 向右滚动
        this.currentTranslateX = 0
      } else {
        // 向左滚动
        if (this.contentWidth * 2 - this.currentTranslateX <= this.scrollWidth) {
          this.currentTranslateX -= this.contentWidth
        } else {
          this.currentTranslateX = this.contentWidth - this.scrollWidth
        }
      }
    },
    checkScroll () {
      let contentWidth = this.$refs.content.clientWidth
      let scrollWidth = this.$refs.scroll.clientWidth
      if (this.isScroll) {
        // 页面依旧允许滚动的情况,需要更新width
        if (this.contentWidth - this.scrollWidth === this.currentTranslateX) {
          // currentTranslateX 也需要相应变化【在右端到头的情况时】
          this.currentTranslateX = contentWidth - scrollWidth
          // 快速的滑动依旧存在判断和计算时对应的contentWidth变成正数,所以需要限制一下
          if (this.currentTranslateX > 0) {
            this.currentTranslateX = 0
          }
        }
        // 更新元素数据
        this.contentWidth = contentWidth
        this.scrollWidth = scrollWidth
        // 判断何时滚动消失: 当scroll > content
        if (contentWidth > scrollWidth) {
          this.isScroll = false
        }
      }
      // 判断何时滚动出现: 当scroll < content
      if (!this.isScroll && contentWidth < scrollWidth) {
        this.isScroll = true
        // 注意,当isScroll变为true,对应的元素盒子大小会发生变化
        this.$nextTick(() => {
          contentWidth = this.$refs.content.clientWidth
          scrollWidth = this.$refs.scroll.clientWidth
          this.contentWidth = contentWidth
          this.scrollWidth = scrollWidth
          this.currentTranslateX = 0
        })
      }
    }
  },
  mounted () {
    // 初始化判断
    // 默认判断父元素和子元素的大小,以确定初始情况是否显示滚动
    window.addEventListener('load', this.checkScroll)
    // 全局窗口变化监听,判断父元素和子元素的大小,从而控制isScroll的开关
    this.throttledCheckScroll = throttle(this.checkScroll, 300)
    window.addEventListener('resize', this.throttledCheckScroll)
  },
  beforeDestroy () {
    // 取消监听
    window.removeEventListener('resize', this.throttledCheckScroll)
    window.removeEventListener('load', this.checkScroll)
  }
}