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

2018-08-23  本文已影响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))}"
上一篇下一篇

猜你喜欢

热点阅读