1
Vue 进阶(幺叁陆):el-steps 实现页面内导航
发布于: 刚刚
一、前言
在前端开发过程中,当页面内容分为若干栏目后,通过增加导航栏位定位至相应栏目不失为一种良好的用户体验。
应用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-steps
的direction
、space
、active
、process-status
、align-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>
复制代码
四、拓展阅读
划线
评论
复制
发布于: 刚刚阅读数: 2
版权声明: 本文为 InfoQ 作者【No Silver Bullet】的原创文章。
原文链接:【http://xie.infoq.cn/article/746afc5b5cca5e4bd4f24d3c4】。文章转载请联系作者。
No Silver Bullet 2021.07.09 加入
岂曰无衣 与子同袍
评论