一段时间以来,我一直在使用enquire.js库来增强JavaScript中媒体查询的使用。 我在各种项目中使用该库取得了许多成功,但是我遇到的大多数开发人员都承认他们从未使用过,甚至从未听说过它。
在本文中,我想向您介绍该库,解释为什么以及如何使用它。
enquire.js是一个轻量级的纯JavaScript库,用于响应CSS媒体查询。
用我自己的话说,在JavaScript中使用媒体查询时,enquire.js在window.matchMedia()
之上为您提供了其他功能和灵活性。
该库是由尼克·威廉姆斯(Nick Williams)编写的,它已经存在了大约三年,拥有大量的开源活动 。 它的目的不是替换或matchMedia
; 相反,它可以为媒体查询提供其他功能,而这些功能本来就不存在。
有很多可以使用enquire.js的用例,包括:
以下各节介绍了这些用例中的每一个。
尽管使用JavaScript操纵DOM时需要考虑一些性能和可维护性,但仍有许多原因会这样做。
假设在您的博客上,您的个人简历中的边栏中有图片。 在小屏幕上,侧边栏是隐藏的-但您仍然希望个人简介在帖子末尾可见。 无需复制生物(和图像)标记,而是可以根据屏幕大小在DOM周围移动它,从而避免标记重复。 这是一个例子:
window.$ = document.querySelector.bind(document);
enquire.register("screen and (max-width:40em)", {
match: function() {
$(".Post-content").appendChild($(".Bio"));
},
unmatch: function() {
$(".Sidebar").insertBefore($(".Bio"), $(".Sidebar").firstChild);
}
});
该示例的实时演示如下所示:
请参阅CodePen上的SitePoint( @SitePoint )提供的Pen MwNYjp 。
这是一个简单的示例,说实话,它所做的不过是原生matchMedia()
提供的功能。 实际上,这是仅使用matchMedia()
:
window.$ = document.querySelector.bind(document);
(function() {
var mq = window.matchMedia("(min-width:40em)");
mq.addListener(positionBio);
function positionBio(mediaQuery) {
if (mediaQuery.matches) {
$(".Sidebar").insertBefore($(".Bio"), $(".Sidebar").firstChild);
} else {
$(".Post-content").appendChild($(".Bio"));
}
}
// On load
positionBio(mq);
}());
该示例的实时演示如下所示:
请参阅CodePen上的SitePoint( @SitePoint )提供的Pen WvVbor 。
让我们回到enquire.js,并从上一步开始进一步举例。 在下面的代码中,我们将使用setup
功能。 该函数在执行enquire.register
后立即运行一次。 在示例中,我们还将缓存一些选择器,以提高代码的性能,并使代码更具可读性和可维护性。 虽然这是一个人为的示例(并且您可以在没有enquire.js的情况下进行相同的操作),但它使我能够向您介绍setup
功能并探索更复杂的示例:
window.$ = document.querySelector.bind(document);
enquire.register("screen and (max-width:40em)", {
setup: function() {
this.bio = $(".Bio");
this.content = $(".Post-content");
this.sidebar = $(".Sidebar");
},
match: function() {
this.content.appendChild(this.bio);
},
unmatch: function() {
this.sidebar.insertBefore(this.bio, this.sidebar.firstChild);
}
});
该示例的实时演示如下所示:
请参阅CodePen上的SitePoint( @SitePoint )提供的Pen MwNYbp 。
让我们将注意力集中在另一个用例上:根据视口的大小通过Ajax加载广告内容。 此示例再次使用setup()
函数,并引入了enquire.js的另一个功能: deferSetup()
。 它还使用reqwest Ajax库 (此处没有拼写错误)和classList
API来演示如何在没有jQuery的情况下编写更复杂的示例。 如果您不知道此API的功能,则可以阅读Exploring the classList API文章。
在下一个示例中,在setup
方法内(提醒您,此媒体查询匹配时,该方法仅运行一次),我们使用jQuery的ajax()
方法请求页面ad.html
并将结果存储在ad
属性中。 然后,我们将.Ad
的内容设置为属性,并通过添加is-visible
类(使用CSS处理)来显示容器。
如果媒体查询“不匹配”,我们将删除is-visible
类,该类将反过来隐藏.Ad
容器。
最后,我们将deferSetup
标志与setup()
方法一起使用,以便Ajax请求仅发生一次,并且仅在媒体查询匹配时发生。 这很有用,因为对Ajax的调用被延迟到需要信息为止,而不是发出过早的请求。
实现我刚才描述的代码的报告如下:
window.$ = document.querySelector.bind(document);
enquire.register("screen and (min-width:40em)", {
deferSetup: true,
setup: function() {
this.ad = "";
this.adContainer = $(".Ad");
this.visibleClass = "is-visible";
this.adUrl = "//codepen.io/damonbauer/pen/LVgxxN.html";
reqwest({ url: this.adUrl, crossOrigin: true})
.then(function(response) {
this.ad = response;
}.bind(this)).fail(function() {
this.ad = "Ad could not be loaded.";
}.bind(this)).always(function(response) {
this.adContainer.innerHTML = this.ad;
}.bind(this));
},
match: function() {
this.adContainer.classList.add(this.visibleClass);
},
unmatch: function() {
this.adContainer.classList.remove(this.visibleClass);
}
});
除了之前的JavaScript代码,我们还必须使用下面报告的CSS小片段:
.Ad {
display: none;
}
.is-visible {
display: block;
}
该示例的实时演示如下所示:
请参阅CodePen上的SitePoint( @SitePoint )的Pen vOoEyb 。
在本节中,我们将介绍添加Packery库以增强较大尺寸的页面。 根据其文档 ,Packery“填补了空白”。 它可以帮助您完成类似于Pinterest布局的工作,在该布局中,卡片填充了网格中的可用空间。
假设您的页面中包含以下HTML:
<div id="Container">
<div class="Item">...</div>
<div class="Item">...</div>
<div class="Item">...</div>
...
</div>
以下代码将使用packery库来实现我之前描述的内容:
enquire.register("screen and (min-width:30em)", {
deferSetup: true,
setup: function() {
this.container = $( "#Container" );
},
match: function() {
this.container.packery({
itemSelector: '.Item'
});
},
unmatch: function() {
this.container.packery('destroy');
}
});
该示例的实时演示如下所示:
请参阅CodePen上的SitePoint( @SitePoint )提供的Pen OVKPWL 。
这与第一个示例非常相似。 首先,将容器作为属性存储在setup()
方法中。 然后,如果媒体查询匹配,它将按照packery
约定布置项目; 否则,我们通过调用packery
的destroy
方法来破坏该packery
实例。
此示例的潜在用例可能是将平板电脑从横向旋转到纵向。 也许我们已经确定屏幕太窄而无法以某种方式显示项目,所以我们可以选择垂直堆叠项目。
希望您对enquire.js的使用速度和功能有所了解。 我想分享几个使用该库时遇到问题的实例。
虽然它不完全支持IE8,但我可以告诉您,我建立的网站没有任何破坏渲染的JavaScript错误。 Enquire.js取决于matchMedia
API,Internet Explorer 10之前的版本不支持该API。如果必须支持此类浏览器,建议您使用Paul Irish编写的matchMedia polyfills 。
为此,您必须加载enquire.js 之前提供的文件。 此外,我建议您将这些脚本放在IE条件注释中,如下所示:
<!--[if lte IE 9]>
<script src="/path/to/matchMedia.js"></script>
<script src="/path/to/matchMedia.addListener.js"></script>
<![endif]-->
由于采用了这种方法,只有需要填充的浏览器才会加载它们。 重要的是要强调一点,即使将它们加载到支持这些功能的浏览器中,由于两个脚本都是以非侵入方式编写的,因此您仍将具有本机实现。 这意味着在执行任何代码之前,它们将检测浏览器是否本机支持这些功能。 在这种情况下,将完全跳过polyfill代码。
在上面的示例之一中,我展示了如何使用enquire.js来操纵DOM。 虽然这项技术有效,但我建议在使用该技术时要谨慎。 请注意,在多个enquire.js match
和unmatch
match
方法中添加了大量DOM更改,因为您添加的操作越多,如果出现问题,调试页面就越困难。 另外,由于操作DOM通常很慢,因此使用此技术可能会导致页面混乱和性能下降 。
我的建议是使用enquire.js“逐步”提供内容或功能,而不是依靠它来显示内容的关键部分。 我的建议是首先显示基本内容,然后使用enquire.js对其进行增强,而不是依赖于所有要增强的内容。
以页面增强为例,默认情况下,项目网格是可见的。 如果屏幕足够大,则使用Packery.js库对项目进行布局。 这样可以确保即使由于某种原因(例如JavaScript损坏,连接速度慢等)未执行JavaScript,用户仍然可以使用内容。
如今,使用移动优先方法来构建网站是一种常见且建议的做法。 如果您需要支持的浏览器无法理解媒体查询(例如IE8),则enquire.js带有一个名为shouldDegrade
的参数非常有用。 它指定如果浏览器不了解媒体查询,则应始终执行enquire.register
块的结果。 默认情况下,它的值设置为false
但是您可以将其更改为true
以适合您的需求。
以下是使用此参数的示例:
enquire.register("screen and (min-width:40em)", function() {
// execute some code for large-screen devices
}, true); // note the true!
通过使用这样的代码片段,您仍然可以构建移动优先的网站并支持较旧的浏览器来获得桌面体验。 我的建议是使用此参数或上面提到的polyfill,而不是同时使用。
在本文中,我向您介绍了enquire.js,这是一个用纯JavaScript编写的功能强大的库,用于响应CSS媒体查询。 希望我已经向您演示了它如何在本机matchMedia()
方法之上为您提供额外的功能,从而使您能够跨所有屏幕尺寸构建性能matchMedia()
,功能丰富的网站。 虽然这还不是库的详尽概述,但这应该足以促使您进一步了解它,并考虑在项目中是否有放置它的地方。
您听说过enquire.js吗? 您是否曾尝试在项目中使用它? 那你的结果呢? 在下面分享您的评论,让我们开始讨论!