众所周知,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="#">Home</a></li> <li><a href="#">Favs</a></li> <li><a href="#">Files</a></li> <li><a href="#">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前端开发,分享相关资源,欢迎点赞,欢迎拍砖。
---------------------------------------------------------------------------------------------------------
原文地址:http://blog.csdn.net/whqet/article/details/42276641