ElementUI滚动视图(类似走马灯)

描述

项目中使用到了 NavMenu 导航菜单 ,当菜单过长时会发生不雅观的事情(换行)
正好 Tabs 标签页 能够检测宽度不够时会出现一个支持内容左右滚动的容器
于是乎,我将其抽取出来作为 NavMenu 导航菜单 的外部容器

效果

当宽度不够时,是滚动而不是换行;
当宽度足够时,左右箭头隐藏无多余元素;
ElementUI滚动视图(类似走马灯)_第1张图片

使用

我已经将此封装成组件。
slot: 插槽 、props width:外层宽度限制(默认100%);
插槽要求有固定宽度

如果使用了 NavMenu 导航菜单,由于它是使用 ul li 元素通过 float 来实现的是无宽度的.

有两种解决方法:
1 直接赋值菜单具体宽度
2 在菜单使用 display: flex,实现了 float 的效果,同时具有自己的宽度


代码

github

<script>
import {
     
  addResizeListener,
  removeResizeListener
} from 'element-ui/src/utils/resize-event'

export default {
     
  props: {
     
    width: {
     
      type: String,
      default: '100%'
    }
  },

  data () {
     
    return {
     
      scrollable: false,
      navOffset: 0
    }
  },

  computed: {
     
    navStyle () {
     
      return {
     
        transform: `translateX(-${
       this.navOffset}px)`
      }
    }
  },

  methods: {
     
    scrollPrev () {
     
      const containerSize = this.$refs.navScroll.offsetWidth
      const currentOffset = this.navOffset

      if (!currentOffset) return

      const newOffset =
        currentOffset > containerSize ? currentOffset - containerSize : 0

      this.navOffset = newOffset
    },
    scrollNext () {
     
      const navSize = this.$refs.nav.offsetWidth
      const containerSize = this.$refs.navScroll.offsetWidth
      const currentOffset = this.navOffset

      if (navSize - currentOffset <= containerSize) return

      const newOffset =
        navSize - currentOffset > containerSize * 2
          ? currentOffset + containerSize
          : navSize - containerSize

      this.navOffset = newOffset
    },
    scrollToActiveTab () {
     
      if (!this.scrollable) return

      const nav = this.$refs.nav
      const activeTab = this.$el.querySelector('.is-active')
      if (!activeTab) return
      const navScroll = this.$refs.navScroll
      const activeTabBounding = activeTab.getBoundingClientRect()
      const navScrollBounding = navScroll.getBoundingClientRect()
      const maxOffset = nav.offsetWidth - navScrollBounding.width
      const currentOffset = this.navOffset
      let newOffset = currentOffset

      if (activeTabBounding.left < navScrollBounding.left) {
     
        newOffset =
          currentOffset - (navScrollBounding.left - activeTabBounding.left)
      }
      if (activeTabBounding.right > navScrollBounding.right) {
     
        newOffset =
          currentOffset + activeTabBounding.right - navScrollBounding.right
      }
      newOffset = Math.max(newOffset, 0)
      this.navOffset = Math.min(newOffset, maxOffset)
    },
    update () {
     
      if (!this.$refs.nav) return
      const navSize = this.$refs.nav.offsetWidth
      this.height = this.$refs.nav.offsetHeight
      const containerSize = this.$refs.navScroll.offsetWidth
      const currentOffset = this.navOffset
      if (containerSize < navSize) {
     
        const currentOffset = this.navOffset
        this.scrollable = this.scrollable || {
     }
        this.scrollable.prev = currentOffset
        this.scrollable.next = currentOffset + containerSize < navSize
        if (navSize - currentOffset < containerSize) {
     
          this.navOffset = navSize - containerSize
        }
      } else {
     
        this.scrollable = false
        if (currentOffset > 0) {
     
          this.navOffset = 0
        }
      }
    }
  },

  updated () {
     
    this.update()
  },

  render () {
     
    const {
      navStyle, scrollable, scrollNext, scrollPrev, height, width } = this
    const lineHeight = {
     
      'line-height': height + 'px'
    }
    const scrollBtn = scrollable
      ? [
        <span
          class={
     ['scrollView__nav-prev', scrollable.prev ? '' : 'is-disabled']}
          on-click={
     scrollPrev}
        >
          <i
            style={
     lineHeight}
            class="el-icon-arrow-left"></i>
        </span>,
        <span
          class={
     ['scrollView__nav-next', scrollable.next ? '' : 'is-disabled']}
          on-click={
     scrollNext}
        >
          <i style={
     lineHeight}
            class="el-icon-arrow-right"></i>
        </span>
      ]
      : null

    return (
      <div
        class={
     [
          'scrollView__nav-wrap',
          scrollable ? 'is-scrollable' : ''
        ]}
        style={
     {
      width }}
      >
        {
     scrollBtn}
        <div
          class="scrollView__nav-scroll"
          ref="navScroll"
        >
          <div
            class="scrollView__nav"
            ref="nav"
            style={
     navStyle}
          >
            {
     this.$slots.default}
          </div>
        </div>
      </div>
    )
  },

  mounted () {
     
    addResizeListener(this.$el, this.update)
  },

  beforeDestroy () {
     
    if (this.$el && this.update) removeResizeListener(this.$el, this.update)
  }
}
</script>

<style lang="less">
.scrollView__nav-wrap {
     
  display: inline-block;
  overflow: hidden;
  margin-bottom: -1px;
  position: relative;
  vertical-align: middle;
}

.scrollView__nav-wrap.is-scrollable {
     
  padding: 0 20px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}

.scrollView__nav-wrap::after {
     
  display: none;
}

.scrollView__nav-scroll {
     
  overflow: hidden;
}

.scrollView__nav {
     
  white-space: nowrap;
  position: relative;
  transition: transform 0.3s, -webkit-transform 0.3s;
  float: left;
  z-index: 2;
}

.scrollView__nav-prev {
     
  left: 0;
}
.scrollView__nav-next {
     
  right: 0;
}
.scrollView__nav-next,
.scrollView__nav-prev {
     
  position: absolute;
  cursor: pointer;
  line-height: 44px;
  font-size: 12px;
  color: #909399;
}
</style>

你可能感兴趣的:(elementUI,vue.js,前端)