美文网首页
vue项目处理列表数据的方法归纳

vue项目处理列表数据的方法归纳

作者: 我才是大田田 | 来源:发表于2018-08-23 15:55 被阅读0次

    项目中遇到了3个列表,它们的要求各不同,将它们的处理方法总结一下

    1、互斥列表

    场景:列表只能展开某一项,点击另一项的时候,前一项折叠,点击的该项展开。

    <template>
    <div v-if="arr.length > 0">
          <div v-for="(item, index) in arr" :key="index">
                  <div class="limits_txt"  @click="showInfo(index)">
                       <div class="txt">{{item.scope_detail.title}}</div>
                          <div class="lable">
                            <van-icon :class="{arrowU: select&&(activeIndex === index), arrowD: !select&&(activeIndex === index)}" name="arrow"></van-icon>
                          </div>
                  </div>
                  <div class="genre_type"  :class="{active: select&&(activeIndex === index)}">
                          // 展示item内容
                  </div>
          </div>
    </div>
    </template>
    
    <script>
    
    export default {
        data() {
            return {
                select: false,
                activeIndex:''
            };
        },
        methods: {
            showInfo(index) {
                  if(index!==this.activeIndex) {
                        this.activeIndex = index  
                        this.select = true
                  } else {
                      this.select = !this.select
                  }
              }
         }
    }
    </script>
    

    解释:全局变量activeIndex用来保存上一次点击的index,布尔值select表示该显示还是隐藏

    每次点击时,将本次的index和activeIndex做比较,如果点击的是同一个,则直接把布尔类型的select变量反转;如果点击的不是同一个,就将当前点击的index保存再activeIndex里,再将select置为true。

    页面中:class="{active: select&&(activeIndex === index)}"动态绑定class,一定要加activeIndex === index这个判断,否则就不是一个item被影响了,item全会跟着动。

    2、非互斥列表

    场景:列表的所有项都能同时展开

    // script
    this.reviewList.forEach((item,index) => {
         this.$set(item,'show',false)
    })
    

    解释:在列表的每一项中新增一个show字段,判断该项是显示还是隐藏。

    3、从页面角度是一组唯一的数据,但是拿到的数据不在一个列表里。

    场景:页面有n个仿微信的短音频,音频播放时有动画,也算是互斥的,页面上只能有一个动画。

    // 数据结构长这样
    "arr": [{
              "submit_item": { 
                    // 一级内容
                   "status": 20,
                   "type": 2,
                   "audio":  {
                        "url": "xx_url",
                        "length": 12 // 音频长度,单位秒
                   }
              },
              "comment_items": [
                   // 二级内容
                  {
                  // 二级内容1
                  "type": 2,
                  "audio":  {
                      "url": "xx_url",
                      "length":60 // 音频长度,单位秒
                  }
              },
              {
                  // 二级内容2
                 "type": 2,
                  "audio":  {
                      "url": "xx_url",
                      "length":60 // 音频长度,单位秒
                  }
              },
              {
                  // 二级内容3
                 "type": 2,
                  "audio":  {
                      "url": "xx_url",
                      "length":60 // 音频长度,单位秒
                  }
              }]
        }
    
    

    返回的arr是一个数组,arr的每个item里又包含一个对象(submit_item)和一个数组(comment_items),item里的数组(comment_items)里又有一个对象,这里面的对象结构和item里的submit_item结构一致,都有音频信息。

    <template>
    <div class="review-card" v-for="(item, index) in reviewList" :key="index">
         <div class="homework">
                        <img v-if="item.submit_item.type === 1" :src="item.submit_item.image.url">
                        <div v-if="item.submit_item.type === 2" class="comment-voice" :style="{width: setAudioWidth(item.submit_item.audio.length)}" @click="playAudio(item.submit_item.audio.url,'homework',index,'',item)">
                            <span class="comment-voice__audio" :class="{play:isplaying && activeIndex === (index +'#'), played: item.submit_item.audio.played && !(isplaying && activeIndex === (index +'#'))}"></span>
                            <span class="comment-voice__length">{{item.submit_item.audio.length}}"</span>
                        </div>
                        <div v-if="item.submit_item.type === 3" class="comment-text">{{item.submit_item.text}}</div>
         </div>
         <div class="teacheer-comment">
             <div class="comment-content" :class="{active: item.show}"  v-for="(it, idx) in item.comment_items" :key="idx">
                  <div class="comment-voice" :style="{width: setAudioWidth(it.audio.length)}" @click="playAudio(it.audio.url,'comment',index,idx,item,it)">
                         <span class="comment-voice__audio" :class="{play:isplaying && activeIndex === (index+'#'+idx), played: it.audio.played && !(isplaying && activeIndex === (index +'#'+idx))}"></span>
                         <span class="comment-voice__length">{{it.audio.length}}"</span>
                  </div>         
             </div>
         </div>
    </div>
    <audio src="http://oya7y0n8c.bkt.clouddn.com/sound.mp3" ref="audio" @ended="over"></audio>
    </template>
    
    <script>
    methods:{
      playAudio(url,type,index,idx,item,it){
                // 点击的音频是否是上一次点击那个,如果是,则切换暂停播放;如果不是上一个,那就把上个音频结束,播放现在点击的这个
        if(type === 'homework') {
             this.$set(item.submit_item.audio,'played',true) 
             if(this.activeIndex ===index +'#') {
                 this.isplaying = !this.isplaying
             } else {
                 this.isplaying = false
                 this.activeIndex = index +'#'
                 this.isplaying = true
             }
        } else {
            this.$set(it.audio,'played',true)
            if(this.activeIndex ===index +'#' + idx) {
                this.isplaying = !this.isplaying
            } else {
                this.isplaying = false
                this.activeIndex = index +'#' + idx
                this.isplaying = true
           }
        }
        // this.$refs.audio.src = url
        // 测试用音频
        this.$refs.audio.src = 'http://oya7y0n8c.bkt.clouddn.com/sound.mp3'
        this.isplaying?this.$refs.audio.play():this.$refs.audio.pause()
      }
    }
    </script>
    <style>
    .comment-voice{
           margin: 30px 0;
           height: 80px;
           line-height: 80px;
           background-color: #f5f5f5;
           position: relative;
           overflow: hidden;
           &__audio {
                display: inline-block;
                position: absolute;
                top: 23px;
                left: 24px;
                width: 26px;
                height: 34px;
                background: url(~/assets/img/audioPlay.png) no-repeat 0 0;
                background-position:-54px;
                background-size: 78px 34px;
                // animation:audio_playing 1s steps(1) infinite;
            }
            &__audio.played {
                background: url(~/assets/img/audioStatic.png) no-repeat 0 0;
                background-size: 26px 34px;
             }
             &__audio.play {
                animation:audio_playing 1s steps(1) infinite;    
             }
             @keyframes audio_playing {
                 0% {
                        background-position: 4px;
                 }
                 33% {
                        background-position: -22px;
                 }
                66% {
                       background-position: -54px;
                }
                100% {
                       background-position: 0px;
                }
            }
    }
    </style>
    

    解决办法:
    因为也是互斥的动画,所以沿用方法1的思路,设置全局变量activeIndex来保存上次点击的index。但是这些音频不在一个数组里,我的解决办法是强行编码,新造一个index:把一级内容的index和二级内容的index拼起来,中间用#隔开。

    这样每次点击的时候做判断,是一级内容还是二级内容,然后再拼接index,判断activeIndex,这样就可以保证互斥点击效果。

    题外话:发现vue的数据操控视图真的非常方便,仿微信的语音播放动画一共有3个状态:未播放、播放中、播放过。分别对应红色,红色扩音器动画、灰色扩音器。默认是未播放状态,然后用play和played分别绑定播放中和播放过的状态。

    :class="{play:isplaying && activeIndex === (index+'#'+idx), played: it.audio.played && !(isplaying && activeIndex === (index +'#'+idx))}"
    

    相关文章

      网友评论

          本文标题:vue项目处理列表数据的方法归纳

          本文链接:https://www.haomeiwen.com/subject/aagpiftx.html