我通常将所有JavaScript脚本放入一个文件中,例如scripts.js
(HTTP请求越少越好)。因此,正如预期的那样,某些页面需要一些脚本,有些则不需要。
要定位特定页面,我使用类似:
if ($("body#share").length > 0) {
// Place the logic pertaining to the page with ID 'share' here...
}
// The file / script continues...
其他或更好的建议?谢谢!
澄清:我不正在寻找将多个JS文件整合到一个大文件中并保留多个单独的JS文件之间的优缺点。对此的答案肯定是“取决于具体情况”(我们知道)。我的问题是,假设我的所有JS逻辑都放在一个大文件中,当加载相应的页面时,如何使特定的(大块)脚本只运行 ?我过去常常使用if ($('#id-of-target-element')) { /* run the script */}
;有更好的方法吗?
答案 0 :(得分:24)
我喜欢Paul Irish's approach ...你不必完全遵循它,但总体思路是非常可靠的。
对于您的示例,它可能看起来像这样
<强> HTML 强>
<body id="share">
您的网页专用javascript
YourNamespace = {
share : {
init : function(){
// Place the logic pertaining to the page with ID 'share' here...
}
}
}
保罗爱尔兰人的Javascript使魔术成为现实
UTIL = {
fire : function(func,funcname, args){
var namespace = YourNamespace; // indicate your obj literal namespace here
funcname = (funcname === undefined) ? 'init' : funcname;
if (func !== '' && namespace[func] && typeof namespace[func][funcname] == 'function'){
namespace[func][funcname](args);
}
},
loadEvents : function(){
var bodyId = document.body.id;
// hit up common first.
UTIL.fire('common');
// do all the classes too.
$.each(document.body.className.split(/\s+/),function(i,classnm){
UTIL.fire(classnm);
UTIL.fire(classnm,bodyId);
});
UTIL.fire('common','finalize');
}
};
// kick it all off here
$(document).ready(UTIL.loadEvents);
因此,您在上面直接看到的行将启动以下
YourNamespace.common.init()
YourNamespace.share.init()
YourNamespace.common.finalize()
阅读他的博客文章以及与之相关的一些变体。
答案 1 :(得分:12)
类似的questions已经被问到,正确答案是,并且始终是
这取决于具体情况。
但是,如果您关注的是minimizing the round-trip time(RTT),那么可以肯定
将外部脚本组合到尽可能少的文件中 RTT和下载其他资源的延迟。
保持尽可能少是件好事,但您不一定非必须将其严格保存在一个文件中。
让我们来看看它为何如此。
虽然将代码分区为模块化软件组件是一件好事 工程实践,将模块导入一个HTML页面 时间可以大大增加页面加载时间。首先,对于有客户 如果是空缓存,浏览器必须为每个缓存发出HTTP请求 资源,并产生相关的往返时间。其次,大多数 浏览器会阻止页面的其余部分加载 正在下载和解析JavaScript文件。
这些图片更清楚地表明为什么将大量JavaScript文件合并到较少的输出文件中可以大大减少延迟:
所有文件都是按顺序下载的,总共需要4.46秒才能完成。
将13个js文件折叠为2个文件后: 相同的729千字节现在只需1.87秒即可下载
Siku-Siku.Com澄清后编辑: 抱歉!我完全误解了你的问题。我不知道任何更好的方法,只有在加载相应的页面时才能运行特定的(块)脚本。我认为你的方式已经足够好了。
答案 2 :(得分:5)
您的建议似乎没问题。但是,我会使用HTML 5 data- attribute标记每个页面,如下所示:
<body data-title="my_page_title">
然后,您可以通过检查此属性(jQuery 1.4.3以后)来编写条件javascript代码:
if ($("body").data("title") === "my_page_title") {
// Place the logic pertaining to the page with title 'my_page_title' here...
}
这允许您以合理的方式系统地对特定页面的所有代码进行分组
答案 3 :(得分:5)
另一种选择是你可以在HTML代码中
<script>
callYourJSFunctionHere(); /*Things you would want to happen on Page load*/
</script>
这将遵循页面的正常流程。因此,如果您正在使用页面上的元素,则在浏览器加载所有元素之后,您需要将此<script>
部分放在页面底部。
我不是100%确定这比你现有的解决方案更有效,但另一方面,它会告诉有人在查看你的HTML页面时页面加载时会运行什么JavaScript。这可能对维护道路有所帮助....没有那么多关于页面加载时脚本运行的猜测游戏。
希望这有帮助!
答案 4 :(得分:3)
确定。让希望,代码示例会说它比文本墙更好:
您的one-and-only.js
文件:
var MY_SITE = {
// you have one namespace-object where you hold all your stuff
main_page: {
// inside you have smaller chunks, for specific pages or widgets
// this one is for main page
_init: function () {
...
},
...
showSplashScreen: function () {
...
}
},
...
// but there are other pages
contacts: { ... },
// or widgets
cool_menu: { ... },
// and maybe you want to put common functions into dedicated block
global_utilities: { ... },
// and of course - the loader
_start: function () {
// here we simply call one _init of the page module that was specified
this[PAGE_TYPE]._init();
// and more tricky stuff - we can search the page for elements
// that contain special data-attribute, collect them
var widgets = $('[data-our-widget]').each().getAttributeValue( 'data-or-widget' );
// and then _init each of those widgets just like we did with main page
widgets.forEach( function (v) {
this[v]._init();
}
}
};
document.on('ready', MY_SITE.start); // here we assume some random js framework
页面上的<script>
标记:
<script>var PAGE_TYPE = 'main_page';</script>
<script src="one-and-only.js" />
页面上的'magic'元素:
<div id="whatever" data-our-widget="cool_menu"> ... </div>
免责声明: 这是高级概述!实施细节可能而且应该有所不同,具体取决于您的需求。
答案 5 :(得分:2)
您的问题是询问如何仅根据特定页面加载脚本块。但是,由于您声明的目标是最小化http请求(以及流量,我认为),我认为我的独特(复杂)实现至少与此问题相关,如果不是您的方法的良好替代/补充。
我在嵌入式应用程序中使用它,我将所有javascript文件合并为一个大文件以减少http请求。我不得不想出一个缓存方法。在使用准系统50kb网络服务器时,除了几个体面大小的图像外,还需要一段120kb的javascript文件加载。
首先,我使用YUI Compressor来压缩我的javascript文件,因为这是节省带宽的简单方法。
我发现一个很酷的“功能”,如果你链接到任何东西(css,js,img),如下所示,你只需加载文件并忽略“?”之后的参数。在'src':
<script type="text/Javascript" src="js/all.js?2382a97f099f42cc43c1b616cd24f281"></script>
现在,看似随意混乱的数字和字母实际上是javascript文件的md5校验和!然后,我将相关扩展(css,js,img等)的服务器响应头修改为永不过期。此标头不会发送给html文件,因为我们总是想要这些文件的最新版本。
Cache-Control:max-age=290304000
这意味着客户端将只加载一次javascript文件,直到校验和更改为止。缓存通过查找整个请求(包括文件参数)来工作。
我实际上是用C代码编译我的html / js / css / image文件,所以我有一个perl脚本在编译之前自动将这些md5校验和插入到html文件中。这显然不适用于您的情况,但您可以使用任意数量的方式来处理它,只要您有一个服务器端语言来帮助您。例如,你可以让PHP动态计算校验和,或者你可以让php将校验和存储在数据库或平面文件中以便轻松查找它们。为了标记php重新计算校验和,您可以检查文件时间,或删除数据库条目/平面文件。
我意识到这是很多前期工作,可能不是你所追求的,但它对我来说非常有效。奇妙。对我而言,性能提升是令人难以置信的。第一页加载速度非常慢(8.5秒),但在此之后,所有脚本,css和图像都会立即缓存。同一应用程序中的新页面加载下降到~300ms。
答案 6 :(得分:2)
正如您所正确提到的,分裂/组合文件的想法确实取决于具体情况。
我认为你所做的事情不会有更好的解决方案,因为我看到许多大型网站实施类似的策略,尽管CSS比js更多。
例如(Facebook的摘录):
<body class="hasLeftCol home fbx hasSlimHeader safari4 win Locale_en_US defaultScrollbar">
您可以从中获得更多优势。您可以使用class属性有选择地将一些JS代码应用于页面组。
即。
if $('body.pagesThatHaveThisClass').length > 0)
{.... code ...}
if $('body#singlePageWithThisId').length > 0)
{.... code ...}
另外,有一种技术可以使用许多基于JS / jQ的菜单来自动为当前页面提供不同的样式。您可以将window.location与特定地址匹配。
即
if (window.top.location.href == 'http://domain.com/mypage1.html')
{ .... code ....}
甚至
switch (window.top.location.href)
{
case 'http://domain.com/mypage1.html' :
{ .... code ....}
case 'http://domain.com/mypage2.html' :
{ .... code ....}
}
我仍然更喜欢你的技术,因为你可以将多个页面的代码组合在一起。我可以想到使用第二种方法的唯一原因是当JS人员无法访问页面的HTML以更改类/ id等时。
希望这就是你要找的东西!
答案 7 :(得分:2)
如何测试window.location
?对我来说这似乎是显而易见的方式。
或者正如您已经做过的那样,测试所需的元素。这是一个相当强大的方法,我认为没有错。
答案 8 :(得分:1)
这将是一个高级概述,但我建议使用Backbone来组织每个“视图”(或页面)的逻辑。我使用根元素并更改要切换的元素的类在布局的其他视图(或状态)之间。然后,您可以按类组织辅助样式,并在ID下保留主要样式。
HTML
<div id="layout" class="default">
<!-- PUT DEFAULT HTML IN HERE -->
</div>
<script id="shareTemplate" type="text/html">
<!-- PUT SHARE HTML IN HERE -->
</script>
CSS
#layout {
/* primary style */
}
#layout.share {
/* secondary style */
}
的JavaScript
window.LayoutView = Backbone.View.extend({
el: "#layout",
shareTemplate: _.template($("#shareTemplate").html()),
initialize: function() {
this.render(shareTemplate, data);
this.el.className = "share";
},
render: function(template, data) {
$(this.el).html(template(data));
return this;
}
});
window.Layout = new LayoutView;
答案 9 :(得分:1)
基于以下假设:您网站上的所有不同网页都明确或至少在逻辑上分组为不同的“视图模型”,并为不同类型的网页提供不同的视图模型(例如“搜索结果”,“博客帖子” “,”首页“,”单个博客“等等,您可以拥有一个包含所有网站共同脚本的javascript文件,以及每个视图模型特有的脚本(如果您认为有必要)。 / p>
然后,您可以让服务器将视图模型的名称插入到HTML数据标记中,供以后使用,以及主脚本库之后的附加脚本标记。
例如:
<head>
<!--
Two JavaScript files, one for the common functionality,
and one for the view model specfic
-->
<script type="text/javascript" src="path/to/scriptslib.js"></script>
<script type="text/javascript" src="path/to/viewmodel.front_page.js"></script>
</head>
<body data-view-model="front_page">
...
</body>
在scriptslib.js
:
var
GlobalSettings = {},
ViewModel = {};
$(function () {
// Save the view model in a variable when the body's been loaded
GlobalSettings.viewModel = $("body").attr("data-view-model");
// Assuming that the viewmodel JavaScript file has been loaded, call a method that it'll have by convention here
ViewModel.initialize();
// Additionally, you can later test for specific view models and perform necessary actions, if needed
if (viewModel === "front_page") {
// ...
}
});
然后,在viewmodel.front_page.js
(或任何其他视图模型文件)中:
ViewModel.FrontPage = {
// data and methods specific for this view model
}
ViewModel.initialize = function () {
// do stuff specific for this view model
this.FrontPage.someFunction();
};
请注意,我在这里描述方法的方式是针对依赖页面重新加载以在页面之间切换的网站。如果您使用Ajax在页面之间切换,则需要JavaScript动态加载新视图模型并执行它们。
希望这对你有用;)
答案 10 :(得分:0)
你可以按照你的方法,但假设你的“鸡尾酒”javascript文件有20k行代码,你把它包含在你所有的html文件中,即使是那些显示“404”或“500”的文件,也不会使用更多不必要的带宽?
我选择为每个HTML页面使用不同的js,并且在多个页面中使用的任何内容都将它转储到“utils.js”或任何你想要调用它的地方,例如
\www
\pages
\index.html
\dashboard.html
\account.html
\ ...
\scripts
\index.js <- for index.html
\dashboard.js <- for dashboard.html
\account.js <- for account.html
\ ...
\utils.js|shared.js|sharedlib.js <- used by all pages
所以基本上会导致:
这只是我的两分钱..