vue做一个tabbar,进行切换问题

现在需要一个和底部tabbar的东西一模一样的,要求就是点击某个,它的图片和背景色改为选中的样式,其它的便会默认样式。
图片描述
现在我已经做了出来,可以实现这样的功能,但是实现的过程实在是不堪入目。下面上代码

HTML

<div class="optioncardbox">
      <div class="optioncard optioncardtext" @click="changetype(0)">
        <p :class="[is0?a:b]">ALL</p>
        <p class="optioncardtip">全部</p>
      </div>
      <div class="optioncard optioncardlist">
        <img :src="[is1?e:f]" alt="" srcset="" :class="[is1?d:c]" @click="changetype(1)">
        <p class="optioncardtip">营养</p>
      </div>
      <div class="optioncard optioncardlist">
        <img :src="[is2?g:h]" alt="" srcset="" :class="[is2?d:c]" @click="changetype(2)">
        <p class="optioncardtip">运动</p>
      </div>
      <div class="optioncard optioncardlist">
        <img :src="[is3?i:j]" alt="" srcset="" :class="[is3?d:c]" @click="changetype(3)">
        <p class="optioncardtip">睡眠</p>
      </div>
      <div class="optioncard optioncardlist">
        <img :src="[is4?k:l]" alt="" srcset="" :class="[is4?d:c]" @click="changetype(4)">
        <p class="optioncardtip">情绪</p>
      </div>
      <div class="optioncard optioncardlist">
        <img :src="[is5?m:n]" alt="" srcset="" :class="[is5?d:c]" @click="changetype(5)">
        <p class="optioncardtip">内分泌</p>
      </div>
    </div>

JavaScript

export default {
    data() {
      return {
        is0: true,
        is1: false,
        is2: false,
        is3: false,
        is4: false,
        is5: false,
        istip0: true,
        istip1: false,
        istip2: false,
        goodsinfo: [],
        targetid: 0,
        a: 'optioncardfirst',
        b: 'notoptioncardfirst',
        c: 'optioncardimg',
        d: 'notoptioncardimg',
        e: '../../../static/image/icon16-y.png',
        f: '../../../static/image/icon16.png',
        g: '../../../static/image/icon17-y.png',
        h: '../../../static/image/icon17.png',
        i: '../../../static/image/icon18-y.png',
        j: '../../../static/image/icon18.png',
        k: '../../../static/image/icon19-y.png',
        l: '../../../static/image/icon19.png',
        m: '../../../static/image/icon20-y.png',
        n: '../../../static/image/icon20.png',
        o: 'islessonlistoptioncard',
        p: 'lessonlistoptioncard',
      }
    },
    
    methods: {
      changetype(x) {
        if (x == 0) {
          this.is0 = true
          this.is1 = false
          this.is2 = false
          this.is3 = false
          this.is4 = false
          this.is5 = false
          this.targetid = 0
          this.getLessonlist(0)
          this.istip0 = true
          this.istip1 = false
          this.istip2 = false
        } else if (x == 1) {
          this.is1 = true
          this.is0 = false
          this.is2 = false
          this.is3 = false
          this.is4 = false
          this.is5 = false
          this.targetid = 16
          this.getLessonlist(0)
          this.istip0 = true
          this.istip1 = false
          this.istip2 = false
        } else if (x == 2) {
          this.istip0 = true
          this.istip1 = false
          this.istip2 = false
          this.is2 = true
          this.is0 = false
          this.is1 = false
          this.is3 = false
          this.is4 = false
          this.is5 = false
          this.targetid = 17
          this.getLessonlist(0)
        } else if (x == 3) {
          this.istip0 = true
          this.istip1 = false
          this.istip2 = false
          this.is3 = true
          this.is0 = false
          this.is2 = false
          this.is1 = false
          this.is4 = false
          this.is5 = false
          this.targetid = 18
          this.getLessonlist(0)
        } else if (x == 4) {
          this.istip0 = true
          this.istip1 = false
          this.istip2 = false
          this.is4 = true
          this.is0 = false
          this.is2 = false
          this.is3 = false
          this.is1 = false
          this.is5 = false
          this.targetid = 19
          this.getLessonlist(0)
        } else if (x == 5) {
          this.istip0 = true
          this.istip1 = false
          this.istip2 = false
          this.is5 = true
          this.is0 = false
          this.is2 = false
          this.is3 = false
          this.is4 = false
          this.is1 = false
          this.targetid = 20
          this.getLessonlist(0)
        }
      },

这个是部分代码,其中有些无关紧要。现在的基本思路就是加载2套不同样式和src,然后每次点击之后判定进行切换,选中的进行加载,其它的返回默认值。但是这样的代码实在繁琐,感觉程序员不应该写出这样的代码,说起来真挺丢人的,谁有很好的思路可以提供一下。非常感谢。

阅读 6.8k
5 个回答

代码大概是这样的

<script src="https://libs.cdnjs.net/vue/2.3.0/vue.min.js"></script>
<script src="https://libs.cdnjs.net/jquery/1.12.4/jquery.min.js"></script>
<style>
.b{background-color:black;}
.a{background-color:red;}
.optioncardbox{width:50px;}
.hide{display:none;}
</style>
<p style="line-height: 18px; font-size: 18px;  font-family: times;">
    <div id='tbar'  class="optioncardbox">
      <div v-for='(btn,key) in btns' class="optioncard optioncardtext"  @click="changetype(key)">      
        <p :class="{'hide':!(!btn.src1&&btn.selected)}" class="a">{{btn.text}}</p>
        <p :class="{'hide':!(!btn.src1&&!btn.selected)}" class="b">{{btn.text}}</p>
        <img :class="{'hide':!(btn.src1&&btn.selected)}" :src="btn.src1" alt="1"/>
        <img :class="{'hide':!(btn.src1&&!btn.selected)}" :src="btn.src2" alt="2"/>
        <p class="optioncardtip">{{btn.tip}}</p>
      </div>
</div> 
</p>
<script>
$(function(){
var app=new Vue({
    el:'#tbar',
    data: {
      btns:[
      {selected:true,text:'All',tip:'全部'},
       {selected:false,src1:'./pic1.png',src2:'./pic2.png',tip:'营养'},
       {selected:false,src1:'./pic1.png',src2:'./pic2.png',tip:'运动'},
       {selected:false,src1:'./pic1.png',src2:'./pic2.png',tip:'睡眠'},
       {selected:false,src1:'./pic1.png',src2:'./pic2.png',tip:'情绪'},
       {selected:false,src1:'./pic1.png',src2:'./pic2.png',tip:'内分泌'}
      ]
      },
   methods: {
        changetype:function(key) { 
        this.btns.forEach(function(e){e.selected=false});
         this.btns[key].selected=true;
       }
       }
  });
});

</script>

一点心得:
1,资源类的东内容最好放在网页模板里面而不是放在代码中,这样看起来比较方便;
2,重复性的东西一定要放在循环里面;
2.5,能完全一致就不要特殊化(都用一样的标签,而不是p和img混用);
3,如果没有外部的资源预加载(主要是图片),尽量用css控制显示隐藏而不用v-if进行渲染控制;

先给你个demo,之后给你说到说到想法。

<div id="app">
  <ul>
    <li v-for="(item,index) in tabbar.list" :class="{selected: index == tabbar.index}" @click="tabbar.index = index">{{index === tabbar.index?item.img_h:item.img}}</li>
  </ul>
</div>
new Vue({
  el: '#app',
  data: {
    tabbar: {
      list: [
        {name: 'ALL',img: '1.jpg',img_h: '1_h.jpg'},
        {name: 'ALL',img: '1.jpg',img_h: '1_h.jpg'},
        {name: 'ALL',img: '1.jpg',img_h: '1_h.jpg'},
        {name: 'ALL',img: '1.jpg',img_h: '1_h.jpg'}
      ],
      index: 0
    }
  }
})

你这个看上去是一样的,为什么不考虑用循环呢?
既然都用了0123来表示为什么不用一个统一变量呢?
如果高亮和不高亮的命名有规律,那么可以判断选中直接拼接呀? tabbar.index == index ? '_h':''

我实现的办法是利用索引。
写一个记录索引的字段,点击的时候改变那个字段的值,与当前点击的索引进行匹配,相等则添加class。
大概是下面这样

<nav class="st-top-category">
    <span class="st-item" :class="{cur:curcate === index}" v-for="(cat,index) in categoryList" :key="index" v-on:click="changecate(index,cat.type,cat.value)">{{cat.label}}</span>
</nav>


data () {
    return {
      curcate: 0,
      categoryList: []
    }
  },
methods:{
    changecate(index,type,value){
      this.curcate = index;
    }
}

其他几个人的答案基本的已经很完备了,我这边补充一个小东西,对于这种navtab,一般点击的tab更改状态,其他没点击的恢复原态,其实不用每次更改的时候都一个个去改变,你只用记录上一次点击的是哪个tab,在本次点击的时候判断是跟上次点击的是同一个还是不同个,同一个的话 就不用做任何更改,非同一个的话,更改状态即可,这样的话,性能上面更好。

https://codepen.io/kingdil/pe...

1.tabbar图片和文字一一对应,首先考虑到的肯定是循环数据格式应该如下

   tabs:[
                    {
                        title:'全部',
                        ico:'http://thyrsi.com/t6/367/1536299620x-1404781180.png',
                        icon:'http://thyrsi.com/t6/367/1536299648x-1404781180.png',
                    },
                    {
                        title:'营养',
                        ico:'http://thyrsi.com/t6/367/1536299680x-1404781180.png',
                        icon:'http://thyrsi.com/t6/367/1536299701x-1404781180.png',

                    },
                    {
                        title:'运动',
                        ico:'http://thyrsi.com/t6/367/1536299735x-1404781180.png',
                        icon:'http://thyrsi.com/t6/367/1536299715x-1404781180.png',
                    }
                ] 

2.选中后图片变化,文字变色,设选中的索引值为curIdx,当选中索引值等于tabbar索引值时便是该tabbar被选中。添加选中后的class,改变选中后的图标

 <ul class="tabs">
            <li :class="{'cur':curIdx==index}" v-for="(item,index) in tabs"  @click="selectTabs(index)">
               <div class="tab_ico">
                   <img :src="curIdx==index?item.icon:item.ico" alt="">
               </div>
                <div class="tab_title">
                    <span v-text="item.title"></span>
                </div>
            </li>
        </ul>

3.绑定点击事件,传索引值,点击哪个tabbar的时候curIdx就等于改索引值

  selectTabs:function(index){
                    this.curIdx=index;

                },
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题