21

我有一个使用 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 库?

4

6 回答 6

40

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

// 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']
  }
}
于 2011-04-10T23:07:53.567 回答
20

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

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

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

应用程序.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.push('myscript.js'); 

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

更新

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

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

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

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

然后,从您的正文模板中添加特定脚本(与以前完全相同):

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

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

于 2011-04-09T13:54:15.693 回答
8

可以在最新的 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
于 2013-01-17T10:45:34.667 回答
2

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

于 2011-04-17T18:59:27.537 回答
2

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

应用程序.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;
于 2011-11-27T22:24:40.460 回答
1

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

布局.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')

This way it doesn't matter where in your .jade pages you put your blocks, they will always render in the correct places.

于 2014-04-04T18:02:39.683 回答