vue中結合animate.css實現元素動畫入場

話不多說先看下demo的GIF:



1.首先引入animate.css,可以直接在index.html中cdn引入;

2.其次在開發這種動畫較多的頁面我覺得還是引用jquery比較方便,操作dom稍多,
我這裏沒有使用jquery,就想複習複習原生js。可以npm安裝,在build/webpack.base.conf.js中定義插件:
    var webpack = require('webpack '); 
    在module.exports的對象中加入:
    plugins:[
      new webpack.ProvidePlugin({
         $:"jquery",
         jQuery:"jquery",
         "windows.jQuery":"jquery"
      })
    ],

接下來直接上該頁面代碼,就是一個vue組件:

<template>
  <div class="home">
		<div class="header " id="header" :class="{fixed: isFixed}">
		     <div class=" fixed-width clearfix">
		        <div class="header-title fl">我是頂部</div>
		        <div class="header-buy fr"  >我也是頂部</div>
		     </div>
		</div>
		<div class="content">
			<div class="banner"></div>
			<div class="animate-box slide">
				<h2 class="animate text-h2" data-ani="fadeInUpBig">LuckLin520 Written in Chengdu</h2>
				<p class="animate text-p" data-ani="rollIn" data-delay="1000">Thank you for reading and I will continue to work hard! —————2018/08/08</p>
			</div>
			<div class="animate-box bounce">
				<div class="animate yellow" data-ani="bounceInLeft"></div>
				<div class="animate red" data-ani="bounceInRight"></div>
				<div class="animate green" data-ani="bounceInLeft"></div>
				<div class="animate blue" data-ani="bounceInRight"></div>
			</div>
			<div class="animate-box slide">
				<h2 class="animate text-h2" data-ani="fadeInUpBig">做真實的自己,一切都會好起來的</h2>
				<p class="animate text-p" data-ani="slideInRight" data-delay="1000">Be true to yourself and everything will be fine</p>
			</div>
			<div class="animate-box zoom">
				<div class="animate one" data-ani="bounceInLeft"></div>
				<div class="animate two" data-ani="bounceInRight"></div>
				<div class="animate three" data-ani="bounceInLeft"></div>
				<div class="animate four" data-ani="bounceInRight"></div>
			</div>
		</div>
  </div>
</template>

<script>
	export default {
	  data () {
	    return {
	    	isFixed: 0
	    }
	  },
	  methods: {
	  	handleScroll() {
	  		let top = pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
	  		if(top > 250){
	  			this.isFixed = 1;
	  		}else if(top < 200){
	  			this.isFixed = 0;
	  		}
	  	},
	  	handleAnimate() {
	  		let top = pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
	  		let vh = document.documentElement.clientHeight;
	  		let dom = document.querySelectorAll(".animate");
	  		[].slice.call(dom).forEach(v => {
	  			if(top + vh > v.offsetTop){
	  				var delay = v.dataset.delay;
	  				if(delay){
	  					setTimeout(() => {
	  						v.style.opacity = 1;
		  					v.classList.add(v.dataset.ani)
		  				}, delay)
	  				}else{
	  					v.style.opacity = 1;
	  					v.classList.add(v.dataset.ani)
	  				}
	  			}else{
	  				v.classList.remove(v.dataset.ani)
	  				v.style.opacity = 0;
	  			}
	  		})

	  	}
	  },
	  mounted() {
	  	this.$nextTick(() => {
	  		this.handleAnimate()//初始化第一次加載時在視口內就執行動畫
	  		addEventListener('scroll', this.handleScroll);
	  		addEventListener('scroll', this.handleAnimate);

	  	})
	  	
	  },
	  destroyed() {
	  	removeEventListener('scroll', this.handleScroll);//避免影響其他頁面
	  	removeEventListener('scroll', this.handleAnimate);
	  }
	}
</script>

<style scoped lang="scss">
	.header{
		background: green;
		height: 50px;
	}
	.fixed{
        position: fixed;
        top: 0px;
        z-index: 4;
        width: 100%;
        animation: slideInDown .5s;
    }
    .content{
    	height: 2000px;
    	background: pink;
    	overflow: hidden;
    	.banner{
			width: 80%;
			height: 400px;
			background:orange;
			margin: 80px auto;
    	}
    	.slide{
    		font-size: initial;
    		height: 100px;
    	}
    	.bounce{
    		width: 80%;
    		margin:0 auto 80px;
    		display: flex;
    		flex-wrap: wrap;
    		justify-content: space-between;
    		&>div{
    			height: 120px;
    			float: left;
    			width: 45%;
    		}
    		.yellow{
    			background:yellow;
    			margin-bottom: 40px;
    		}
    		.red{
    			background:red;
    		}
    		.green{
    			background:green;
    		}
    		.blue{
    			background:blue;
    		}
    	}
    	.zoom{
    		width: 80%;
    		margin:0 auto 80px;
    		display: flex;
    		justify-content: space-between;
    		&>div{
    			width: 23%;
    			height: 263px;
    		}
    		.one{
    			background:url(http://www.codingke.com/themes/codingnew-1/img/study/python/python_block1_img1.jpg) no-repeat center/100%;
    		}
    		.two{
    			background:url(http://www.codingke.com/themes/codingnew-1/img/study/python/python_block1_img2.jpg) no-repeat center/100%;
    		}
    		.three{
    			background:url(http://www.codingke.com/themes/codingnew-1/img/study/python/python_block1_img3.jpg) no-repeat center/100%;
    		}
    		.four{
    			background:url(http://www.codingke.com/themes/codingnew-1/img/study/python/python_block1_img4.jpg) no-repeat center/100%;
    		}
    	}
    }

 //animate classs
 .animate{
 	opacity: 0;
 }
 .fadeInUpBig{
 	animation: fadeInUpBig 1s;
 }
 .rollIn{
 	animation: rollIn 1s;
 }
 .slideInRight{
 	animation: slideInRight 1s;
 }
 .bounceInLeft{
	animation: bounceInLeft 2s ease-in;
 }
 .bounceInRight{
	animation: bounceInRight 2s ease-in;
 }
</style>

不難看得出核心代碼就是那個handleAnimate方法,實際運用中肯定多個頁面會有動畫效果,這個函數可以抽離成公共代碼,其實他可以只需要接收一個所有運動元素的統一選擇器(這裏的".animate"),而該方法通過這些".animate"元素傳入的自定義屬性ani來判斷該元素被指定了哪種動畫類型,通過動態添加該類型名稱的class來定義animation動畫,在最初我的思路是將animation-delay動畫延遲同樣用該類型的class在css中定義,最後我又考慮到如果不止一個元素必須用同一個動畫類型,但是有的需要有的不需要延遲呢,那不是該屬性出現耦合了?所以最後把所有動畫延遲定義在該元素自身—data-delay,沒錯又是自定義屬性,把需要有延遲時間的元素就加一個自定義屬性delay,執行中判斷是否有該屬性,有的話就用setTimeout來延遲該屬性的值的時間添加動畫class,這樣就讓動畫樣式和動畫延遲互不影響了,動畫類型樣式完全複用,同時,如果直接定義animation-delay或者直接animation以簡寫的形式來定義動畫延遲的話,當被添加上動畫class時該元素就會立馬顯示出來,就是說在延遲期間(元素動起來之前)它也是處於顯示狀態的,可以用js操作用setTimeout來延遲元素顯示出來,不過比較麻煩了,因爲還得js獲取animate-delay的值才能知道延遲時間,所以我上面最後用的是自定義屬性通過延遲添加類來處理延遲動畫,比較好操作。這些便是核心思路。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章