vue+vuex实现滑动块导航栏+优化window.onresize的方案网址推荐

海星吧 2019-9-18 4602


听歌敲代码。没想到吧,这个是jojo哒。


今天想到有些网页上会有那种滑动块导航栏,我还从来没做过这个,就从网上找了一个看看。

图1.jpg

它的效果是这样的。但是我后来发现了个很严重的问题。


图s3.jpg

如果我不点击上面的li标签,直接把我的浏览器窗口缩放的话,他的left值是不会改变的,也就是说这个滑动块的位置在看起来会飘到别的地方。

这样的效果如果是手机的话还能接受,毕竟手机的话应该是不会缩放浏览器的,但是这东西放到pc网站上会被人笑死。


怎么办,快用你无敌的空条承太郎想想办法啊,白金之星!


我看了一下他里面的代码(这个是在html上写的,所以是用挂载的方式。)

<div id="app">

<div id="menu">

            <ul>

                <li v-for="(item,index) in menulist" @click="movebg(item,index)">

                    {{item.title}}

                </li>

                <div class="menubg"></div>

            </ul>

        </div>

</div>

<style>

html,

    body,

    ul,

    li {

        padding: 0;

        margin: 0;

        list-style: none

    }


    #menu {

        width: 80%;

        background: #024067;

        box-shadow: 0 2px 3px rgba(0, 0, 0, .2);

        padding: 0 10%;

    }


    #menu ul {

        display: flex;

        position: relative

    }


    #menu ul li {

        flex: 1;

        line-height: 40px;

        color: #fff;

        font-size: 14px;

        cursor: pointer;

        text-align: center;

        position: relative;

        z-index: 2

    }


    .menubg {

        position: absolute;

        background: #8f0000;

        height: 40px;

        top: 0;

        z-index: 1;

        transition: all .4s;

        left: 0

    }

</style>



var app = new Vue({

        el: '#app',

        data: {

            menulist: [{title: 'UI',value: 1

            }, {title: '输入', value: 2}, {title: '媒体',value: 3

            }, {title: '导航',value: 4}, {title: '其他',value: 5

            }, {title: '网页模板',value: 6}, { title: '常用代码',value: 7  }]

        },

        mounted() {

            let menuwidth = document.querySelector("#menu ul").offsetWidth//获取menu宽度

            let liwidth = document.querySelectorAll("#menu li")//获取li

            let bgWidth = document.querySelector(".menubg")//背景

            bgWidth.style.width = liwidth[0].offsetWidth + 'px' //设置menubg的宽度 

        },

        methods: {

            movebg(item, index) {

                let bgWidth = document.querySelector(".menubg")

                let selfLeft = document.querySelectorAll("#menu li")[index].offsetLeft

                bgWidth.style.left = selfLeft + 'px'  //设置menubg的left

                this.id = item.value

            }

        }

    })


看好了,他是选择('#menu li') 后面还用了index,这个index是从哪里来的?

是他点击事件里传过来的。如果不点它,那么就没有index这个东西,console.log打印就会为undefined。

而且他设置滑动块 宽度的代码是写死的,无论我们怎么点,他的滑动块宽度始终都是一样的,除非刷新页面。

所以我们还得动态改变他的宽度。

⑧说了,上代码。


首先我们得使用vuex来管理index的问题。这里如果没有学过vuex的可以先看下去再去学vuex。)

先在

360截图20190918175216655.jpg


mutation-types.js文件下写上代理的方法名:

export const SETMENULIINDEX = "SETMENULIINDEX"

然后在mutation文件下引入,最后写上我们要使用的方法。

import {SETMENULIINDEX} from './mutation-types'


[SETMENULIINDEX]:(state,number)=>{//存入滑动块导航栏的index的方法。

    state.menuLiIndex = number

  },

这样我们的vuex就写好了,然后就在vue文件里用它。


在vue文件的script标签下引入vuex中的mapMutation

import {mapMutations} from 'vuex'


最后就是我们的逻辑代码了

mounted() { 

     this.movebg()

     const _that = this;

     window.onresize = function(){//这里我们使用window.onresize监听浏览器窗口宽度。

       _that.movebg()

     };

   },


    methods: {

      ...mapMutations([]), //在这里引入映射方法,别忘了‘,’号

          movebg(item, index) {

            if(index==null||index == undefined){//判断index是否为空

              index = 0;

              item = this.menulist[0];

            }else{

              this.$store.commit('SETMENULIINDEX',index)

                //如果index不为空,把它存入vuex

            }

            var bgWidth = document.querySelector('.menubg')

            var aLi = document.querySelectorAll('#menu li ')

            var liWidth = aLi[index].offsetWidth //获取点击的li标签的宽

            bgWidth.style.width = liWidth + 'px';

            bgWidth.style.left = liWidth * this.$store.state.menuLiIndex + 'px'

             //这里我们让他乘以的是存放在vuex里面的index,这样就不会跟个二愣子一样傻站在原地了。

          }

    }


然后我们可以用computed来返回一下这个menuLiIndex的数值

computed: {

    menuLiIndex() {

      return this.$store.state.menuLiIndex

    }

  },


这样写就能用模板看到了。{{menuLiIndex}}


让我们看一下效果图


我们可以从右侧的数据看到,他的width和left的值已经可以根据可视窗口的改变而动态改变了。

而且我们不点击他,他也会自己根据窗口宽度改变。

就此我们的目的已经达到了。


当然这个方法还是有点问题的。

首先是他的index的问题其实是没有解决的,我虽然在上面设置了一个判断语句,

但是他的index如果没有点击的话,其实还是为undefined,我们用的是之前点击所存入在vuex中的index。

其次,window.onresize这个方法在vue中,如果定义了很多个,那么也只会有一个生效。

而且会让网页很卡很卡,现在我的浏览器的cpu就飙升到35%了

cpu.jpg


所以这是个需要优化的地方。

目前已经找到了优化方案,不过还没整理,如果有想挑战一下的可以试试。

优化方案网站:https://www.jb51.net/article/135427.htm


感觉我说的应该比较详细了吧,当然有问题还是可以下方留言。我看到了就会回答你的。

(别只打字,附上图,没有医生能够只看病人脸色就知道是啥病的。)


Welcome to  Starfish bar,If you have better suggestions or better ideas,

Thank you forleave a message below, see you again.


弱鸡程序员年底还在加班
最新回复 (4)
  • 欧派兽 2019-9-18
    0 2
    奖励三级精华
    1:管理员给你移区后会显示移到了你之前发帖的区。 2:点击我作为楼主发帖时一楼下的图片签名,可以跳转到站规教程贴。 3:多次水贴水回复会封号哦? 4:不知道回什么的时候就点“里世界专属”,一键随机生成几种回复内容。 5:祝你在里世界玩得愉快!
  • 海星吧 2019-9-18
    0 3
    欧派兽 奖励三级精华
    阿利亚多
    弱鸡程序员年底还在加班
  • 天竟自由 2019-10-29
    0 4
    海星吧 阿利亚多
    是阿里嘎多
    明天一起去吃烤肉吧!!!各位
  • 海星吧 2019-10-30
    0 5
    最近用我自己的demo的时候老是报一个错误,

    offsetWidth is undefined ,
    后来感觉应该是需要关掉这个事件,不然在别的组件里也会触发window事件。

    beforeDestroy() {
          window.onresize = null;
          console.log("组件销毁前把window.onresize事件设置为空。")
        }
    弱鸡程序员年底还在加班
    • ACG里世界
      6
          
返回
发新帖