【问题标题】:Node.js with Express: Importing client-side javascript using script tags in Jade views?带有 Express 的 Node.js:在 Jade 视图中使用脚本标签导入客户端 JavaScript?
【发布时间】:2011-04-09 13:43:46
【问题描述】:

我有一个使用 Jade 模板引擎运行的 node.js express 服务器。

我有一个布局文件,它可以像这样导入单个视图的主体:

!!!
html

    head
        title= title || 'Title not set.'

    body
        #header
            h1 Header.

        #content!= body //- this renders the body of an individual view

        #footer
            p Footer.

例如以下索引页面:

p Welcome to the front page.

p This page serves as a now.js test.

这很好用。但是,我现在想包含两个专门用于该索引页面的客户端 javascript 库(因此不是每个页面,这就是为什么我不能将它放在布局的头部)。

这行得通:

//- import jquery
script(type='text/javascript', src='./jquery-1.5.2.min.js');

//- import now.js (hosts itself)
script(type='text/javascript', src='/nowjs/now.js')

//- import the chat client
script(type='text/javascript', src='./indexChatClient.js')

p Welcome to the front page.

p This page serves as a now.js test.

但是,这会将脚本加载到完整页面的正文中,这不是有效的 HTML,对吧?

据我所知,如果我想正确执行,脚本应该加载到头部,但头部部分由布局文件处理。

那么,我该如何正确地包含这些专门针对某个视图/页面的客户端 JavaScript 库?

【问题讨论】:

    标签: javascript node.js express pug


    【解决方案1】:

    您可以将它们放在布局上,并指定要在“控制器”上加载哪些库。

    // layout.jade
    !!!
    html
    
        head
            title= title || 'Title not set.'
            -each script in scripts 
              script(type='text/javascript', src= script)
        body
            #header
                h1 Header.
    
            #content!= body //- this renders the body of an individual view
    
            #footer
                p Footer.
    

    还有你的“控制者”:

    // app.js
    app.get('/', function (req, res) {
      res.render({
        scripts: ['jquery.min.js', '/nowjs/now.js']
      }
    }
    

    【讨论】:

    • 我想这样更好,因为脚本不应该设置在视图中,而应该设置在控制器中。
    • 我更喜欢将它们放在控制器上,这样您就可以轻松地重用该代码
    • 如何设置一个包含在任何地方的脚本而不在单个渲染/视图中明确设置它?
    • 要使脚本出现在 Express 3.0 中的任何地方,而不在单个视图中明确设置,您可以使用 app.locals,即:app.locals.globalScripts = ['/lib/jquery-min.js ', '/lib/bootstrap.min.js'];并在视图中: - globalScripts script(type='text/javascript', src= script) 中的每个脚本,根据上面 masylum 的回答。
    • 但是这不是仍然加载所有视图中的所有脚本吗?我以为 OP 只想在特定视图上加载?
    【解决方案2】:

    我已经使用这个线程的解决方案做了同样的事情:

    http://groups.google.com/group/express-js/browse_thread/thread/8c2006dc7bab37b1/f9a273c836e0a2ac

    您可以在视图选项中声明一个“脚本”变量:

    app.js:

    app.set('view options', { locals: { scripts: ['jquery.js'] } });  // You can declare the scripts that you will need to render in EVERY page
    

    你可以有一个助手将脚本标签渲染到布局的头部

    renderScriptTags() 帮助代码:

    app.helpers({ renderScriptTags: function(scripts) {
      return scripts.map(function(script) {
        return '<script src="scripts/' + script + '"></script>';
      }).join('\n ');
    

    进入head部分的布局模板,您将拥有:

    - renderScriptTags(scripts)
    

    现在,要在 head 标签上添加脚本,您只需要将脚本推送到您的翡翠内容模板(正文模板)上的“scripts”变量中:

    - scripts.push('myscript.js'); 
    

    这样页面会将jquery.js和myscript.js渲染到页面头部

    更新

    似乎最新的 express 版本以不同的方式处理本地人,为了使其正常工作,您可以这样做(但我不确定它是否是最佳解决方案,我需要稍微挖掘一下)

    您可以像以前一样在布局模板中使用上一个方法的 renderScriptTags() 帮助器。

    但不要将脚本变量设置为局部变量,而是创建一个动态帮助器,使 scripts 变量在我们的模板中可用:

    app.dynamicHelpers({
      scripts: function(req, res){
        return ['jquery.js']; //this will be available in all views
      }
    });
    

    然后,从你的正文模板中添加一个特定的脚本(和以前一样):

    - scripts.push('myscript.js'); 
    

    现在,对于这个特定视图,您应该正确呈现 jquery.js 和 myscript.js

    【讨论】:

    • 您只需将这些添加到通用脚本列表中,然后将其添加到通用布局文件的头部。但是,我需要为特定的视图设置特定的脚本。
    • 您可以通过将视图特定的脚本推送到脚本变量中来将其设置到视图中,以便将其呈现在布局头中,这不正是您想要完成的吗?
    • @ShadowCloud,我不确定,你在哪里推送脚本变量?这不会导致脚本在其他视图中加载,并且脚本 var 似乎是在主范围中声明的?
    • @Tom:我注意到在较新版本的 express 中本地人的处理方式不同,我在更新的答案中为您提供了修改后的解决方案(也许有更好的解决方案,但它应该可以工作)
    • @ShadowCloud 你在哪里调用 script.push?在特定视图中?
    【解决方案3】:

    可以在最新的 Jade (0.28.1) 中以正确的方式 (tm) 进行操作,方法是将其全部保存在模板/视图中,而无需在其他地方入侵页面内容(脚本链接):

    • 在模板中将头部声明为命名块:
    文档类型 5 html 头 // 命名块允许我们在每个页面中附加自定义头部条目 块头 标题=标题 链接(rel='stylesheet', href='/css/style.css') 脚本( type="text/javascript", src="/js/some-default-script.js" ) 身体 阻止内容
    • 在视图中附加页面特定的头部元素(包括脚本标签):
    扩展布局 // 这里我们引用模板头并附加到它 块追加头 元(名称=“某事”,内容=“废话”) 链接( href="/css/another.css", rel="stylesheet", type="text/css" ) 风格 div.foo { 位置:绝对; } 脚本( src="/js/page-specific-script.js" ) 阻止内容 #page-contents-follows

    【讨论】:

      【解决方案4】:

      我认为问题(通过简要阅读)是您没有“刷新”数组,将其 .length 设置为 0 以删除旧值,因此每个请求可能只是推送越来越多的字符串

      【讨论】:

      • 但我不需要这样做,对吧?我以为每次渲染视图时都会设置本地人?另外,这种添加脚本的方式是不是效率很低,因为每个请求基本上都有相同的脚本,因此应该将其缓存为固定的 html,而不是每次都遍历数组?
      【解决方案5】:

      这是另一种方法(使用 ShadowCloud 的答案)。通过概括一下,您可以指定本地和远程脚本,然后将它们推迟到页面加载后:

      app.js:

      app.dynamicHelpers({
          scripts: function() {
              //scripts to load on every page
              return ['js/jquery.min.js','js/jquery-ui.min.js','js/all.js'];
          }
      });
      

      然后,您可以在视图内的任何位置添加本地或远程脚本

      //- local script
      - scripts.push('js/myPage.js');
      //- remote script ( note: this is a schemeless url. You can use http(s)? ones too )
      - scripts.push('//platform.twitter.com/widgets.js')
      

      layout.jade:(我把它放在 body 的末尾,先加载可见的东西,但它真的可以去任何地方)

      //- Bring the scripts into a client-side array,
      //-    and attach them to the DOM one by one on page load
      script
          var page_scripts = !{'["' + scripts.join('","') + '"]'};
          function loadJS() {
              for(var i in page_scripts) {
                  var e = document.createElement("script");
                  e.src = page_scripts[i];
                  document.body.appendChild(e);
              }
          }
          // Check for browser support of event handling capability
          if (window.addEventListener)
              window.addEventListener("load", loadJS, false);
          else if (window.attachEvent)
              window.attachEvent("onload", loadJS);
          else window.onload = loadJS;
      

      【讨论】:

        【解决方案6】:

        我不确定到目前为止这些方法的意义是什么。对我来说,执行以下操作要干净得多...

        layout.jade:

        doctype html
        html
          head
            title= title
            block headscripts  // placeholder for scripts that need to be in the <head>
            link(rel='stylesheet', href='/styles/style.css')
            block styles       // placeholder for styles
          body
            block content
            script(src='/libs/jquery/dist/jquery.min.js') // this will render before all scripts in every page
            block scripts  // placeholder for scripts that go in the body
        

        somepage.jade:

        extends layout
        
        block styles  // this will render in the <head>
          link(rel='stylesheet', href='/styles/films.css')
          link(rel='stylesheet', href='/styles/pagination.css')
        
        block headscripts  // this will also render in the <head>
          script(src='/js/somescript.js')
        
        block content
          h1= title
          div.someotherstuff
        
        block scripts  // this will render at the end of the body
          script(src='/js/libs/someotherscript.js')
          scirpt(src='/libs/doT/doT.js')
        

        这样,无论您将块放在.jade 页面的哪个位置,它们都会始终呈现在正确的位置。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多