javascript-多个页面的一个JS文件

我通常将所有JavaScript脚本放到一个文件中,例如 if ($('#id-of-target-element')) { /* run the script */}(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 */}; 有没有更好的办法?

moey asked 2020-06-30T02:41:24Z
11个解决方案
24 votes

我喜欢保罗·爱尔兰(Paul Irish)的方法...您不必完全遵循它,但是总体思路是非常扎实的。

您的示例可能看起来像这样

HTML

<body id="share">

您的网页专用javascript

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

保罗·爱尔兰(Paul Irish)的Java语言,使魔术得以实现

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

阅读他的博客文章,以及与之相关的一些变化。

Charlino answered 2020-06-30T02:41:59Z
12 votes

已经问过类似的问题,正确的答案一直是而且永远都是

这取决于实际情况。

但是,如果您担心要减少往返时间(RTT),则可以确定

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

最好使它尽可能少,但是不必严格将其保存在一个文件中。

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

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

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

All files are downloaded serially, and take a total of 4.46 seconds to complete所有文件都是串行下载的,总共需要花费4.46秒才能完成。

将13个js文件折叠成2个文件后:The same 729 kilobytes now take only 1.87 seconds to download相同的729 KB现在仅需1.87秒即可下载

在由Siku-Siku.Com澄清后进行编辑:抱歉! 我完全误解了你的问题。 我不知道有什么更好的方法来使特定(大块)脚本仅在加载相应页面时运行。 我认为您的方法足够好。

Sajib Mahmood answered 2020-06-30T02:43:09Z
5 votes

您的建议似乎还可以。 但是,我将使用HTML 5的data-属性标记每个页面,如下所示:

<body data-title="my_page_title">

然后,您可以通过检查此属性来编写条件javascript代码(从jQuery 1.4.3开始):

if ($("body").data("title") === "my_page_title") {
    // Place the logic pertaining to the page with title 'my_page_title' here...
}

这使您可以以明智的方式系统地将特定页面的所有代码分组

Wesley answered 2020-06-30T02:43:38Z
5 votes

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

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

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

我不确定100%是否比您当前使用的解决方案更有效,但另一方面,它将告诉查看HTML页面的人在页面加载时将运行什么JavaScript。 这可能对将来的维护很有帮助。。。。关于页面加载时运行什么脚本的猜测游戏不多。

希望这可以帮助!

blo0p3r answered 2020-06-30T02:44:12Z
3 votes

好。 让我们希望,代码示例会比文字墙更好地说:


您的<script>文件:

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

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

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

免责声明:这是高级概述! 实施细节可能并且应该根据您的需求而有所不同。

c69 answered 2020-06-30T02:44:49Z
2 votes

您的问题是询问如何仅基于特定页面加载脚本块。 但是,由于您的既定目标是最大程度地减少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和图像现在都已缓存。 同一应用程序中的新页面加载时间降至300毫秒左右。

Jeff Lamb answered 2020-06-30T02:45:43Z
2 votes

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

我认为您无法为自己的工作找到更好的解决方案,因为我看到许多大型网站都采用了类似的策略,尽管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等时。

希望这就是您想要的!

Gaurav Ramanan answered 2020-06-30T02:46:43Z
2 votes

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

或者就像您已经在做的那样,测试所需的元素是否在那里。 那是一个相当健壮的方法,我认为没有错。

Anony-Mousse answered 2020-06-30T02:47:08Z
1 votes

这将是一个高层次的概述,但是我建议使用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;
Ryan answered 2020-06-30T02:47:41Z
1 votes

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

然后,您可以让服务器将视图模型的名称插入例如HTML数据标签(供以后供JavaScript使用)和主脚本库后的其他脚本标签。

例如:

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

viewmodel.front_page.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动态加载新的视图模型并执行它们。

希望这对您有用;)

Sune Rasmussen answered 2020-06-30T02:48:29Z
0 votes

您可以按照自己的方法进行操作,但是假设您的“鸡尾酒” javascript文件具有20k行代码,并且将其包括在所有html文件中,即使那些显示“ 404”或“ 500”的HTML文件,也不会使用更多不必要的代码 带宽?

我选择为每个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

所以基本上它将导致:

  • 1个html请求
  • 1用于页面脚本
  • 1用于共享脚本(如果使用)
  • n为css,但我假设为1

这只是我的两分钱。

ComputerSaysNo answered 2020-06-30T02:49:20Z
translate from https://stackoverflow.com:/questions/8410298/one-js-file-for-multiple-pages