HTML5应用开发:神奇的动态布局库isotope教程
1. isotope介绍
Isotope 是一个jQuery的插件,用来实现精美的动态元素布局。可以到http://isotope.metafizzy.co/demos/elements-complete.html了解一下大概情况。
Isotope可以实现仅仅依靠CSS3无法实现的动态布局方式,可以动态添加,删除,排序,筛选元素。Isotope的动画引擎可以充分使用现代浏览器CSS动画中GPU硬件加速性能,。
实例我已经上传到CSDN资源中,敬请下载。
2. 简单的isotope例子
Isotope要求jQuery1.4.3版本以上。首先需要在HTML页面中加载jQuery和isotope。
- <script src="../js/jquery-1.7.1.min.js"></script>
- <script src="../jquery.isotope.min.js"></script>
Isotope可以工作在一个包含很多类似item的container中,如下面所示:在div container中,声明了很累类似的div item。.
- <div id="container">
- <div class="item">…</div>
- <div class="item">…</div>
- <div class="item">…</div>
- …
- </div>
在JavaScript中,添加如下代码:
- $('#container').isotope({
- // options
- itemSelector : '.item',
- layoutMode : 'fitRows'
- });
itemSelector 用来指定container中用来动态排版的元素。
运行效果如下图所示:
调整窗口大小后,排列效果图。
3. Sorting and Filtering
在isotope中,可以动态地对元素进行排序和筛选。
排序的方式很多样化,可以按照元素的不同属性进行排序。首先在HTML页面中添加相应的option:
- <section id="options" class="clearfix">
- <h3>Sort</h3>
- <ul id="sort-by" class="option-set clearfix" data-option-key="sortBy">
- <li><a href="#sortBy=original-order" data-option-value="original-order" class="selected" data>original-order</a></li>
- <li><a href="#sortBy=name" data-option-value="name">name</a></li>
- <li><a href="#sortBy=symbol" data-option-value="symbol">symbol</a></li>
- <li><a href="#sortBy=number" data-option-value="number">number</a></li>
- <li><a href="#sortBy=weight" data-option-value="weight">weight</a></li>
- <li><a href="#sortBy=category" data-option-value="category">category</a></li>
- <li><a href="#sortBy=random" data-option-value="random">random</a></li>
- </ul>
- <h3>Sort direction</h3>
- <ul id="sort-direction" class="option-set clearfix" data-option-key="sortAscending">
- <li><a href="#sortAscending=true" data-option-value="true" class="selected">sort ascending</a></li>
- <li><a href="#sortAscending=false" data-option-value="false">sort descending</a></li>
- </ul>
- </section> <!– #options –>
我们看到,排序的方式包含了element所有的属性。可以进行升序排列也可以降序排列。
Element代码:
- <div class="element transition metal " data-symbol="Hg" data-category="transition">
- <p class="number">80</p>
- <h3 class="symbol">Hg</h3>
- <h2 class="name">Mercury</h2>
- <p class="weight">200.59</p>
- </div>
在JavaScript中,对每个sorting的方法进行实现:
- $(function(){
- var $container = $('#container');
- $container.isotope({
- itemSelector : '.element',
- getSortData : {
- symbol : function( $elem ) {
- return $elem.attr('data-symbol');
- },
- category : function( $elem ) {
- return $elem.attr('data-category');
- },
- number : function( $elem ) {
- return parseInt( $elem.find('.number').text(), 10 );
- },
- weight : function( $elem ) {
- return parseFloat( $elem.find('.weight').text().replace( /[]/g, '') );
- },
- name : function ( $elem ) {
- return $elem.find('.name').text();
- }
- }
- });
- var $optionSets = $('#options .option-set'),
- $optionLinks = $optionSets.find('a');
- $optionLinks.click(function(){
- var $this = $(this);
- // don't proceed if already selected
- if ( $this.hasClass('selected') ) {
- return false;
- }
- var $optionSet = $this.parents('.option-set');
- $optionSet.find('.selected').removeClass('selected');
- $this.addClass('selected');
- // make option object dynamically, i.e. { filter: '.my-filter-class' }
- var options = {},
- key = $optionSet.attr('data-option-key'),
- value = $this.attr('data-option-value');
- // parse 'false' as false boolean
- value = value === 'false' ? false : value;
- options[ key ] = value;
- if ( key === 'layoutMode' && typeof changeLayoutMode === 'function' ) {
- // changes in layout modes need extra logic
- changeLayoutMode( $this, options )
- } else {
- // otherwise, apply new options
- $container.isotope( options );
- }
- return false;
- });
- });
筛选的实现:isotope可以筛选不同属性的元素,需要对每个element属性通过class进行标记,如一个典型的element定义如下:
- <div class="element transition metal " data-symbol="Hg" data-category="transition">
- <p class="number">80</p>
- <h3 class="symbol">Hg</h3>
- <h2 class="name">Mercury</h2>
- <p class="weight">200.59</p>
- </div>
在class中表明该元素是transition 而且是metal和
sorting类似,在HTML中添加筛选的option:
- <section id="options" class="clearfix">
- <h3>Filters</h3>
- <ul id="filters" class="option-set clearfix" data-option-key="filter">
- <li><a href="#filter" data-option-value="*" class="selected">show all</a></li>
- <li><a href="#filter" data-option-value=".metal">metal</a></li>
- <li><a href="#filter" data-option-value=".transition">transition</a></li>
- <li><a href="#filter" data-option-value=".post-transition">post-transition</a></li>
- <li><a href="#filter" data-option-value=".nonmetal">nonmetal</a></li>
- <li><a href="#filter" data-option-value=".inner-transition">inner-transition</a></li>
- <li><a href="#filter" data-option-value=".alkali, .alkaline-earth">alkali and alkaline-earth</a></li>
- <li><a href="#filter" data-option-value=":not(.transition)">not transition</a></li>
- <li><a href="#filter" data-option-value=".metal:not(.transition)">metal but not transition</a></li>
- </ul>
- </section> <!– #options –>
对应的JavaScript function实现如下:
- $(function(){
- var $container = $('#container');
- $container.isotope({
- itemSelector : '.element'
- });
- var $optionSets = $('#options .option-set'),
- $optionLinks = $optionSets.find('a');
- $optionLinks.click(function(){
- var $this = $(this);
- // don't proceed if already selected
- if ( $this.hasClass('selected') ) {
- return false;
- }
- var $optionSet = $this.parents('.option-set');
- $optionSet.find('.selected').removeClass('selected');
- $this.addClass('selected');
- // make option object dynamically, i.e. { filter: '.my-filter-class' }
- var options = {},
- key = $optionSet.attr('data-option-key'),
- value = $this.attr('data-option-value');
- // parse 'false' as false boolean
- value = value === 'false' ? false : value;
- options[ key ] = value;
- if ( key === 'layoutMode' && typeof changeLayoutMode === 'function' ) {
- // changes in layout modes need extra logic
- changeLayoutMode( $this, options )
- } else {
- // otherwise, apply new options
- $container.isotope( options );
- }
- return false;
- });
- });
Filter demo演示,全部显示:
筛选所有metal的元素:
4. 动态添加元素
在isotope中,可以对container中的元素进行动态的删除和添加。
首先还是在HTML页面中添加相应的操作option:
- <section id="options">
- <ul class="clearfix">
- <li id="insert"><a href="#insert">Insert new elements</a></li>
- <li id="append"><a href='#append'>Append new elements</a></li>
- <li id="prepend"><a href='#prepend'>Prepend</a></li>
- </ul>
- </section>
在对应的JavaScript中,添加对function的实现:
- $(function(){
- var $container = $('#container');
- $('#insert a').click(function(){
- var $newEls = $( fakeElement.getGroup() );
- $container.isotope( 'insert', $newEls );
- return false;
- });
- $('#append a').click(function(){
- var $newEls = $( fakeElement.getGroup() );
- $container.append( $newEls ).isotope( 'appended', $newEls );
- return false;
- });
- $('#prepend a').click(function(){
- var $newEls = $( fakeElement.getGroup() );
- $container
- .prepend( $newEls ).isotope('reloadItems').isotope({ sortBy: 'original-order' })
- // set sort back to symbol for inserting
- .isotope('option', { sortBy: 'symbol' });
- return false;
- });
- $container.isotope({
- itemSelector : '.element',
- filter: '*',
- getSortData : {
- symbol : function( $elem ) {
- return $elem.attr('data-symbol');
- }
- },
- sortBy : 'symbol'
- });
- });
5. 不同的布局机制
在本例中,我们来尝试isotope中非常神奇的布局机制。
首先在HTML页面中,添加布局机制的选项:
- <section id="options" class="clearfix">
- <h3>Layout modes</h3>
- <ul id="layouts" class="option-set clearfix" data-option-key="layoutMode">
- <li><a href="#masonry" data-option-value="masonry" class="selected">masonry</a></li>
- <li><a href="#fitRows" data-option-value="fitRows">fitRows</a></li>
- <li><a href="#cellsByRow" data-option-value="cellsByRow">cellsByRow</a></li>
- <li><a href="#straightDown" data-option-value="straightDown">straightDown</a></li>
- <li><a href="#masonryHorizontal" data-option-value="masonryHorizontal" class="horizontal">masonryHorizontal</a></li>
- <li><a href="#fitColumns" data-option-value="fitColumns" class="horizontal">fitColumns</a></li>
- <li><a href="#cellsByColumn" data-option-value="cellsByColumn" class="horizontal">cellsByColumn</a></li>
- <li><a href="#straightAcross" data-option-value="straightAcross" class="horizontal">straightAcross</a></li>
- </ul>
- </section> <!-- #options -->
在JavaScript代码中实现相应的布局机制:
- $(function(){
- var $container = $('#container');
- // add randomish size classes
- $container.find('.element').each(function(){
- var $this = $(this),
- number = parseInt( $this.find('.number').text(), 10 );
- if ( number % 7 % 2 === 1 ) {
- $this.addClass('width2');
- }
- if ( number % 3 === 0 ) {
- $this.addClass('height2');
- }
- });
- $container.isotope({
- itemSelector : '.element',
- masonry : {
- columnWidth : 120
- },
- masonryHorizontal : {
- rowHeight: 120
- },
- cellsByRow : {
- columnWidth : 240,
- rowHeight : 240
- },
- cellsByColumn : {
- columnWidth : 240,
- rowHeight : 240
- }
- });
- // change layout
- var isHorizontal = false;
- function changeLayoutMode( $link, options ) {
- var wasHorizontal = isHorizontal;
- isHorizontal = $link.hasClass('horizontal');
- if ( wasHorizontal !== isHorizontal ) {
- // orientation change
- // need to do some clean up for transitions and sizes
- var style = isHorizontal ?
- { height: '80%', width: $container.width() } :
- { width: 'auto' };
- // stop any animation on container height / width
- $container.filter(':animated').stop();
- // disable transition, apply revised style
- $container.addClass('no-transition').css( style );
- setTimeout(function(){
- $container.removeClass('no-transition').isotope( options );
- }, 100 )
- } else {
- $container.isotope( options );
- }
- }
- var $optionSets = $('#options .option-set'),
- $optionLinks = $optionSets.find('a');
- $optionLinks.click(function(){
- var $this = $(this);
- // don't proceed if already selected
- if ( $this.hasClass('selected') ) {
- return false;
- }
- var $optionSet = $this.parents('.option-set');
- $optionSet.find('.selected').removeClass('selected');
- $this.addClass('selected');
- // make option object dynamically, i.e. { filter: '.my-filter-class' }
- var options = {},
- key = $optionSet.attr('data-option-key'),
- value = $this.attr('data-option-value');
- // parse 'false' as false boolean
- value = value === 'false' ? false : value;
- options[ key ] = value;
- if ( key === 'layoutMode' && typeof changeLayoutMode === 'function' ) {
- // changes in layout modes need extra logic
- changeLayoutMode( $this, options )
- } else {
- // otherwise, apply new options
- $container.isotope( options );
- }
- return false;
- });
- );
显示效果:
选择fitRows后排列效果:
完整demo代码:https://github.com/DaweiCheng/isotope-tutorial/blob/master/layout.html
Isotope中同样可以实现点击element,其中元素动态扩展的效果,即,在运行时,动态改变每个element尺寸;参见代码:https://github.com/DaweiCheng/isotope-tutorial/blob/master/relayout.html
运行显示效果:
点中Li元素之后显示效果:
6. 标记#Hash历史记录
至此,相信读者已经领略到了Isotope显示的动态布局的神奇之处,使用isotope可以实现你意向不到的绚丽的布局和动画效果。但是可否每次记住布局方式,当点击浏览器返回按钮的时候,返回上次观看的布局方式呢?
答案是可以的,借助jQuery另一个插件JQuery BBQ来实现。
jQuery BBQ的官方介绍:jQuery BBQ leverages the HTML5 hashchange event to allow simple, yet powerful bookmarkable #hash history..
首先在HTML页面中加载需要的JavaScript文件
- collapse sourceview plaincopy to clipboardprint?
- <script src="js/jquery-1.7.1.min.js"></script>
- <script src="js/jquery.isotope.min.js"></script>
- <script src="js/jquery.ba-bbq.min.js"></script>
然后我们在option中,将sorting, filtering,layout modes全部添加进来:
- collapse sourceview plaincopy to clipboardprint?
- <section id="options" class="clearfix">
- <h3>Filters</h3>
- <ul class="option-set clearfix">
- <li><a href="#filter=*" class="selected">show all</a></li>
- <li><a href="#filter=.metal">metal</a></li>
- <li><a href="#filter=.transition">transition</a></li>
- <li><a href="#filter=.post-transition">post-transition</a></li>
- <li><a href="#filter=.nonmetal">nonmetal</a></li>
- <li><a href="#filter=.inner-transition">inner-transition</a></li>
- <li><a href="#filter=.alkali%2C+.alkaline-earth">alkali and alkaline-earth</a></li>
- <li><a href="#filter=%3Anot(.transition)">not transition</a></li>
- <li><a href="#filter=.metal%3Anot(.transition)">metal but not transition</a></li>
- </ul>
- <h3>Sort</h3>
- <ul class="option-set clearfix">
- <li><a href="#sortBy=original-order" class="selected">original-order</a></li>
- <li><a href="#sortBy=name">name</a></li>
- <li><a href="#sortBy=symbol">symbol</a></li>
- <li><a href="#sortBy=number">number</a></li>
- <li><a href="#sortBy=weight">weight</a></li>
- <li><a href="#sortBy=category">category</a></li>
- <li><a href="#sortBy=random">random</a></li>
- </ul>
- <h3>Sort direction</h3>
- <ul class="option-set clearfix">
- <li><a href="#sortAscending=true" class="selected">sort ascending</a></li>
- <li><a href="#sortAscending=false">sort descending</a></li>
- </ul>
- <h3>Layout modes</h3>
- <ul class="option-set clearfix">
- <li><a href="#layoutMode=masonry" class="selected">masonry</a></li>
- <li><a href="#layoutMode=fitRows">fitRows</a></li>
- <li><a href="#layoutMode=cellsByRow">cellsByRow</a></li>
- <li><a href="#layoutMode=straightDown">straightDown</a></li>
- </ul>
- </section> <!-- #options -->
对应的JavaScript代码中,Hash bookmark history部分代码如下,由于篇幅限制,全部JavaScript代码请参见Github中的文件:
- collapse sourceview plaincopy to clipboardprint?
- var hashChanged = false;
- $(window).bind( 'hashchange', function( event ){
- // get options object from hash
- var hashOptions = window.location.hash ? $.deparam.fragment( window.location.hash, true ) : {},
- // do not animate first call
- aniEngine = hashChanged ? 'best-available' : 'none',
- // apply defaults where no option was specified
- options = $.extend( {}, defaultOptions, hashOptions, { animationEngine: aniEngine } );
- // apply options from hash
- $container.isotope( options );
- // save options
- isotopeOptions = hashOptions;
- // if option link was not clicked
- // then we'll need to update selected links
- if ( !isOptionLinkClicked ) {
- // iterate over options
- var hrefObj, hrefValue, $selectedLink;
- for ( var key in options ) {
- hrefObj = {};
- hrefObj[ key ] = options[ key ];
- // convert object into parameter string
- // i.e. { filter: '.inner-transition' } -> 'filter=.inner-transition'
- hrefValue = $.param( hrefObj );
- // get matching link
- $selectedLink = $optionSets.find('a[href="#' + hrefValue + '"]');
- changeSelectedLink( $selectedLink );
- }
- }
- isOptionLinkClicked = false;
- hashChanged = true;
- })
- // trigger hashchange to capture any hash data on init
- .trigger('hashchange');
至此就实现了可标记的#hash历史记录,可以记住所有的排版方式,依次进行返回观看前几次的排版样式。
本篇全部示例代码:https://github.com/DaweiCheng/isotope-tutorial 欢迎贡献更多的示例代码。