前端開發whqet,csdn,王海慶,whqet,前端開發專家
效果預覽
衆所周知,flash動畫類型可以分為補間動畫和逐幀動畫,補間動畫又可以分為屬性改變(大小、位置、顔色等)和形狀改變(直線變弧線等)。網頁動畫裡,我們可以使用css3、javascript(jquery)等實作屬性改變,卻對形狀改變無能為力,那麼如何實作網頁動畫裡的形狀改變呢?今天提供一種解決方案——通過snap.svg動态改變svg形狀實作,案例效果如下圖所示,案例靈感來自codrops。
----------------
----------------------------------------
線上研究點選這裡,下載下傳收藏點選這裡。
----------------------------------------
---------------
關鍵技術
制作這個案例,你需要
1. snap.svg的基本使用
2. classie.js的基本使用
3. snap.svg操作改變svg的内容
4. 沖動與激情
實作步驟
ok,我們html内容如下,.menu為整個容器,.menu__handle為單擊按鈕,.menu__inner為彈出菜單内容,.morph-shape為形狀改變的線條。我們把需要改變的線條的path資料實作放到data-morph-open和data-morph-close兩個屬性裡。
<div class="container">
<nav id="menu" class="menu">
<button class="menu__handle"><span>Menu</span></button>
<div class="menu__inner">
<ul>
<li><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >Home</a></li>
<li><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >Favs</a></li>
<li><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >Files</a></li>
<li><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >Stats</li>
</ul>
</div>
<div class="morph-shape" data-morph-open="M300-10c0,0,295,164,295,410c0,232-295,410-295,410" data-morph-close="M300-10C300-10,5,154,5,400c0,232,295,410,295,410">
<svg width="100%" height="100%" viewBox="0 0 600 800" preserveAspectRatio="none">
<path fill="none" d="M300-10c0,0,0,164,0,410c0,232,0,410,0,410"/>
</svg>
</div>
</nav>
</div>
然後是css,css裡面我們實作基本布局與css3動畫。css裡面我們使用了Normalize和prefixfree。按鈕(三條線變成x)由.menu__handle的before、after兩個僞對象和span實作。
/*統一化設定*/
*, *:after, *:before { box-sizing: border-box; }
.clearfix:before, .clearfix:after { content: ''; display: table; }
.clearfix:after { clear: both; }
body {
color: #fff;
background: #FF7F50;
font-weight: 400;
font-size: 1em;
}
a {
color: #fff;
text-decoration: none;
}
a:hover,
a:focus {
color: #393;
outline: none;
}
.container {
text-align: center;
padding: 5.25em 0.5em 0;
}
/*菜單設定*/
.menu {
position: fixed;
width: 240px;
top: 2px;
bottom: 2px;
left: 0;
z-index: 100;
overflow: hidden;
transform: translate3d(-150px, 0, 0);
transition: transform 0.6s;
}
.menu.menu--open {
transform: translate3d(0, 0, 0);
}
.menu__inner {
width: calc(100% + 15px);
padding: 0 100px 2em 0;
overflow-y: auto;
height: 100%;
position: relative;
z-index: 100;
}
.menu ul {
list-style: none;
padding: 0;
margin: 0;
}
.menu ul li {
transform: translate3d(-150px, 50px, 0);
transition: transform 0.6s;
height:24px;
line-height:24px;
}
.menu.menu--anim ul li {
transform: translate3d(0, 0, 0);
}
.menu ul li:first-child {
transition-delay: 0.3s;
}
.menu ul li:nth-child(2) {
transition-delay: 0.2s;
}
.menu ul li:nth-child(3) {
transition-delay: 0.1s;
}
.menu ul li a {
display: block;
outline: none;
}
/*按鈕及單擊之後變換*/
.menu__handle {
background: #FF7F50;
border: none;
width: 30px;
height: 24px;
padding: 0;
outline: none;
position: absolute;
top: 3px;
right: 45px;
z-index: 2000;
}
.menu__handle::before,
.menu__handle::after,
.menu__handle span {
background: #fff;
}
.menu__handle::before,
.menu__handle::after {
content: '';
position: absolute;
height: 2px;
width: 100%;
left: 0;
top: 50%;
transform-origin: 50% 50%;
transition: transform 0.25s;
}
.menu__handle span {
position: absolute;
width: 100%;
height: 2px;
left: 0;
overflow: hidden;
text-indent: 200%;
transition: opacity 0.25s;
}
.menu__handle::before {
transform: translate3d(0, -10px, 0);
}
.menu__handle::after {
transform: translate3d(0, 10px, 0);
}
.menu--open .menu__handle span {
opacity: 0;
}
.menu--open .menu__handle::before {
transform: rotate3d(0, 0, 1, 45deg);
}
.menu--open .menu__handle::after {
transform: rotate3d(0, 0, 1, -45deg);
}
/* 線條及改變 */
.morph-shape {
position: absolute;
width: 160px;
height: 100%;
top: 0;
right: 0px;
}
.morph-shape svg path {
stroke: #fff;
stroke-width: 2px;
}
.menu--open .morph-shape svg path {
stroke: #fff;
stroke-width: 4px;
}
然後是javascript,也是我們的核心。這裡用到了classie.js和snap.svg(可以參考張鑫旭大俠翻譯的snap.svg中文版)。
function SVGMenu( el, options ) {
this.el = el;
this.init();
}
SVGMenu.prototype.init = function() {
this.trigger = this.el.querySelector( 'button.menu__handle' );
this.shapeEl = this.el.querySelector( 'div.morph-shape' );
var s = Snap( this.shapeEl.querySelector( 'svg' ) );
this.pathEl = s.select( 'path' );
this.paths = {
reset : this.pathEl.attr( 'd' ),
open : this.shapeEl.getAttribute( 'data-morph-open' ),
close : this.shapeEl.getAttribute( 'data-morph-close' )
};
this.isOpen = false;
this.trigger.addEventListener( 'click', this.toggle.bind(this) );
};
SVGMenu.prototype.toggle = function() {
var self = this;
if( this.isOpen ) {
classie.remove( self.el, 'menu--anim' );
setTimeout( function() { classie.remove( self.el, 'menu--open' ); }, 250 );
}
else {
classie.add( self.el, 'menu--anim' );
setTimeout( function() { classie.add( self.el, 'menu--open' ); }, 250 );
}
self.pathEl.stop().animate( { 'path' : self.isOpen ? self.paths.close : this.paths.open }, 350, mina.easeout, function() {
self.pathEl.stop().animate( { 'path' : self.paths.reset }, 800, mina.elastic );
} );
self.isOpen = !self.isOpen;
};
new SVGMenu( document.getElementById( 'menu' ) );
ok,請大家仔細揣摩。當然,這個方面也出了一些插件可以使用例如,SVG Morpheus,也可看看《SVG-Morpheus實作SVG圖示圖形間的補形動畫》這篇教程。
----------------------------------------------------------
前端開發whqet,關注web前端開發,分享相關資源,歡迎點贊,歡迎拍磚。
---------------------------------------------------------------------------------------------------------