Javascript 多个页面的一个 JS 文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8410298/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 05:54:02  来源:igfitidea点击:

One JS File for Multiple Pages

javascriptfilesystems

提问by moey

I typically put all the JavaScript scripts into one file e.g. scripts.js(the less HTTP request, the better). So, as expected, some scripts are needed for some pages, some aren't.

我通常将所有 JavaScript 脚本放在一个文件中,例如scripts.js(HTTP 请求越少越好)。因此,正如预期的那样,有些页面需要一些脚本,有些则不需要。

To target a specific page, I use something like:

要定位特定页面,我使用以下内容:

if ($("body#share").length > 0) {
    // Place the logic pertaining to the page with ID 'share' here...
}

// The file / script continues...

Other or better suggestions? Thanks!

其他或更好的建议?谢谢!

Clarification:I was notlooking for the pros / cons between consolidating multiple JS files into one big file and keeping multiple separate JS files. The answer for this is surely 'depends on the situation' (we know that). My question is, assuming all my JS logic is placed into one big file, how do I make a particular (chunk of) script runs onlywhen the corresponding page is loaded? One way I used to do is using if ($('#id-of-target-element')) { /* run the script */}; is there a better way?

澄清:不是在寻找将多个 JS 文件合并为一个大文件和保留多个单独的 JS 文件之间的利弊。答案肯定是“视情况而定”(我们知道)。我的问题是,假设我所有的 JS 逻辑都放在一个大文件中,我如何使特定(块)脚本在加载相应页面时运行?我以前做的一种方法是使用if ($('#id-of-target-element')) { /* run the script */}; 有没有更好的办法?

采纳答案by Charlino

I like Paul Irish's approach... you don't have to follow it exactly, but the general idea is a very solid one.

我喜欢保罗爱尔兰的方法......你不必完全遵循它,但总体思路是非常可靠的。

It might look something like this for your example

对于您的示例,它可能看起来像这样

Html

html

<body id="share">

Your page specific javascript

您的页面特定的 javascript

YourNamespace = {
  share : {
    init : function(){
      // Place the logic pertaining to the page with ID 'share' here...
    }
  }
}

Paul Irish's Javascript that makes the magic happen

Paul Irish 的 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);

So the line you see directly above will kick off the following

所以你在上面直接看到的行将开始以下

YourNamespace.common.init()
YourNamespace.share.init()
YourNamespace.common.finalize()

Have a read of his blog post and a few of the variations linked from it.

阅读他的博客文章以及从中链接的一些变体。

回答by Sajib Mahmood

Similar questionshave been already asked and the correct answer was and always will be

已经提出了类似的问题,正确的答案是并且永远是

It depends on the situation.

这取决于实际情况。

However, if your concern is about minimizing the round-trip time(RTT) then it is certain that

但是,如果您关心的是最小化往返时间(RTT),那么可以肯定的是

Combining external scripts into as few files as possible cuts down on RTTs and delays in downloading other resources.

将外部脚本合并到尽可能少的文件中可以减少 RTT 和下载其他资源的延迟。

It is good to keep it as few as possible, but you don't necessarily have to keep it into one file strictly.

保持尽可能少是好的,但您不必严格将其保存在一个文件中。

Let's take a look at why it is so.

让我们来看看为什么会这样。

While partitioning code into modular software components is a good engineering practice, importing modules into an HTML page one at a time can drastically increase page load time. First, for clients with an empty cache, the browser must issue an HTTP request for each resource, and incur the associated round trip times. Secondly, most browsers prevent the rest of the page from from being loaded while a JavaScript file is being downloaded and parsed.

虽然将代码划分为模块化软件组件是一种很好的工程实践,但一次一个地将模块导入 HTML 页面会大大增加页面加载时间。首先,对于缓存为空的客户端,浏览器必须为每个资源发出 HTTP 请求,并产生相关的往返时间。其次,大多数浏览器会在下载和解析 JavaScript 文件时阻止加载页面的其余部分。

These images show it more clearly why combining a number of JavaScript files into fewer output files can dramatically reduce latency:

这些图像更清楚地说明了为什么将多个 JavaScript 文件组合成更少的输出文件可以显着降低延迟:

All files are downloaded serially, and take a total of 4.46 seconds to completeAll files are downloaded serially, and take a total of 4.46 seconds to complete.

所有文件都是串行下载的,总共需要 4.46 秒才能完成所有文件都是串行下载的,总共需要 4.46 秒才能完成。

After collapsing the 13 js files into 2 files: The same 729 kilobytes now take only 1.87 seconds to downloadThe same 729 kilobytes now take only 1.87 seconds to download

将 13 个 js 文件折叠成 2 个文件后: 相同的 729 KB 现在只需 1.87 秒即可下载同样的 729 KB 现在只需 1.87 秒即可下载

Edit after Clarification given by Siku-Siku.Com:Sorry! I totally misunderstood your question. I don't know of any betterway for making a particular (chunk of) script run only when the corresponding page is loaded. I think your way is good enough.

经 Siku-Siku.Com 澄清后编辑:对不起!我完全误解了你的问题。我不知道有什么更好的方法可以使特定(块)脚本仅在加载相应页面时运行。我觉得你的方法已经够好了。

回答by Wesley

Your suggestion seems OK. I would however use an HTML 5 data- attributeto tag every page like this:

你的建议看起来不错。但是,我会使用HTML 5 data- 属性来标记每个页面,如下所示:

<body data-title="my_page_title">

You can then write conditional javascript code by checking this property (jQuery 1.4.3 onwards):

然后,您可以通过检查此属性(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...
}

This allows you to systematically group all code for a certain page in a sensible way

这允许您以合理的方式系统地对某个页面的所有代码进行分组

回答by blo0p3r

Another option is that you could have, within the HTML code

另一种选择是您可以在 HTML 代码中

<script>
    callYourJSFunctionHere();  /*Things you would want to happen on Page load*/
</script>

This will follow the normal flow of the page. Therefore if you are playing with elements on the page, you will need to place this <script>portion at the bottom of the page, after all the elements have been loaded by the browser.

这将遵循页面的正常流程。因此,如果您正在使用页面上的元素,则需要<script>在浏览器加载所有元素后将此部分放置在页面底部。

I'm not 100% sure this is more efficient then the current solution you have, but on the other hand, it will be telling someone looking at your HTML page what JavaScript will be run when the page loads. This might be helpful in terms of maintenance down the road.... no so much a guessing game as to what script runs when the page loads.

我不是 100% 确定这比您当前的解决方案更有效,但另一方面,它会告诉正在查看您的 HTML 页面的人在页面加载时将运行哪些 JavaScript。这可能对以后的维护有所帮助.... 页面加载时运行的脚本与其说是猜谜游戏,不如说是猜谜游戏。

Hope this helps!

希望这可以帮助!

回答by c69

Ok. Lets hope, code example will say it better, than wall of text:

好的。让我们希望,代码示例比文字墙更能说明问题:



your one-and-only.jsfile:

你的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

your <script>tags on the page:

<script>在页面上的标签:

<script>var PAGE_TYPE = 'main_page';</script>
<script src="one-and-only.js" />

your 'magic'elements on the page:

您的“魔力”页面上的元素:

<div id="whatever" data-our-widget="cool_menu"> ... </div>


Disclaimer:This is high level overview! Implementation details may and should vary, depending on yourneeds.

免责声明:这是高级概述!实施细节可能并且应该有所不同,具体取决于您的需要。

回答by Gaurav Ramanan

As you've rightly mentioned, the idea of splitting / combining files really doesdepend on the situation.

正如您正确提到的,拆分/合并文件的想法确实取决于具体情况。

I don't think there can be a better solutionfor what you're doing, as I have seen many big websites implement a similar strategy albeit more for CSS than js.

我认为没有更好的解决方案可以解决您正在做的事情,因为我已经看到许多大型网站实施了类似的策略,尽管更多的是针对 CSS 而不是针对 js。

Eg (An excerpt from facebook):

例如(Facebook 的摘录):

<body class="hasLeftCol home fbx hasSlimHeader safari4 win Locale_en_US defaultScrollbar">

There is one more great advantage you can reap out of this. You can selectively apply some JS code into groups of pages using the class attribute.

您还可以从中获得另一大优势。您可以使用 class 属性有选择地将一些 JS 代码应用到页面组中。

ie.

IE。

if $('body.pagesThatHaveThisClass').length > 0)
{.... code ...}

if $('body#singlePageWithThisId').length > 0)
{.... code ...}

Else, there is a technique that many JS/jQ based menus use to automatically give a different style to the current page. You can match the window.location to specific a address.

另外,许多基于 JS/jQ 的菜单使用一种技术来自动为当前页面提供不同的样式。您可以将 window.location 与特定地址进行匹配。

ie.

IE。

if (window.top.location.href == 'http://domain.com/mypage1.html')
{ .... code ....}

or even

甚至

switch (window.top.location.href)
{
   case 'http://domain.com/mypage1.html' :
    { .... code ....}

   case 'http://domain.com/mypage2.html' :
    { .... code ....}

}

I would still prefer your technique as you can group code for multiple pages together. The only reason I can think of for using the second method is when the JS people don't have access to the HTML of the page to change the class / id etc.

我仍然更喜欢你的技术,因为你可以将多个页面的代码组合在一起。我能想到的使用第二种方法的唯一原因是当 JS 人员无法访问页面的 HTML 来更改类 / id 等时。

Hope this is what you were looking for!

希望这就是你要找的!

回答by Has QUIT--Anony-Mousse

How about testing window.location? That seems the obvious way for me.

测试window.location怎么样?这对我来说似乎是显而易见的方式。

Or as you already seem to do, test for the required elements to be there. That is a rather robust method, I see nothing wrong with that.

或者就像您已经做的那样,测试所需的元素是否存在。这是一种相当稳健的方法,我认为没有任何问题。

回答by Jeff Lamb

Your question is asking how to only load chunks of your scripts based upon a particular page. However, since your stated goal is minimizing http requests (and traffic, I assume), I think my unique (complicated) implementation is at least relevant to this question, if not a good alternative/complement to your approach.

您的问题是询问如何仅根据特定页面加载脚本块。但是,由于您声明的目标是最小化 http 请求(和我假设的流量),我认为我独特的(复杂的)实现至少与这个问题相关,如果不是您方法的一个很好的替代/补充。

I use this in an embedded application where I combine all javascript files into one large one for reducing http requests. I had to figure out a caching method as well. A 120kb javascript file in addition to several decently-sized images take a while to load when using a barebones 50kb webserver.

我在嵌入式应用程序中使用它,我将所有 javascript 文件合并为一个大文件以减少 http 请求。我还必须找出一种缓存方法。使用准系统 50kb 网络服务器时,一个 120kb 的 javascript 文件以及几个大小合适的图像需要一段时间才能加载。

First off, I use YUI Compressorto compress my javascript files, as that's an easy way to save bandwidth.

首先,我使用YUI Compressor来压缩我的 javascript 文件,因为这是一种节省带宽的简单方法。

A cool "feature" I discovered was if you link to anything (css, js, img) like the following, you'll simply load the file and ignore the parameters past the '?' in 'src':

我发现的一个很酷的“功能”是,如果您链​​接到如下所示的任何内容(css、js、img),您只需加载文件并忽略 '?' 之后的参数。在“源代码”中:

<script type="text/Javascript" src="js/all.js?2382a97f099f42cc43c1b616cd24f281"></script>

Now, that seemingly random jumble of numbers and letters is actually the md5 checksum of the javascript file! I then modified my server's response header for the correlated extensions (css, js, img, etc) to never expire. This header is not sent for html files, as we always want the latest versions of those.

现在,那看似随机的数字和字母的混乱实际上是 javascript 文件的 md5 校验和!然后,我修改了相关扩展(css、js、img 等)的服务器响应标头,使其永不过期。不会为 html 文件发送此标头,因为我们总是想要这些文件的最新版本。

Cache-Control:max-age=290304000

This means clients will load the javascript file once and only once until the checksum changes. Caching works by looking up the entire request, including file parameters.

这意味着客户端将只加载一次 javascript 文件,直到校验和更改。缓存的工作原理是查找整个请求,包括文件参数。

I'm actually compiling my html/js/css/image files in with C code, so I have a perl script automatically insert those md5 checksums into the html files before compiling. This obviously won't work in your case, but you can use any number of ways to handle it, as long as you have a server-side language to aid you. For example, you can have php calculate the checksum on-the-fly, or you can have php store the checksums in a database or flat file to easily look them up. In order to flag php to recalculate the checksum, you could check the filetime, or delete the database entries/flat file.

我实际上是用 C 代码编译我的 html/js/css/image 文件,所以我有一个 perl 脚本在编译之前自动将这些 md5 校验和插入到 html 文件中。这显然不适用于您的情况,但是您可以使用多种方法来处理它,只要您有一种服务器端语言来帮助您。例如,您可以让 php 即时计算校验和,或者您可以让 php 将校验和存储在数据库或平面文件中以便轻松查找。为了标记 php 重新计算校验和,您可以检查文件时间,或删除数据库条目/平面文件。

I realize this is a lot of upfront work and might not be what you're after, but it works wonderfullyfor me. The performance gains for me are incredible. The first page load is awfully slow (8.5 seconds), but after that, all your scripts, css, and images are all cached now. New page loads within the same application drop to ~300ms.

我意识到这是一个很大的前期工作,并可能不是你以后,但它的工作原理奇妙的我。对我来说,性能提升令人难以置信。第一个页面加载速度非常慢(8.5 秒),但在那之后,您所有的脚本、CSS 和图像现在都被缓存了。同一应用程序中的新页面加载下降到约 300 毫秒。

回答by Ryan

This is going to be a high level overview, but I recommend using Backboneto organize the logic for each "view" (or page.) I use a root element and change the class of that element to switch between the other views (or states) of the layout. You can then organize the secondary styles by class and keep a primary style under the ID.

这将是一个高级概述,但我建议使用Backbone来组织每个“视图”(或页面)的逻辑。我使用根元素并更改该元素的类以在其他视图(或状态)之间切换) 的布局。然后,您可以按类组织次要样式,并在 ID 下保留主要样式。

HTML

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

CSS

#layout {
    /* primary style */
}

#layout.share {
   /* secondary style */
}

JavaScript

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;

回答by Sune Rasmussen

Based on the assumption that all of the different pages on your site is categorically or at least logically grouped into different "view models", with a different view model for a different type of page (e.g. "search results", "blogposts", "front page", "single blogpost", etcetera), you could have a single javascript file that contains the scripts in common for all of your site, and one specific for each view model (if you deem it necessary).

基于以下假设:您网站上的所有不同页面都被分类或至少在逻辑上分组为不同的“视图模型”,不同类型的页面(例如“搜索结果”、“博客文章”、“首页”、“单个博客文章”等),您可以有一个 javascript 文件,其中包含您所有站点的通用脚本,以及一个特定于每个视图模型的脚本(如果您认为有必要)。

You could then have the server insert the name of the view model into, for instance, a HTML data-tag, for later use by JavaScript, and an additional script tag after the main script library.

然后,您可以让服务器将视图模型的名称插入到例如 HTML 数据标签中,供 JavaScript 稍后使用,并在主脚本库之后插入一个附加脚本标签。

For instance:

例如:

<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>

In scriptslib.js:

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") {
    // ...
  }
});

Then, in viewmodel.front_page.js(or any other view model file):

然后,在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();
};

Note, that the way I've described the approach here is for sites that rely on page reloads for shifting between pages. If you were using Ajax to shift between pages, you'd want JavaScript to dynamically load the new view models and execute them.

请注意,我在此处描述的方法适用于依赖页面重新加载以在页面之间切换的站点。如果您使用 Ajax 在页面之间切换,您会希望 JavaScript 动态加载新的视图模型并执行它们。

Hope this could work for you ;)

希望这对你有用;)