前端实战小案例--fullpage导航栏实现

前端实战小案例--fullpage导航栏实现

想练习更多前端案例,请进个人主页,点击前端实战案例->传送门

觉得不错的记得点个赞?支持一下我0.0!谢谢了!

不积跬步无以至千里,不积小流无以成江海。

技术栈:vue + vue-fullpage

效果图如下:( 这是一个vue组件)

 

 

代码如下:

Fullpage.vue

<template>
    <div class="content">
        <!--导航菜单-->
        <navigation :cur-index="curIndex" @select="selectItem"></navigation>
        <!--右侧小导航菜单-->
        <div id="menu" :class="playingStateCls">
            <span class="active" data-menuanchor='/page1'><a href="#/page1"></a></span>
            <span data-menuanchor='/page2'><a href="#/page2"></a></span>
            <span data-menuanchor='/page3'><a href="#/page3"></a></span>
            <span data-menuanchor='/page4'><a href="#/page4"></a></span>
            <span data-menuanchor='/page5'><a href="#/page5"></a></span>
            <span data-menuanchor='/page6'><a href="#/page6"></a></span>
            <div class="play-btn" @click.stop="togglePlay" >
                <i class="iconfont icon-play" v-show="!playingState"></i>
                <i class="iconfont icon-pause" v-show="playingState"></i>
            </div>
            <audio loop ref="audio" src="../../assets/audio/wuyuetian.mp3"></audio>
        </div>
        <full-page :options="options" ref="fullpage">
            <div class="section">
                <home></home>
            </div>
            <div class="section">
                <about-me></about-me>
            </div>
            <div class="section">
                <div class="box3">
                    section3
                </div>
            </div>
            <div class="section">
                <div class="box4">
                    section4
                </div>
            </div>
            <div class="section">
                <div class="box5">
                    section5
                </div>
            </div>
            <div class="section">
                <div class="box6">
                    section6
                </div>
            </div>
        </full-page>
    </div>
</template>
<script>
  import Home from "./Home/Home";
  import Navigation from "../Navigation/Navigation";
  import AboutMe from "./AboutMe/AboutMe";

  export default {
    name: "Fullpage",
    data () {
      return {
        curIndex: 1,
        playingState: false,
        options: {
          scrollOverflow: true,
          scrollBar: false,
          navigation: true,
          anchors: ['/page1', '/page2', '/page3','/page4', '/page5', '/page6'],
          menu: '#menu',
          sectionsColor: ['#41b883', '#F3F2F3', '#0798ec', '#fec401', '#1bcee6', '#925B4B']
        }
      }
    },
    methods: {
      selectItem(index){
        // 当在大导航菜单选择某项时,让fullpage滚动到对应的page
        this.curIndex = index
        this.$refs.fullpage.api.moveTo(index)
      },
      togglePlay(){
        // 切换歌曲播放状态
        if(!this.playingState){
          this.$refs.audio.play()
        }else{
          this.$refs.audio.pause()
        }
        this.playingState = !this.playingState
      },
      refreshPath(){
        // 在页面刷新的时候,判断当前路径,并刷新 this.curIndex 的值
        let path = this.$route.path
        let index
        if(path === '/'){
          index = 0
        }else{
          index = this.options.anchors.findIndex((item) => {
            return item === path
          })
        }
        this.curIndex = index + 1
      }
    },
    computed: {
      playingStateCls(){
        // 播放状态不同决定了音乐的背景图片是否处于旋转状态
        if(this.playingState){
          return 'running'
        }else{
          return 'paused'
        }
      }
    },
    watch: {
      $route(newVal){
        // 这个只有在页面路由变化时才触发,页面刷新时不触发,所以需要为页面刷新写一个处理函数  refreshPath()
        // 路由变化时,也即滚动fullpage页面时,让大导航菜单跟着刷新到对应的导航菜单项
        // 至于为什么要这样处理,主要是fullpage的事件回调函数有bug
        let index = this.options.anchors.findIndex((item) => {
          return item === newVal.path
        })
        this.curIndex = index + 1
      }
    },
    created() {
        this.refreshPath()
    },
    components: {
      Home,
      Navigation,
      AboutMe
    }
  }
</script>

<style lang="less" scoped>
    @keyframes breath {
        0%{
            box-shadow: 0 0 0 0 rgba(37, 143, 184, 1);
            background: #fff;
        }
        100%{
            box-shadow: 0 0 0 10px rgba(37, 143, 184, 0.1);
            background: #dddedc;
        }
    }
    @keyframes imgRotate {
        0%{
            transform: rotateZ(0);
        }
        100%{
            transform: rotateZ(360deg);
        }
    }
    
    .content{
        #menu{
            position: fixed;
            top: 50%;
            right: 3%;
            transform: translateY(-50%);
            z-index: 99;
            &.running{
                &::after{
                    animation-play-state: running;
                }
            }
            &.paused{
                &::after{
                    animation-play-state: paused;
                }
            }
            &::after{
                position: absolute;
                bottom: -40px;
                right: -13px;
                width: 40px;
                height: 40px;
                background: url("../../assets/images/music.jpg") no-repeat;
                background-size: contain;
                border-radius: 50%;
                transition: background 0.3s ease-in;
                content: '';
                animation: imgRotate 6s infinite linear;
            }
            &::before{
                position: absolute;
                top: 24px;
                left: 0;
                width: 6px;
                height: 230px;
                display: block;
                border-right: 1px dashed #8c7576;
                content: '';
            }
            span{
                display: block;
                position: relative;
                width: 14px;
                height: 14px;
                border-radius: 50%;
                background: #dddedc;
                margin: 24px auto!important;
                cursor: pointer;
                z-index: 999;
                &.active{
                    background: #fff;
                    animation: breath 2s infinite;
                }
                &::before{
                    width: 6px;
                    height: 6px;
                    content: '';
                    border-radius: 50%;
                    background: @color-blue;
                    display: block;
                    position: absolute;
                    left: 50%;
                    margin-left: -3px;
                    top: 50%;
                    margin-top: -3px;
                }
                a{
                    position: relative;
                    display: block;
                    width: 100%;
                    height: 100%;
                    z-index: 1000;
                }
            }
            .play-btn{
                position: absolute;
                bottom: -40px;
                right: -13px;
                width: 40px;
                height: 40px;
                z-index: 100;
                background: transparent;
                border-radius: 50%;
                cursor: pointer;
                .iconfont{
                    width: 40px;
                    height: 40px;
                    font-size: 28px;
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    border-radius: 50%;
                    opacity: 0;
                    &:hover{
                        opacity: 1;
                        background: rgba(255,255,255,0.5);
                    }
                }
            }
        }
    }
</style>

Navigation.vue

<template>
    <div class="box">
        <div class="nav-wrapper">
            <div class="nav-toggle" @click="toggleNav" :class="visitedCls">
                <div class="icon"></div>
            </div>
            <div class="nav-text">导航</div>
        </div>
        <transition name="slide">
            <div class="nav-menu-wrapper" v-show="showFlag" ref="NavMenuWrapper">
                <div class="nav-menu">
                    <ul class="items">
                        <li class="item" :key="item.id" v-for="item in menuList">
                            <a href="javascript:;" :class="{'actived' : item.id === curIndex}" @click="selectItem(item.id)" >{{item.name}}<span class="line"></span></a>
                        </li>
                    </ul>
                    <div class="logo">
                        <img src="../../assets/images/logo.png" alt="">
                        <span class="text">朽木</span>
                        <div class="wrapper">
                            <span class="site-url">xmzd.wang</span>
                            <span class="qq">QQ:1061750360</span>
                        </div>
                        <span class="text">自雕</span>
                    </div>
                </div>
            </div>
        </transition>
    </div>
</template>

<script>
  export default {
    name: "Navgation",
    data(){
      return {
        showFlag: false
      }
    },
    props: {
      curIndex: {
        type: Number,
        default: 1
      },
      menuList: {
        type: Array,
        default: () => [
          {id:1, name: "首页"},
          {id:2, name: "关于我"},
          {id:3, name: "技能掌握"},
          {id:4, name: "我的经历"},
          {id:5, name: "我的作品"},
          {id:6, name: "联系我"},
        ]
      }
    },
    methods: {
      toggleNav(){
        this.showFlag = !this.showFlag
        if(this.showFlag){
          this._disabledMouseWheel(this.$refs.NavMenuWrapper)
        }
      },
      selectItem(id){
        // 当某项被选中的时候,将当前的curIndex改为被选择的id,然后向父组件派发事件,并告诉哪一项被选择了,然后让父组件跳转到fullpage的第几页
        this.$emit("select", id)
        this.toggleNav()
      },
      _scrollFunc(evt) {
        evt = evt || window.event;
        if(evt.preventDefault) {
          // Firefox
          evt.preventDefault();
          evt.stopPropagation();
        } else {
          // IE
          evt.cancelBubble=true;
          evt.returnValue = false;
        }
        return false;
      },
      _disabledMouseWheel(obj) {
        // 禁用某个元素的鼠标滚轮事件
        if (document.addEventListener) {
          obj.addEventListener('DOMMouseScroll', this._scrollFunc, false);
        }//W3C
        obj.onmousewheel  = this._scrollFunc;//IE/Opera/Chrome
      }
    },
    computed: {
      visitedCls(){
        if(this.showFlag){
          return 'visited'
        }else{
          return ''
        }
      }
    }
  }
</script>

<style lang="less" scoped>
    .box{
        .nav-wrapper{
            position: fixed;
            right: 2%;
            top: 4%;
            z-index: 999;
            .nav-toggle{
                width: 60px;
                height: 60px;
                border-radius: 50%;
                background: transparent;
                box-shadow: 0 3px 0 rgba(0,0,0,0.2);
                cursor: pointer;
                transition: all 0.5s ease;
                &:hover{
                    background: @color-blue;
                }
                &:hover+.nav-text{
                    opacity: 1;
                }
                .icon{
                    position: absolute;
                    top: 28px;
                    left: 15px;
                    width: 30px;
                    height: 4px;
                    background-color: white;
                    border-radius: 2px;
                    transition: all 0.5s ease;
                    &::before{
                        content: '';
                        position: absolute;
                        top: -10px;
                        width: 30px;
                        height: 4px;
                        background-color: white;
                        border-radius: 2px;
                        transition: all 0.5s ease;
                        transform-origin: left center;
                    }
                    &::after{
                        content: '';
                        position: absolute;
                        top: 10px;
                        width: 30px;
                        height: 4px;
                        background-color: white;
                        border-radius: 2px;
                        transition: all 0.5s ease;
                        transform-origin: left center;
                    }
                }
            }
            .visited{
                background: @color-CCC;
                .icon{
                    width: 0;
                    &::before{
                        transform: translate(3px,-1px) rotateZ(45deg);
                    }
                    &::after{
                        transform: translate(3px,1px) rotateZ(-45deg);
                    }
                }
            }
            .nav-text{
                opacity: 0;
                width: 60px;
                height: 30px;
                background: @color-blue;
                position: absolute;
                top: 73px;
                right: 0;
                -moz-border-radius: 5px;
                -webkit-border-radius: 5px;
                border-radius: 5px;
                text-align: center;
                line-height: 30px;
                color: #fff;
                font-size: 12px;
                transition: all 0.5s ease;
                &::before{
                    content: "";
                    position: absolute;
                    right: 22px;
                    top: -8px;
                    width: 0;
                    height: 0;
                    border-left: 8px solid transparent;
                    border-bottom: 8px solid @color-blue;
                    border-right: 8px solid transparent;
                }
            }
        }
        .nav-menu-wrapper{
            position: fixed;
            top: 0;
            left: 0;
            bottom: 0;
            right: 0;
            background: rgba(0,0,0,0.3);
            z-index: 998;
            box-sizing: border-box;
            &.slide-enter-active,
            &.slide-leave-active{
                transition: all 0.5s ease;
                .nav-menu{
                    transition: all 0.5s ease;
                    .items,
                    .logo{
                        transition: all 0.5s ease;
                    }
                }
            }
            &.slide-enter,
            &.slide-leave-to{
                opacity: 0;
                .nav-menu{
                    right: -18%;
                    .items,
                    .logo{
                        right: -13%;
                    }
                }
            }
            .nav-menu{
                position: absolute;
                right: 0;
                width: 18%;
                border-bottom: @color-grey 100vh solid;
                border-left: transparent 180px solid;
                border-top: none;
                border-right: none;
                .items{
                    position: fixed;
                    top: 50%;
                    right: 1%;
                    transform: translateY(-50%);
                    .item{
                        width: 156px;
                        display: flex;
                        justify-content: flex-end;
                        a{
                            position: relative;
                            display: inline-block;
                            padding: 15% 30px;
                            color: #686967;
                            font-size: 24px;
                            transition: all 0.5s ease;
                            &.actived{
                                color: @color-blue;
                                .line{
                                    width: 100%;
                                }
                            }
                            &:hover{
                                color: @color-blue;
                                .line{
                                    width: 100%;
                                }
                            }
                            .line{
                                position: absolute;
                                top: 50%;
                                left: 0;
                                right: 0;
                                bottom: 0;
                                margin: 0 auto;
                                display: block;
                                width: 0;
                                height: 2px;
                                background: @color-blue;
                                transition: all 0.5s ease;
                            }
                        }
                    }
                }
                .logo{
                    position: fixed;
                    bottom: 5%;
                    right: 5%;
                    display: flex;
                    justify-content: center;
                    img{
                        width: 50px;
                        height: 50px;
                    }
                    .text{
                        font-size: 34px;
                    }
                    .wrapper{
                        display: flex;
                        flex-direction: column;
                        justify-content: center;
                        align-content: center;
                        text-align: center;
                        .site-url{
                        
                        }
                        .qq{
                            font-weight: 600;
                            color: #fff;
                            background: black;
                            padding: 0 5px;
                            border-radius: 4px;
                        }
                    }

                }
            }
        }
    }
</style>

 Home.vue

<template>
    <div class="home">
        <div class="header">
            <p class="title">Hello,I'm Snake</p>
            <p class="motto">Never, never, never, never give up</p>
            <p class="name">我叫王越</p>
            <p class="desc">一块自我雕刻的朽木</p>
            <p class="email"><i class="iconfont icon-email"></i>m17364250251@163.com</p>
        </div>
    </div>
</template>

<script>

  export default {
    name: "Home",
  }
</script>

<style lang="less" scoped>
    /*font-family: Arial, Helvetica, sans-serif;*/
    /*font-family: 'Shadows Into Light', cursive;*/
    .home{
        width: 100%;
        height: 100%;
        background: url("../../../assets/images/background1.jpg") no-repeat;
        background-size: cover;
        display: flex;
        justify-content: center;
        align-items: center;
        .header{
            text-align: center;
            color: #fff;
            .title{
                font-family: 'Bree Serif', 'Arial', 'Helvetica', 'sans-serif', serif;
                font-size: 70px;
                font-weight: 800;
                margin: 20px;
            }
            .motto{
                font-family: 'Bree Serif', 'Arial', 'Helvetica', 'sans-serif', serif;
                font-size: 25px;
                font-weight: 800;
                margin: 20px;
            }
            .name{
                font-size: 20px;
            }
            .desc{
                font-size: 20px;
            }
            .email{
                font-size: 20px;
                
                .iconfont{
                    font-size: 18px;
                    font-weight: 800;
                    margin-right: 10px;
                }
            }
        }
    }
</style>

 

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值