[vue ]滚动视图解决ElementUI NavMenu 导航菜单过长显示的问题
记录一下工作
需求
导航菜单过长的时候会溢出,需要一个像 Tabs 标签页一样的滚动视图容器,可以左右滚动内部视图。
解决方法
由于时间问题,所以直接将 Tabs 源码抽取出来使用。
这里要做一些特殊处理,不允许 NavMenu 导航菜单滚动视图容器内的元素换行。
如:
/deep/.el-menu--horizontal>.el-menu-item,.el-menu--horizontal>.el-submenu {
float: none !important;
display: inline-block !important;
}
使用方法如下:
<scrollView> <div> // 一些不换行内容 </div> </scrollView>
最后效果
下面是抽出来的源码,稍稍改造了下,左右箭头做了自适应垂直居中,把 elementui的样式抽取出来以及修改了类名,减少依赖。
scrollView.vue
<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>