Vue组件 el-steps 实现页面内导航

举报
SHQ5785 发表于 2022/03/20 18:17:14 2022/03/20
【摘要】 一、前言在前端开发过程中,当页面内容分为若干栏目后,通过增加导航栏位定位至相应栏目不失为一种良好的用户体验。应用el-steps可实现页面内栏目跳转。el-steps基本用法如下:<el-steps :active="active" finish-status="success"> <el-step title="步骤 1"></el-step> <el-step title="步...

一、前言

在前端开发过程中,当页面内容分为若干栏目后,通过增加导航栏位定位至相应栏目不失为一种良好的用户体验。

应用el-steps可实现页面内栏目跳转。el-steps基本用法如下:

<el-steps :active="active" finish-status="success">
   <el-step title="步骤 1"></el-step>
   <el-step title="步骤 2"></el-step>
   <el-step title="步骤 3"></el-step>
</el-steps>
<el-button style="margin-top:12px;" @click="next">下一步</el-button>
data:{
    active:0
},
methods:{
    next(){
        if(this.active++ >2){
            this.active = 0
        }
    }
}

二、属性介绍

下面重点介绍el-stepsdirectionspaceactiveprocess-statusalign-center属性,如下:
在这里插入图片描述

通过查看Element手册,需要定宽的步骤条时,设置space属性即可,单位为px,如果不设置为自适应(若不确定步骤条中每一步骤中内容高度或宽度,可设置为自适应;为使界面美观,可修改el-step属性:

.el-step__main {
	width: 100%!important;
	padding-left: 3%!important;
	margin-bottom: 3%!important;
}


el-step属性如下图所示:
在这里插入图片描述

这里重点介绍下如何应用el-steps动态展示所需信息。

三、Demo

<div>
	<el-steps direction="vertical" :align-center="true" :active="arr.length" finish-status="success">
	<el-step :title="item.title" :description="item.description" v-for="(item, index) in arr" :key="index" @click.native="onCLick(index)">
		<template slot="description">
			<!--表单内容-->
		</template>
	</el-step>
</el-steps>
</div>
<div>
	<transition name="slide-fade">
		<div v-if="shownav" class="rightList">
			<span class="line_prev"></span>
			<ul>
				<li v-for="(item, index) in navArr" :key="index" @click="crollTo(index)" :class="{active: active====index}">
					<img src="cue.png" v-if="active === index">
				</li>
			</ul>
			<span class="line_next"></span>
		</div>
	</transition>
</div>

以上只是实现了步骤条内容的动态展示,若需实现根据用户浏览内容定位导航栏目或者根据导航栏目快速定位至相关栏目处,需通过动态监听页面内容实现。

<!--流程流转处理节点导航栏位-->
<div v-if="flowopinoin.length > 4" :class="[flowopinoin.length > 10 ? 'navConst' : 'nav']">
  <div :class="[flowopinoin.length > 10 ? 'navStyleConst' : 'navStyle']">
    <transition name="slide-fade">
      <div v-if="shownav" class="rightList">
        <span class="line_prev"></span>
        <ul>
          <li v-for="(item, index) in flowopinoin" :key="index" @click="scrollTo(index)" :class="{active: active===index}">
            <img src="../../../assets/img/cur.png" width="20" v-if="active === index"/>
            <span>{{item.nodename}}</span>
          </li>
        </ul>
        <span class="line_next"></span>
      </div>
    </transition>
  </div>
  <el-button @click="shownav = !shownav" type="primary" :class="[flowopinoin.length > 10 ? 'shownavConst' : 'shownav']">
    <i style="margin-left: -6px;" :class="[shownav ? 'el-icon-d-arrow-right': 'el-icon-d-arrow-left']"></i>
  </el-button>
</div>
<script>
      this.$nextTick(() => {
        // 监听滚动事件
        window.addEventListener('scroll', this.onScroll, false)
      })


// 滚动监听器
onScroll () {
	// 获取所有锚点元素
	const navContents = document.querySelectorAll('.el-steps>.el-step')
	// console.log('navContents:', navContents)
	// 所有锚点元素的 offsetTop
	const offsetTopArr = []
	for (let i = 0; i < navContents.length; i++) {
		offsetTopArr.push(navContents[i].offsetTop)
	}
	//        navContents.forEach(item => {
	//          offsetTopArr.push(item.offsetTop)
	//        })
	// 获取当前文档流的 scrollTop
	const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
	// 定义当前点亮的导航下标
	for (let n = 0; n < offsetTopArr.length; n++) {
		// 如果 scrollTop 大于等于第n个元素的 offsetTop 则说明 n-1 的内容已经完全不可见
		// 那么此时导航索引就应该是n了
		// console.log('scrollTop:', scrollTop)
		// console.log('offsetTopArr[n]:', offsetTopArr[n])
		if (scrollTop >= offsetTopArr[n]) {
		  this.navIndex = n
		}
	}
	this.active = this.navIndex
},
// 跳转到指定索引的元素
scrollTo (index) {
	// 获取目标的 offsetTop
	// css选择器是从 1 开始计数,我们是从 0 开始,所以要 +1
	const targetOffsetTop = document.querySelector(`.el-steps>.el-step:nth-child(${index + 1})`).offsetTop
	// 获取当前 offsetTop
	let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
	// 定义一次跳 50 个像素,数字越大跳得越快,但是会有掉帧得感觉,步子迈大了会扯到蛋
	const STEP = 50
	// 判断是往下滑还是往上滑
	// console.log('scrollTop:', scrollTop)
	// console.log('targetOffsetTop:', targetOffsetTop)
	if (scrollTop >= targetOffsetTop) {
		// 往上滑
		smoothUp()
	} else {
		// 往下滑
		smoothDown()
	}
	// 定义往下滑函数
	function smoothDown () {
		// 如果当前 scrollTop 小于 targetOffsetTop 说明视口还没滑到指定位置
		if (scrollTop < targetOffsetTop) {
		// 如果和目标相差距离大于等于 STEP 就跳 STEP
		// 否则直接跳到目标点,目标是为了防止跳过了。
		if (targetOffsetTop - scrollTop >= STEP) {
		  scrollTop += STEP
		} else {
		  scrollTop = targetOffsetTop
		}
		document.body.scrollTop = scrollTop
		document.documentElement.scrollTop = scrollTop
		// 关于 requestAnimationFrame 可以自己查一下,在这种场景下,相比 setInterval 性价比更高
		requestAnimationFrame(smoothDown)
	  }
}
// 定义往上滑函数
function smoothUp () {
	if (scrollTop > targetOffsetTop) {
	  if (scrollTop - targetOffsetTop >= STEP) {
	    scrollTop -= STEP
	  } else {
	    scrollTop = targetOffsetTop
	  }
	  document.body.scrollTop = scrollTop
	  document.documentElement.scrollTop = scrollTop
	  requestAnimationFrame(smoothUp)
	}
}
}
</script>
<style>
	@charset "UTF-8";
	.navConst {
	  position:fixed;
	  right: 3%;
	  top:15%;
	}
	.nav {
	  position:fixed;
	  right: 2%;
	  top:15%;
	}
	.navStyleConst {
	  position:fixed;
	  top:15%;
	  cursor: pointer;
	  right: 3%;
	  width: 7%;
	  height: auto;
	  max-height:800px;
	  overflow: scroll;
	  overflow-x: hidden;
	}
	.navStyle {
	  position:fixed;
	  top:51%;
	  cursor: pointer;
	  right: 2%;
	  width: 7%;
	  height: auto;
	}
	.shownavConst {
	  position:absolute;
	  right: -37px;
	  top: 50%;
	  width: 10px;
	  height: 100px;
	}
	.shownav {
	  position: fixed;
	  right:18px;
	  top: 57%;
	}
	.shownav2 {
	  position: fixed;
	  right:18px;
	  top: 38%;
	}
	ul {
	  list-style: none;
	}
	.active img {
	  position: absolute;
	  left: -26px;
	  top: 5px;
	  z-index: 2;
	}
	.line_prev{
	  display:inline-block;
	  width: 1px;
	  height:20px;
	  background:#ccc;
	  position:relative;
	  left:20px;
	  bottom:-8px;
	}
	.line_prev:before{
	  content: '';
	  position:absolute;
	  width:9px;
	  height:9px;
	  border-radius:50%;
	  border:2px solid #EDEDED;
	  z-index:1;
	  left:-4px;
	  top:-8px;
	}
	.rightList li{
	  position:relative;
	  line-height:25px;
	  cursor:pointer;
	  padding-bottom:16px;
	}
	.rightList li span{
	  padding-left:5px;
	  border-bottom: 1px solid #e3e5eb;
	}
	.rightList li:before{
	  content: '';
	  position:absolute;
	  width:9px;
	  height:9px;
	  left:-24px;
	  border-radius:50%;
	  background: #FFFFFF;
	  border: 2px solid #EDEDED;
	  top:20%;
	  z-index:2;
	}
	/*.rightList li:after{*/
	/*content: '';*/
	/*position:absolute;*/
	/*width:9px;*/
	/*height:9px;*/
	/*border-radius:50%;*/
	/*background:#fff;*/
	/*left:-2px;*/
	/*top:33%;*/
	/*z-index:1;*/
	/*}*/
	.rightList li.active{
	  font-family: PingFangSC-Medium;
	  color: #20A0FF;
	  text-align: left;
	  line-height: 22px;
	}
	.rightList ul{
	  position:relative;
	}
	.rightList{
	  background:#fff;
	  right:10px;
	  box-shadow:0 0 5px 5px rgba(170,167,167,0.1);
	  z-index:13;
	}
	.rightList ul:after{
	  content:'';
	  width:1px;
	  height:100%;
	  display:inline-block;
	  background:#ccc;
	  position:absolute;
	  top:0;
	  left:20px;
	}
	.rightList .line_next{
	  display:inline-block;
	  width: 1px;
	  height:20px;
	  background:#ccc;
	  position:relative;
	  left:20px;
	  top:-15px;
	}
	.rightList .line_next:after{
	  content: '';
	  position:absolute;
	  width:9px;
	  height:9px;
	  border-radius:50%;
	  border:2px solid #EDEDED;
	  z-index:1;
	  left:-4px;
	  bottom: -8px;
	}
	.shownav.el-button.el-button--primary{
	  height:100px;
	  padding: 0 5px;
	}
	.shownav2.el-button.el-button--primary{
	  height:100px;
	  padding: 0 5px;
	}
	.slide-fade-enter-active{
	  transition: all 0.3s ease;
	}
	.slide-fade-leave-active{
	  transition: all 0.5s ease;
	}
	.slide-fade-enter, .slide-fade-leave-to{
	  /*transform: translateX(10px);*/
	  opacity:0;
	}
</style>

四、拓展阅读

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。