jQuery Deferred和Promise创建响应式应用程序详细介绍

这篇文章,我们一起探索一下 JavaScript 中的 Deferred 和 Promise 的概念,它们是 JavaScript 工具包(如Dojo和MochiKit)中非常重要的一个功能,最近也首次亮相于 流行的 JavaScript 库 jQuery(已经是1.5版本的事情了)。 Deferred 提供了一个抽象的非阻塞的解决方案(如 Ajax 请求的响应),它创建一个 “promise” 对象,其目的是在未来某个时间点返回一个响应。如果您之前没有接触过 “promise”,我们将会在下面做详细介绍。

抽象来说,deferreds 可以理解为表示需要长时间才能完成的耗时操作的一种方式,相比于阻塞式函数它们是异步的,而不是阻塞应用程序等待其完成然后返回结果。deferred对 象会立即返回,然后你可以把回调函数绑定到deferred对象上,它们会在异步处理完成后被调用。

Promise
  你可能已经阅读过一些关于promise和deferreds实现细节的资料。在本章节中,我们大致介绍下promise如何工作,这些在几乎所有的支持deferreds的javascript框架中都是适用的。

  一般情况下,promise作为一个模型,提供了一个在软件工程中描述延时(或将来)概念的解决方案。它背后的思想我们已经介绍过:不是执行一个方法然后阻塞应用程序等待结果返回,而是返回一个promise对象来满足未来值。

  举一个例子会有助于理解,假设你正在建设一个web应用程序, 它很大程度上依赖第三方api的数据。那么就会面临一个共同的问题:我们无法获悉一个API响应的延迟时间,应用程序的其他部分可能会被阻塞,直到它返回 结果。Deferreds 对这个问题提供了一个更好的解决方案,它是非阻塞的,并且与代码完全解耦 。

  Promise/A提议'定义了一个'then‘方法来注册回调,当处理函数返回结果时回调会执行。它返回一个promise的伪代码看起来是这样的:


代码如下:

promise = callToAPI( arg1, arg2, ...);
promise.then(function( futureValue ) {
/* handle futureValue */
});
promise.then(function( futureValue ) {
/* do something else */
});

此外,promise回调会在处于以下两种不同的状态下执行:

•resolved:在这种情况下,数据是可用
•rejected:在这种情况下,出现了错误,没有可用的值
  幸运的是,'then'方法接受两个参数:一个用于promise得到了解决(resolved),另一个用于promise拒绝(rejected)。让我们回到伪代码:

代码如下:

promise.then( function( futureValue ) {
/* we got a value */
} , function() {
/* something went wrong */
} );

在某些情况下,我们需要获得多个返回结果后,再继续执行应用程序(例如,在用户可以选择他们感兴趣的选项前,显示一组动态的选项)。这种情况下,'when'方法可以用来解决所有的promise都满足后才能继续执行的场景。

代码如下:

when(
promise1,
promise2,
...
).then(function( futureValue1, futureValue2, ... ) {
/* all promises have completed and are resolved */
});

一个很好的例子是这样一个场景,你可能同时有多个正在运行的动画。 如果不跟踪每个动画执行完成后的回调,很难做到在动画完成后执行下一步任务。然而使用promise和‘when'方式却可以很直截了当的表示: 一旦动画执行完成,就可以执行下一步任务。最终的结果是我们可以可以简单的用一个回调来解决多个动画执行结果的等待问题。 例如:

代码如下:

when( function(){
/* animation 1 */
/* return promise 1 */
}, function(){
/* animation 2 */
/* return promise 2 */
} ).then(function(){
/* once both animations have completed we can then run our additional logic */
});

这意味着,基本上可以用非阻塞的逻辑方式编写代码并异步执行。 而不是直接将回调传递给函数,这可能会导致紧耦合的接口,通过promise模式可以很容易区分同步和异步的概念。

  在下一节中,我们将着眼于jQuery实现的deferreds,你可能会发现它明显比现在所看到的promise模式要简单。

jQuery的Deferreds
  jQuery在1.5版本中首次引入了deferreds。它 所实现的方法与我们之前描述的抽象的概念没有大的差别。原则上,你获得了在未来某个时候得到‘延时'返回值的能力。在此之前是无法单独使用的。 Deferreds 作为对ajax模块较大重写的一部分添加进来,它遵循了CommonJS的promise/ A设计。1.5和先前的版本包含deferred功能,可以使$.ajax() 接收调用完成及请求出错的回调,但却存在严重的耦合。开发人员通常会使用其他库或工具包来处理延迟任务。新版本的jQuery提供了一些增强的方式来管理 回调,提供更加灵活的方式建立回调,而不用关心原始的回调是否已经触发。 同时值得注意的是,jQuery的递延对象支持多个回调绑定多个任务,任务本身可以既可以是同步也可以是异步的。

  您可以浏览下表中的递延功能,有助于了解哪些功能是你需要的:






































jQuery.Deferred() 创建一个新的Deferred对象的构造函数,可以带一个可选的函数参数,它会在构造完成后被调用。
jQuery.when() 通过该方式来执行基于一个或多个表示异步任务的对象上的回调函数
jQuery.ajax() 执行异步Ajax请求,返回实现了promise接口的jqXHR对象
deferred.then(resolveCallback,rejectCallback) 添加处理程序被调用时,递延对象得到解决或者拒绝的回调。
deferred.done()

当延迟成功时调用一个函数或者数组函数.

deferred.fail()

当延迟失败时调用一个函数或者数组函数.。

deferred.resolve(ARG1,ARG2,...) 调用Deferred对象注册的‘done'回调函数并传递参数
deferred.resolveWith(context,args) 调用Deferred对象注册的‘done'回调函数并传递参数和设置回调上下文
deferred.isResolved 确定一个Deferred对象是否已经解决。
deferred.reject(arg1,arg2,...) 调用Deferred对象注册的‘fail'回调函数并传递参数
deferred.rejectWith(context,args) 调用Deferred对象注册的‘fail'回调函数并传递参数和设置回调上下文
deferred.promise() 返回promise对象,这是一个伪造的deferred对象:它基于deferred并且不能改变状态所以可以被安全的传递

jQuery延时实现的核心是jQuery.Deferred:一个可以链式调用的构造函数。...... 需要注意的是任何deferred对象的默认状态是unresolved, 回调会通过 .then() 或 .fail()方法添加到队列,并在稍后的过程中被执行。

  下面这个$.when() 接受多个参数的例子


代码如下:

function successFunc(){ console.log( “success!” ); }
function failureFunc(){ console.log( “failure!” ); }

$.when(
$.ajax( "/main.php" ),
$.ajax( "/modules.php" ),
$.ajax( “/lists.php” )
).then( successFunc, failureFunc );

在$.when() 的实现中有趣的是,它并非仅能解析deferred对象,还可以传递不是deferred对象的参数,在处理的时候会把它们当做deferred对象并立 即执行回调(doneCallbacks)。 这也是jQuery的Deferred实现中值得一提的地方,此外,deferred.then()还为deferred.done和 deferred.fail()方法在deferred的队列中增加回调提供支持。

  利用前面介绍的表中提到的deferred功能,我们来看一个代码示例。 在这里,我们创建一个非常基本的应用程序:通过$.get方法(返回一个promise)获取一条外部新闻源(1)并且(2)获取最新的一条回复。 同时程序还通过函数(prepareInterface())实现新闻和回复内容显示容器的动画。

  为了确保在执行其他相关行为前,上面的这三个步骤确保完成,我们使用$.when()。根据您的需要 .then()和.fail() 处理函数可以被用来执行其他程序逻辑。

代码如下:

function getLatestNews() {
return $.get( “latestNews.php”, function(data){
console.log( “news data received” );
$( “.news” ).html(data);
} );
}
function getLatestReactions() {
return $.get( “latestReactions.php”, function(data){
console.log( “reactions data received” );
$( “.reactions” ).html(data);
} );
}

function prepareInterface() {
return $.Deferred(function( dfd ) {
var latest = $( “.news, .reactions” );
latest.slideDown( 500, dfd.resolve );
latest.addClass( “active” );
}).promise();
}

$.when(
getLatestNews(), getLatestReactions(), prepareInterface()
).then(function(){
console.log( “fire after requests succeed” );
}).fail(function(){
console.log( “something went wrong!” );
});

deferreds在ajax的幕后操作中使用并不意味着它们无法在别处使用。 在本节中,我们将看到在一些解决方案中,使用deferreds将有助于抽象掉异步的行为,并解耦我们的代码。

异步缓存
  当涉及到异步任务,缓存可以是一个有点苛刻的,因为你必须确保对于同一个key任务仅执行一次。因此,代码需要以某种方式跟踪入站任务。 例如下面的代码片段:

代码如下:

$.cachedGetScript( url, callback1 );
$.cachedGetScript( url, callback2 );

缓存机制需要确保 脚本不管是否已经存在于缓存,只能被请求一次。 因此,为了缓存系统可以正确地处理请求,我们最终需要写出一些逻辑来跟踪绑定到给定url上的回调。

  值得庆幸的是,这恰好是deferred所实现的那种逻辑,因此我们可以这样来做:

代码如下:

var cachedScriptPromises = {};
$.cachedGetScript = function( url, callback ) {
if ( !cachedScriptPromises[ url ] ) {
cachedScriptPromises[ url ] = $.Deferred(function( defer ) {
$.getScript( url ).then( defer.resolve, defer.reject );
}).promise();
}
return cachedScriptPromises[ url ].done( callback );
};

代码相当简单:我们为每一个url缓存一个promise对象。 如果给定的url没有promise,我们创建一个deferred,并发出请求。 如果它已经存在我们只需要为它绑定回调。 该解决方案的一大优势是,它会透明地处理新的和缓存过的请求。 另一个优点是一个基于deferred的缓存 会优雅地处理失败情况。 当promise以‘rejected'状态结束的话,我们可以提供一个错误回调来测试:

  $.cachedGetScript( url ).then( successCallback, errorCallback );

  请记住:无论请求是否缓存过,上面的代码段都会正常运作!

通用异步缓存
  为了使代码尽可能的通用,我们建立一个缓存工厂并抽象出实际需要执行的任务​​:

代码如下:

$.createCache = function( requestFunction ) {
var cache = {};
return function( key, callback ) {
if ( !cache[ key ] ) {
cache[ key ] = $.Deferred(function( defer ) {
requestFunction( defer, key );
}).promise();
}
return cache[ key ].done( callback );
};
}

现在具体的请求逻辑已经抽象出来,我们可以重新写cachedGetScript:

代码如下:

$.cachedGetScript = $.createCache(function( defer, url ) {
$.getScript( url ).then( defer.resolve, defer.reject );
});

每次调用createCache将创建一个新的缓存库,并返回一个新的高速缓存检索函数。现在,我们拥有了一个通用的缓存工厂,它很容易实现涉及从缓存中取值的逻辑场景。

图片加载
  另一个候选场景是图像加载:确保我们不加载同一个图像两次,我们可能需要加载图像。 使用createCache很容易实现:


代码如下:

$.loadImage = $.createCache(function( defer, url ) {
var image = new Image();
function cleanUp() {
image.onload = image.onerror = null;
}
defer.then( cleanUp, cleanUp );
image.onload = function() {
defer.resolve( url );
};
image.onerror = defer.reject;
image.src = url;
});

接下来的代码片段如下:

代码如下:

$.loadImage( "my-image.png" ).done( callback1 );
$.loadImage( "my-image.png" ).done( callback2 );

无论image.png是否已经被加载,或者正在加载过程中,缓存都会正常工作。

缓存数据的API响应
  哪些你的页面的生命周期过程中被认为是不可变的API请求,也是缓存完美的候选场景。 比如,执行以下操作:


代码如下:

$.searchTwitter = $.createCache(function( defer, query ) {
$.ajax({
url: "http://search.twitter.com/search.json",
data: { q: query },
dataType: "jsonp",
success: defer.resolve,
error: defer.reject
});
});

程序允许你在Twitter上进行搜索,同时缓存它们:


代码如下:

$.searchTwitter( "jQuery Deferred", callback1 );
$.searchTwitter( "jQuery Deferred", callback2 );

定时
  基于deferred的缓存并不限定于网络请求;它也可以被用于定时目的。

  例如,您可能需要在网页上给定一段时间后执行一个动作,来吸引用户对某个不容易引起注意的特定功能的关注或处理一个延时问题。 虽然setTimeout适合大多数用例,但在计时器出发后甚至理论上过期后就无法提供解决办法。 我们可以使用以下的缓存系统来处理:


代码如下:

var readyTime;
$(function() { readyTime = jQuery.now(); });
$.afterDOMReady = $.createCache(function( defer, delay ) {
delay = delay || 0;
$(function() {
var delta = $.now() - readyTime;
if ( delta >= delay ) { defer.resolve(); }
else {
setTimeout( defer.resolve, delay - delta );
}
});
});

新的afterDOMReady辅助方法用最少的计数器提供了domReady后的适当时机。 如果延迟已经过期,回调会被马上执行。

同步多个动画
  动画是另一个常见的异步任务范例。 然而在几个不相关的动画完成后执行代码仍然有点挑战性。尽管在jQuery1.6中才提供了在动画元素上取得promise对象的功能,但它是很容易的手动实现:


代码如下:

$.fn.animatePromise = function( prop, speed, easing, callback ) {
var elements = this;
return $.Deferred(function( defer ) {
elements.animate( prop, speed, easing, function() {
defer.resolve();
if ( callback ) {
callback.apply( this, arguments );
}
});
}).promise();
};

然后,我们可以使用$.when()同步化不同的动画:

代码如下:

var fadeDiv1Out = $( "#div1" ).animatePromise({ opacity: 0 }),
fadeDiv2In = $( "#div1" ).animatePromise({ opacity: 1 }, "fast" );

$.when( fadeDiv1Out, fadeDiv2In ).done(function() {
/* both animations ended */
});

我们也可以使用同样的技巧,建立了一些辅助方法:

代码如下:

$.each([ "slideDown", "slideUp", "slideToggle", "fadeIn", "fadeOut", "fadeToggle" ],
function( _, name ) {
$.fn[ name + "Promise" ] = function( speed, easing, callback ) {
var elements = this;
return $.Deferred(function( defer ) {
elements[ name ]( speed, easing, function() {
defer.resolve();
if ( callback ) {
callback.apply( this, arguments );
}
});
}).promise();
};
});

然后想下面这样使用新的助手代码来同步动画:

代码如下:

$.when(
$( "#div1" ).fadeOutPromise(),
$( "#div2" ).fadeInPromise( "fast" )
).done(function() {
/* both animations are done */
});

一次性事件
  虽然jQuery提供你可能需要的所有的时间绑定方法,但当事件仅需要处理一次时,情况可能会变得有点棘手。( 与$.one() 不同 )

  例如,您可能希望有一个按钮,当它第一次被点击时打开一个面板,面板打开之后,执行特定的初始化逻辑。 在处理这种情况时,人们通常会这样写代码:

代码如下:

var buttonClicked = false;
$( "#myButton" ).click(function() {
if ( !buttonClicked ) {
buttonClicked = true;
initializeData();
showPanel();
}
});

不久后,你可能会在面板打开之后点击按钮时添加一些操作,如下:

代码如下:

if ( buttonClicked ) { /* perform specific action */ }

这是一个非常耦合的解决办法。 如果你想添加一些其他的操作,你必须编辑绑定代码或拷贝一份。 如果你不这样做,你唯一的选择是测试buttonClicked。由于buttonClicked可能是false,新的代码可能永远不会被执行,因此你 可能会失去这个新的动作。

  使用deferreds我们可以做的更好 (为简化起见,下面的代码将只适用于一个单一的元素和一个单一的事件类型,但它可以很容易地扩展为多个事件类型的集合):

代码如下:

$.fn.bindOnce = function( event, callback ) {
var element = $( this[ 0 ] ),
defer = element.data( "bind_once_defer_" + event );
if ( !defer ) {
defer = $.Deferred();
function deferCallback() {
element.unbind( event, deferCallback );
defer.resolveWith( this, arguments );
}
element.bind( event, deferCallback )
element.data( "bind_once_defer_" + event , defer );
}
return defer.done( callback ).promise();
};

该代码的工作原理如下:

•检查该元素是否已经绑定了一个给定事件的deferred对象
•如果没有,创建它,使它在触发该事件的第一时间解决
•然后在deferred上绑定给定的回调并返回promise
  代码虽然很冗长,但它会简化相关问题的处理。 让我们先定义一个辅助方法:

代码如下:

$.fn.firstClick = function( callback ) {
return this.bindOnce( "click", callback );
};

然后,之前的逻辑可以重构如下:

代码如下:

var openPanel = $( "#myButton" ).firstClick();
openPanel.done( initializeData );
openPanel.done( showPanel );

如果我们需要执行一些动作,只有当面板打开以后,所有我们需要的是这样的:


代码如下:

openPanel.done(function() { /* perform specific action */ });

如果面板没有打开,行动将得到延迟到单击该按钮时。

组合助手
  单独看以上每个例子,promise的作用是有限的 。 然而,promise真正的力量是把它们混合在一起。

在第一次点击时加载面板内容并打开面板

  假如,我们有一个按钮,可以打开一个面板,请求其内容然后淡入内容。使用我们前面定义的助手方法,我们可以这样做:


代码如下:

var panel = $( "#myPanel" );
panel.firstClick(function() {
$.when(
$.get( "panel.html" ),
panel.slideDownPromise()
).done(function( ajaxResponse ) {
panel.html( ajaxResponse[ 0 ] ).fadeIn();
});
});

在第一次点击时载入图像并打开面板

  假如,我们已经的面板有内容,但我们只希望当第一次单击按钮时加载图像并且当所有图像加载成功后淡入图像。HTML代码如下:


代码如下:

<div id="myPanel">
<img data-src="image1.png" />
<img data-src="image2.png" />
<img data-src="image3.png" />
<img data-src="image4.png" />
</div>

我们使用data-src属性描述图片的真实路径。 那么使用promise助手来解决该用例的代码如下:


代码如下:

$( "#myButton" ).firstClick(function() {
var panel = $( "#myPanel" ),
promises = [];
$( "img", panel ).each(function() {
var image = $( this ), src = element.attr( "data-src" );
if ( src ) {
promises.push(
$.loadImage( src ).then( function() {
image.attr( "src", src );
}, function() {
image.attr( "src", "error.png" );
} )
);
}
});

promises.push( panel.slideDownPromise() );

$.when.apply( null, promises ).done(function() { panel.fadeIn(); });
});

这里的窍门是跟踪所有的LoadImage 的promise,接下来加入面板slideDown动画。 因此首次点击按钮时,面板将slideDown并且图像将开始加载。 一旦完成向下滑动面板和已加载的所有图像,面板才会淡入。

在特定延时后加载页面上的图像
  假如,我们要在整个页面实现递延图像显示。 要做到这一点,我们需要的HTML的格式如下:


代码如下:

<img data-src="image1.png" data-after="1000" src="placeholder.png" />
<img data-src="image2.png" data-after="1000" src="placeholder.png" />
<img data-src="image1.png" src="placeholder.png" />
<img data-src="image2.png" data-after="2000" src="placeholder.png" />

意思非常简单:

•image1.png,第三个图像立即显示,一秒后第一个图像显示
•image2.png 一秒钟后显示第二个图像,两秒钟后显示第四个图像
  我们将如何实现呢?

代码如下:

$( "img" ).each(function() {
var element = $( this ),
src = element.attr( "data-src" ),
after = element.attr( "data-after" );
if ( src ) {
$.when(
$.loadImage( src ),
$.afterDOMReady( after )
).then(function() {
element.attr( "src", src );
}, function() {
element.attr( "src", "error.png" );
} ).done(function() {
element.fadeIn();
});
}
});

如果我们想延迟加载的图像本身,代码会有所不同:

代码如下:

$( "img" ).each(function() {
var element = $( this ),
src = element.attr( "data-src" ),
after = element.attr( "data-after" );
if ( src ) {
$.afterDOMReady( after, function() {
$.loadImage( src ).then(function() {
element.attr( "src", src );
}, function() {
element.attr( "src", "error.png" );
} ).done(function() {
element.fadeIn();
});
} );
}
});

这里,我们首先在尝试加载图片之前等待延迟条件满足。当你想在页面加载时限制网络请求的数量会非常有意义。

结论
  正如你看到的,即使在没有Ajax请求的情况下,promise也非常有用的。通过使用jQuery 1.5中的deferred实现 ,会非常容易的从你的代码中分离出异步任务。 这样的话,你可以很容易的从你的应用程序中分离逻辑。

(0)

相关推荐

  • jquery SweetAlert插件实现响应式提示框

    jquery弹出层插件,支持消息提示.错误提示.确认框提示等.交互体验度非常好,大家都用微信支付.支付宝等完成用户体验度非常的不错.本插件至少要支持IE9+.使用方式也非常的简单.粗暴,很符合大众的jquery插件使用方法. 先给大家演示效果: 在线预览    源码下载 代码如下: <h1>Sweet Alert</h1> <h2>A beautiful replacement for JavaScript's "Alert"</h2>

  • 使用Chart.js图表库制作漂亮的响应式表单

    入门基础 Chart.js是一个基于HTML5的开源图表库,可以方便简洁的绘制美观的图表. 主要特性包括: 1.支持6种不同的表格类型:曲线图.柱状图.饼状图.雷达图.极坐标区域图.环图. 2.基于HTML5开发,支持所有浏览器(包括IE7/8). 3.不依赖于其他任何库,仅有4.5k大小,并且可以进行定制. Chart.js 是一个基于 HTML5 canvas 的响应式.灵活的.轻量化的图表库.库中提供了六种不同的图表类型,每种类型都带有一系列的自定义选项.如果这些还不够,你还可以创造自己的

  • jQuery插件slick实现响应式移动端幻灯片图片切换特效

    jQuery响应式手机端移动端幻灯片图片切换特效插件slick,基于jQuery,功能非常强大,支持左右按钮切换.支持圆点切换.支持自定义切换数量,支持自定义切换速度.支持图片预加载.支持自动播放定义,效果非常的不错,众多的参数自定义支持,觉得可以的可以参考他们的参数配置,还是值得学习使用的. 使用方法: 1.加载插件和jQuery <script src="//code.jquery.com/jquery-1.11.0.min.js"></script> &l

  • CSS3+Js实现响应式导航条

    今天制作了一个响应式导航条,能够自动随着不同的屏幕分辨率或浏览器窗口大小的不同而改变导航条的样式,这里主要用到的就是CSS3的Media Query.具体可以查看浅谈响应式布局这篇文章,这里就不花费大量的篇幅介绍了,主要看一下这个导航条该怎么做. 另外需要提到的是,ie6-ie8是不支持CSS3的Media Query的,因此对于ie6-ie8我们需要特殊处理,就让他们保持默认样式,这对于布局及样式上都要考虑到这一点. 首先看一下布局这一块,html代码如下: 复制代码 代码如下: <div c

  • Bootstrap Metronic完全响应式管理模板之菜单栏学习笔记

    继续上一篇,针对Bootstrap Metronic菜单栏整理的笔记分享给大家,供大家参考,具体内容如下 1.简介 1)  .环境配置 2)  .提取页面 3).动态生成菜单(无限级别树) 2.系统环境配置  项目需要程序数据支撑,这里选择MVC5.0+EF6.0[SQLSERVER](不对MVC架构和SQLServer做出解读)  运行环境:VS2013+MVC5.0+EF6.1+SQLServer2012  解决方案名称:AppSolution 项目名称:App.Web(UI层)与App.M

  • CSS图片响应式 垂直水平居中

    我看最近微博流行CSS居中技术,我看了几编资料写的都不多好,于是抽时间把相关资料整合了,具体内容如下. 点击此处下载源码 效果展示: 要求: 1.尽可能兼容更多浏览器,这里兼容到ie7,ie6不支持max-*就不考虑了. 2.浏览器尺寸变化时,图片总是等比例拉伸或缩放. 3.包裹图片的div也是响应式的,并且每个div的尺寸是一样的. 4.图片始终保持水平垂直居中. 5.图片的行列数不变,这里一直都是3*3. 下面来搞定一个个要求. 满足要求1意味着这里要尽量不使用高级浏览器才有的属性,比如高级

  • 8款非常棒的响应式jQuery 幻灯片插件推荐

    这篇文章收集了8款优秀的响应式 jQuery 幻灯片插件,它们能够非常容易的集成到 Web 项目中.响应式(Responsive)设计的目标是要让产品界面能够响应用户的行为,根据不同终端设备自动调整尺寸,带给用户良好的使用体验. Flexslider FlexSlider 是一款非常棒的响应式 jQuery 幻灯片插件,能够自适应屏幕尺寸,呈现漂亮的外观. Blueberry Blueberry 是一款开源的 jQuery 图片幻灯片插件,适用于流体.响应式网页布局. unoslider 特别推

  • 原生JS实现响应式瀑布流布局

    原生JS实现的瀑布流布局,代码及demo代码地址:https://github.com/leozdgao/responsive_waterfall Demo:http://leozdgao.github.io/demo/responsive_waterfall/ 演示图: 核心代码: responsive_waterfall.js (function() { var Waterfall = function(opts) { var minBoxWidth; Object.defineProper

  • 几种响应式文字详解

    讲真,其实我也不知道该如何为此篇开头, 因为响应式文字需不需要做其实我也没有深入探究过, 但在学习其他网站的过程中,我发现了一些比较新奇的做法,所以想试着梳理一下, 为何会出现这种有些奇怪,可能实则非常奇妙的解决方案. 如果理解有偏差的地方,还望大佬们不吝赐教. 简单来说,响应式是为了让网页在各种显示设备上都有不错的浏览体验, 无论是 @media 将元素换行,后台获取 userAgent 返回不同页面,利用 viewport 限定视图,还是利用根元素 html 属性来计算大小等, 他们都能实现

  • Bootstrap实现响应式导航栏效果

    为了给导航栏添加响应式特性,您要折叠的内容必须包裹在带有 classes .collapse..navbar-collapse 的 <div> 中.折叠起来的导航栏实际上是一个带有class .navbar-toggle 及两个 data- 元素的按钮.第一个是 data-toggle,用于告诉 JavaScript 需要对按钮做什么,第二个是 data-target,指示要切换到哪一个元素.三个带有 class .icon-bar 的 <span> 创建所谓的汉堡按钮.这些会切换

随机推荐