vue+幀動畫 實現 獲獎獎品列表滾動循環展示


實現效果

 

 

 初級方法:

實現原理:

  1. 由於列表的總數是變化的,所以不能用css把動畫寫死,通過定時器移動列表,實現動畫效果
  2. 計算總高度,建一個變量存儲移動距離,兩者之前比較,當移動距離>=總高度 就把移動距離重置為0
  3. 在css中給列表盒子絕對定位,通過移動top值實現動畫

注意事項:由於需要循環滾動,可以把獲取到的數組在復制一份放到列表里,做到無縫銜接

html:

   <div class="inner_box">
        <div class="prize_container">
          <ul
            ref="prizeRef"
            class="prize_ul"
            v-if="info.joinList && info.joinList.length"
          >
            <li
              class="prize_item"
              v-for="(item, index) in info.joinList"
              :key="index"
            >
              <div class="left">{{ item.mobile | mobileFilter }}</div>
              <div class="right">{{ item.name }}</div>
            </li>
          </ul>
        </div>
     </div>

js:

// 獲取活動信息
    getData() {
      this.fetch
        .get("TjModule/GetActivityInfo", {
          activityId: this.id
        })
        .then(res => {
          if (res.data && res.data.success) {
            this.$setTitle(res.data.result.activityName);
            this.info = res.data.result;
            let arr = [];
            if (res.data.result.joinList.length) {
              arr = res.data.result.joinList;
              arr.map(i => {
                arr.push(i);
              });
            }
            this.info.joinList = arr;
            console.log(this.info.joinList);
            this.$nextTick(() => {
              this.changeAnimation(this.info.joinList.length);
            });
          }
        })
        .catch(error => {
          if (error.response && error.response.status === 500) {
            this.$toast(error.response.data.error.message);
          }
        });
    },
    // 編寫動畫
    changeAnimation(d) {
      console.log(9090);
      let total = 25.5 * d/2
      let every = 0
      const dm = this.$refs.prizeRef;
      this.timers = setInterval(()=>{
        every += 5
        if(every < total){
          dm.style.top = - every + 'px'
        }else{
          dm.style.top = 0
          every = 0
        }
      },120)
    },

// 關閉定時器
   beforeDestroy() {
       clearInterval(this.timers)
   },

css:

     .prize_container {
        overflow: hidden;
        position: absolute;
        height: 90%;
        width: 100%;
        padding: 30px 0;
      }

      .prize_ul {
        width: 100%;
        color: #fff;
        position: absolute;
        padding: 0px 80px;
        // animation: opacityShow linear 5s infinite;
        .prize_item {
          width: 100%;
          display: flex;
          justify-content: space-between;
          margin-bottom: 12px;
        }
      }

 

在changeAnimation函數中, let total = 25.5 * d/2  這個25.5是每行的高度,通過 every(移動距離) 與 total(總高度) 比較,實現循環

缺點:

  1. 滾動的時候總是感覺一卡一卡的效果,不夠流暢( 原因: 瀏覽器每秒刷新的次數 和 每次移動距離的時間頻率 不一致,導致視覺上產生卡頓效果 )
  2. 通過top值進行移動,比較損耗性能,每次改變都會影響布局
  3. 獲取總高度total,不要手動計算,應該通過 clientHeight 動態獲取比較好
高級方法:

使用一個屬性: 幀動畫  window.requestAnimationFrame() 
告訴瀏覽器——你希望執行一個動畫,並且要求瀏覽器在下次重繪之前調用指定的回調函數更新動畫。該方法需要傳入一個回調函數作為參數,該回調函數會在瀏覽器下一次重繪之前執行
這個方法掛載在window上,很方便我們的使用
 
實現原理:
  1.  通過控制 transform 的 translateY值進行移動動畫
  2. 動態獲取列表高度,padding,margin去掉,否則會在計算高度的時候,有誤差,循環銜接點會有卡頓
  3. requestAnimationFrame與animate函數相互調用,執行幀動畫requestAnimationFrame時,調用移動動畫的函數,實現同頻率改變    requestAnimationFrame(this.animate) 

    animate() {
        requestAnimationFrame(this.animate);
     this.changeAnimation();
    },

html:

      <div class="prize_container">
          <div class="prize_list"  :style="{ transform: 'translateY( -'+ ulLeft + 'px)' }" >
            <ul
              ref="prizeUl"
              class="prize_ul"
              v-if="info.joinList && info.joinList.length" >
              <li
                class="prize_item"
                v-for="(item, index) in info.joinList"
                :key="index"
              >
                <div class="left">{{ item.mobile | mobileFilter }}</div>
                <div class="right">{{ item.name }}</div>
              </li>
            </ul>
            <ul
              class="prize_ul"
              v-if="info.joinList && info.joinList.length" >
              <li
                class="prize_item"
                v-for="(item, index) in info.joinList"
                :key="index"
              >
                <div class="left">{{ item.mobile | mobileFilter }}</div>
                <div class="right">{{ item.name }}</div>
              </li>
            </ul>
          </div>
      </div>

這里使用復制兩個ul元素,不在js中操作復制列表

js:

data(){
    prizeUlHeight:0,  //滾動ref高度
    $prizeUl:null,  //滾動的ref
    ulLeft:0, //移動參數 
}
 beforeDestroy() {
    cancelAnimationFrame(this.times); //清理原生的監聽
  },

methods:{
   // 獲取活動信息
   getData() {
      this.fetch
        .get("TjModule/GetActivityInfo", {
          activityId: this.id
        })
        .then(res => {
          if (res.data && res.data.success) {
            this.$setTitle(res.data.result.activityName);
            this.info = res.data.result;
            this.$nextTick(() => {
              this.$prizeUl = this.$refs.prizeUl;
              this.prizeUlHeight = this.$prizeUl.clientHeight;
              this.times =  requestAnimationFrame(this.animate);
            });
          }
        })
        .catch(error => {
          if (error.response && error.response.status === 500) {
            this.$toast(error.response.data.error.message);
          }
        });
    },
    animate() {
      requestAnimationFrame(this.animate);
      this.changeAnimation();
    },
    // 編寫動畫
    changeAnimation(d) {
      if( this.ulLeft == this.prizeUlHeight ){
        this.ulLeft = 0;
      }else{
        this.ulLeft += 1;
      }
    },

}

css:

.prize_container {
     overflow: hidden;
     position: absolute;
     height: 90%;
     width: 100%;
}

.prize_ul {
     width: 100%;
     color: #fff;
     // position: absolute;
     padding: 0px 80px;
     .prize_item {
        width: 100%;
        display: flex;
        line-height: 58px;
        justify-content: space-between;
    }
}

這樣就完美解決了循環滾動動畫,

使用幀動畫還有一個優點:  

每次切換頁面的時候,幀動畫會暫停執行,直到切換回該頁面,才會繼續執行動畫,這樣就比定時器更加保護性能

 

其實還有一個方案:

用css + js

  1. css中寫動畫,把動畫屬性分開寫, animation-duration 動態計算:根據每行花費幾秒 * 幾行 這樣動態賦值
  2. css中通過控制 transform 的 translateY值進行移動50%即可
// 寫動畫
@keyframes opacityShow {
        from {
          transform: translateY(0);          
        }
        to {
          transform: translateY(-50%);          
        }
}
.prize_ul {
        width: 100%;
        color: #fff;
        padding: 0px 80px;
        animation-name: opacityShow;
        animation-iteration-count: infinite;
        .prize_item {
          width: 100%;
          display: flex;
          line-height: 58px;
          justify-content: space-between;
        }
 }
 

 

 使用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM