功能

  • 節點樣式動態變化,模擬未進行、當前、已進行三種效果
  • 自動播放,也可以手動點擊節點切換
  • 根據節點數量改變佈局,節點較少時均勻分佈,節點較多時固定節點間距離,通過控制左右箭頭實現橫向滾動,滾動到最右(左)時隱藏右(左)箭頭

效果

節點數少於規定值(我這裏定<=10),隱藏左右箭頭,節點均勻分佈

節點數大於規定值,出現左右箭頭,固定節點間距離,可以橫向滾動

重點

  • 偽類樣式及修改
  • 監聽滾動事件

完整代碼

html

<div v-show="imgChange" class="bar">
        <!-- 左箭頭 -->
        <div :class="['toLeft', menuLeft ? '' : 'hide']" @click="toLeft">
            <img src="../../static/img/to_left.png" />
        </div>
        <!-- 要控制的面板 -->
        <div class="box">
            <ul class="ul" ref="menu" @scroll="orderScroll">
                <div class="ul-content">
                <li v-for="(point,i) in list" :key="i" :class="['point', (activeIndex == undefined || i > activeIndex) ? '': i == activeIndex ? 'active' : 'over']">
                    <div class="curPoint">{{point.name}}</div>
                    <div class="marker-out" @click="pointChange(point, i)">
                        <div class="marker-in"></div>
                    </div>
                    <div class="label" @click="pointChange(point, i)">
                        <el-tooltip class="item" effect="dark" :content="point.label" placement="bottom">
                            <span>{{point.label}}</span>
                        </el-tooltip>
                    </div>
                </li>
                </div>
            </ul>
        </div>
        <!-- 右箭頭 -->
        <div :class="['toRight', menuRight ? '' : 'hide']" @click="toRight">
            <img src="../../static/img/dataCenter/to_right.png" />
        </div>
    </div>

data

list: [
            {
                label: '標籤1',
                name: '名稱1'
            }
        ],
        activeIndex: undefined,
        menuLeft: false,
        menuRight: true,
        maxScrollLeft: undefined,
        interval: undefined

mounted

this.init()
        document.addEventListener('scroll',this.Scroll())

methods

init(){
            let that = this
            if(this.list.length <= 10){ //根據節點數量改變佈局方式
                document.getElementsByClassName('ul')[0].classList.add("flex")
                document.getElementsByClassName('toLeft')[0].classList.add("hide")
                document.getElementsByClassName('toRight')[0].classList.add("hide")
            }
            this.$nextTick(() => {
                document.getElementsByClassName('marker-out')[0].classList.add("first")
            })
        },
        autoProcess(){
            let that = this;
            this.activeIndex = undefined
            let length = this.list.length
            this.interval = setInterval(() => {
                if(that.activeIndex == undefined){
                    that.activeIndex = 0
                    that.makePopup(that.list[that.activeIndex]) //切換節點同時切換彈窗
                }else if(that.activeIndex < length-1){
                    that.activeIndex++
                    that.makePopup(that.list[that.activeIndex])
                }else{
                    clearInterval(that.interval)
                }
            }, 1000); 
        },
        layoutAdaptation(){
            let that = this
            this.$nextTick(() => {
                let elWidth = document.getElementsByClassName('point')[0].scrollWidth
                let lineWidth = elWidth - 22
                let lineLeft = 0 - lineWidth
                for(let i=0;i<document.styleSheets.length;i++){
                    document.styleSheets[i].addRule('.flex .marker-out:before', `width:${lineWidth}px;left:${lineLeft}px`)
                } //這裏不能用foreach
                that.calMaxScrollLeft() //計算最大橫向滾動像素值
            })
        },
        pointChange(point, i){
            this.activeIndex = i
            this.makePopup(point)
        },
        handlePointChange(index){
            this.pointChange(this.list[index], index)
        },
        makePopup(point){ //切換彈窗
            this.$emit('switchPopup', point)
        },
        calMaxScrollLeft(){
            let menuUl = document.getElementsByClassName('ul')[0]
            this.maxScrollLeft = menuUl.scrollWidth - menuUl.offsetWidth
        },
        toLeft(){
            this.$refs.menu.scrollLeft = this.$refs.menu.scrollLeft - 50 //滾動步長自行設置
        },
        toRight(){
            this.$refs.menu.scrollLeft = this.$refs.menu.scrollLeft + 50 
        },
        Scroll(e){
            // console.log('scrollLeft',this.$refs.menu.scrollLeft)
        },
        orderScroll(){
            // console.log('this.$refs.menu.scrollLeft',this.$refs.menu.scrollLeft)
            if(this.$refs.menu.scrollLeft > 0){
                this.menuLeft = true
            }else{
                this.menuLeft = false
            }
            if(this.$refs.menu.scrollLeft >= (this.maxScrollLeft - 1)){
                this.menuRight = false
            }else{
                this.menuRight = true
            }
        }

watch

flag: function(newVal,oldVal) {
          if(this.flag){
            this.autoProcess()
            this.layoutAdaptation()
          }else{
              clearInterval(this.interval)
          }
      }

css

.bar{
    height: 143px;
    width: 1162px;
    background: url('../../static/img/tourBar.png') 100% 100% no-repeat;
    display: flex;
}

/* 左右箭頭 */
.toLeft, .toRight{
    width: 70px;
    line-height: 143px;
}

.toLeft img, .toRight img{
    cursor: pointer;
}

.toLeft{
    text-align: right;
    padding-right: 10px;
}

.toRight{
    text-align: left;
    padding-left: 10px;
}

/* 要控制的面板 */
.box{
    width: 1022px;
}

.ul{
    display: -webkit-box;
    color: white;   
    padding: 30px 0 0; 
    overflow: auto;
}

.ul-content{
    display: flex;
}

.point{
    width: 103px;
}

.curPoint{
    font-size: 12px;
    color: #FF9702FF;
    font-weight: bold;
    visibility: hidden;
}

.marker-out{
    width: 22px;
    height: 22px;
    background: #1358B3;
    border-radius: 50%;
    padding: 4px;
    margin: 0 auto;
    position: relative;
    cursor: pointer;
}

.marker-in{
    width: 14px;
    height: 14px;
    background: #35FFF5;
    box-shadow: 2px 1px 8px 0px rgba(9, 53, 117, 0.71);
    border-radius: 50%;
}

/* 節點左邊的線段 */
.marker-out:before{
    height: 0;
    width: 81px;
    border-top: 3px dashed #0B4A8A;
    position: absolute;
    left: -81px;
    top: 50%;
    content: "";
    pointer-events: none;
}

.label{
    margin: 0 auto;
    margin-top: 14px;
    width: 86px;
    height: 26px;
    line-height: 26px;
    font-size: 12px;
    background: url('../../static/img/pane.png') no-repeat;
    background-size:100% 100%; 
    opacity: 0.9;   
    position: relative; 
    cursor: pointer;
    overflow: hidden;
    text-overflow:ellipsis; 
    white-space: nowrap;
    padding: 0 5px;
}

/* 原本是用偽類做標籤左上角和右下角的形狀的,但是左上角的梯形實現起來有點麻煩,最後用了切圖(感謝美工大哥) */
/* .label:before{
    width: 3px;
    height: 6px;
    background: #00A3FF;
    position: absolute;
    left: -1px;
    top: -1px;
    content: "";
}
.label:after{
    width: 0;
    height: 0;
    border: solid transparent;
    border-width: 3px 4px;
    border-right-color: #00A3FF;
    border-bottom-color: #00A3FF;
    position: absolute;
    right: -1px;
    bottom: -1px;
    content: "";
} */

/* 當前活動狀態的節點,圓圈替換成攝像頭gif */
.active .marker-out {
    background: url('../../static/img/icon_video.gif') no-repeat;
    background-position: center; 
}
.active .marker-in {
    display: none;
}
/* 當前節點顯示下箭頭指向標籤 */
.active .marker-out:after{
    width: 0;
    height: 0;
    border: solid transparent;
    border-width: 7px 6px;
    border-top-color: #FF9702; 
    position: absolute;
    bottom: -19px;
    left: 5px;
    content: "";
}
.active .label{
    color: #FF9702FF;
    background: url('../../static/img/pane_active.png') no-repeat;
    background-size:100% 100%;     
}
/* 當前節點上方顯示名稱 */
.active .curPoint{
    visibility: visible;
}
/* 當前節點改變左邊線段樣式 */
.active .marker-out:before, .over .marker-out:before{
    border-top: 2px solid #369EFF;
    border-bottom: 2px solid #369EFF;
}

/* 已經過的節點 */
.over .marker-in{
    background: #359EFF;
    box-shadow: 2px 1px 8px 0px rgba(9, 53, 117, 0.71);   
}

/* 節點少時均勻分佈 */
.flex{
    display: flex;
    flex-direction: row;
}
.flex .point{
    flex: 1;
}
.flex .ul-content{
    width: 100%;
}

/* 節點少時或滾動到最左/最右側時隱藏箭頭 */
.hide{
    visibility: hidden;
    pointer-events: none;
}
.ul::-webkit-scrollbar {
    height: 0;     
}

/* 隱藏第一個節點左側的線段 */
.first:before{
    display: none;
}