2013-05-08 52 views
59

好吧,我已經使用Jekyll構建了一個博客,您可以在文件_config.yml中定義可在所有模板/佈局中訪問的變量。我目前正在使用Node.JS/ExpressEJS模板和ejs-locals(對於partials/layouts)。我正在尋找類似site.title這樣的全局變量,如果有人熟悉Jekyll,可以在_config.yml找到。 ,(而不是頁面標題),作者/公司名稱,它保持不變對所有我的網頁。如何使用Express/Node.JS創建在所有視圖中可訪問的全局變量?

這裏是什麼我目前做的,我想:

exports.index = function(req, res){ 
    res.render('index', { 
     siteTitle: 'My Website Title', 
     pageTitle: 'The Root Splash Page', 
     author: 'Cory Gross', 
     description: 'My app description', 
     indexSpecificData: someData 
    }); 
}; 

exports.home = function (req, res) { 
    res.render('home', { 
     siteTitle: 'My Website Title', 
     pageTitle: 'The Home Page', 
     author: 'Cory Gross', 
     description: 'My app description', 
     homeSpecificData: someOtherData 
    }); 
}; 

爲例能夠在一個地方定義像我的網站的標題,描述,作者等變量,並讓他們accessib在我的佈局/模板中通過EJS,而不必將它們作爲選項傳遞給每個res.render的調用。有沒有辦法做到這一點,並仍然允許我傳遞每個頁面特有的其他變量?

回答

80

在有機會學習Express 3 API Reference多一點之後,我發現了我正在尋找的東西。具體來說,app.locals的條目,然後再下降res.locals舉行我需要的答案。

我發現自己的功能app.locals需要一個對象,並將其所有屬性存儲爲應用程序的全局變量。這些全局變量作爲局部變量傳遞給每個視圖。然而,函數res.locals被限制在請求的範圍內,因此響應局部變量只能在特定請求/響應期間呈現的視圖訪問。

所以我的情況,我app.js我所做的就是加:

app.locals({ 
    site: { 
     title: 'ExpressBootstrapEJS', 
     description: 'A boilerplate for a simple web application with a Node.JS and Express backend, with an EJS template with using Twitter Bootstrap.' 
    }, 
    author: { 
     name: 'Cory Gross', 
     contact: '[email protected]' 
    } 
}); 

然後所有這些變量都在我的意見,site.titlesite.descriptionauthor.nameauthor.contact訪問。

我也可以爲res.locals的請求的每個響應定義局部變量,或者只需傳遞像頁面標題那樣的變量作爲render調用中的options參數。

編輯:這種方法將而不是允許您在您的中間件中使用這些當地人。 Pickels在下面的評論中建議我確實遇到了這個問題。在這種情況下,您需要在他的替代(和讚賞)答案中創建中間件功能。您的中間件功能將需要將它們添加到每個響應的res.locals,然後調用next。這個中間件功能將需要放在任何其他需要使用這些本地中間件的中間件之上。

編輯:通過app.localsres.locals聲明當地人之間的另一個區別是,app.locals變量設定一個時間,在整個應用程序的生命存在。當您在中間件中設置了res.locals的本地人時,每次收到請求時都會設置它們。你應該更喜歡通過app.locals設置全局變量,除非值取決於請求req傳遞給中間件的變量。如果該值沒有改變,那麼在app.locals中只設置一次就會更有效率。

+1

app.locals比我建議的更有意義。但它有一個問題,你不能訪問你的中間件中的本地人。在這種情況下,它可能並不重要,但它是您偶爾遇到的其中一個問題。 – Pickels 2013-05-12 16:31:31

+0

布埃諾!感謝您澄清不明顯的文檔! – 2013-06-18 22:16:59

+0

您還可以在js或json文件中定義配置,並只需要()它在任何需要它的地方。該文件只會在應用程序中加載一次,並且每個需要它的模塊都可以訪問它定義的值。請參閱http://stackoverflow.com/questions/5869216/how-to-store-node-js-deployment-settings-configuration-files – 2014-07-18 01:50:38

41

您可以通過將它們添加到常規中間件中的本地對象來完成此操作。

app.use(function (req, res, next) { 
    res.locals = { 
    siteTitle: "My Website's Title", 
    pageTitle: "The Home Page", 
    author: "Cory Gross", 
    description: "My app's description", 
    }; 
    next(); 
}); 

當地人也是一個函數,它將擴大當地人的對象,而不是覆蓋它。所以下面的作品以及

res.locals({ 
    siteTitle: "My Website's Title", 
    pageTitle: "The Home Page", 
    author: "Cory Gross", 
    description: "My app's description", 
}); 

完整的示例

var app = express(); 

var middleware = { 

    render: function (view) { 
     return function (req, res, next) { 
      res.render(view); 
     } 
    }, 

    globalLocals: function (req, res, next) { 
     res.locals({ 
      siteTitle: "My Website's Title", 
      pageTitle: "The Root Splash Page", 
      author: "Cory Gross", 
      description: "My app's description", 
     }); 
     next(); 
    }, 

    index: function (req, res, next) { 
     res.locals({ 
      indexSpecificData: someData 
     }); 
     next(); 
    } 

}; 


app.use(middleware.globalLocals); 
app.get('/', middleware.index, middleware.render('home')); 
app.get('/products', middleware.products, middleware.render('products')); 

我還添加了一個通用的渲染中間件。這樣你就不必爲每條路由添加res.render,這意味着你有更好的代碼重用。一旦你下了可重用的中間件路線,你會發現你將擁有大量的構建塊,這將大大加快開發速度。

+0

我知道這是一個古老的答案,但在你的'globalLocals'功能params用於在'req'和'res'是倒退。 – brandon927 2015-03-09 07:21:58

+0

我可以通過這種方式查詢意圖是全局的數據嗎?從每個頁面請求直接加載的導航欄數據?這似乎是這個想法可能超過了當地人的使用,例如,一個貓鼬電話。我正在尋找直接加載,因爲navbar是全球性的,所以在每一條路線上,稍後都會考慮到緩存。或者,也許我需要一個運行一次的函數,然後在收集數據後將它們加載到本地。 – blamb 2017-07-02 00:53:15

6

在你app.js你需要添加像這樣

global.myvar = 100; 

現在,在你想使用這個變量所有的文件,你可以訪問它myvar

+0

我正在使用require模塊,並且必須將它作爲'global.myvar'隨處引用,並且工作正常。這是一個很好的socket.io簡單解決方案,我想從其他文件中的處理程序發出消息。我把我的「io」對象放在'global.myIO'上,一切都很好。 – 2013-11-05 11:58:10

+3

這實際上並不推薦或在節點開發中被認爲是一種好的做法。 Node.JS包含基於CommonJS系統的模塊系統實現,完全集中於不共享全局範圍的模塊的思想,而是使用require方法。這也在Node中設置了一個全局的js var,而不是本地的Express視圖/模板,就像問題所要求的那樣。 – 2013-11-24 22:14:07

+0

@CoryGross將請求對象設置爲這樣的全局變量是一種很好的做法嗎? – 2017-07-28 10:33:29

9

對於快遞4.0,我發現使用應用程序級變量的工作原理有點不同& Cory的答案對我來說並不適用。

從文檔:http://expressjs.com/en/api.html#app.locals

我發現,你可以在

app.locals 

聲明一個全局變量的應用程序如

app.locals.baseUrl = "http://www.google.com" 

然後在你的應用程序,你可以訪問這些變量&在您的快遞中間件中,您可以在req對象中訪問它們作爲

req.app.locals.baseUrl 

例如

console.log(req.app.locals.baseUrl) 
//prints out http://www.google.com 
+0

在代碼中添加新本地人時,還需要重新啓動快速服務器。 – Wtower 2016-07-05 12:30:57

1

的一種方式,以通過更新該應用的app.locals變量app.js

做到這一點通過以下

var app = express(); 
app.locals.appName = "DRC on FHIR"; 

獲取/訪問

app.listen(3000, function() { 
    console.log('[' + app.locals.appName + '] => app listening on port 3001!'); 
}); 

與截圖闡述設置從@RamRovi例子略有增強。

enter image description here

1

你也可以使用 「全局」

例子:

聲明是這樣的:

app.use(function(req,res,next){ 
     global.site_url = req.headers.host; // hostname = 'localhost:8080' 
     next(); 
    }); 

使用這樣的:在任何意見或EJS 文件 < % console.log(site_url); %>

in js files console.log(site_url);

1

我爲了避免受到污染的全局範圍所做的工作是創建一個腳本,我可以將其包含在任何地方。

// my-script.js 
const ActionsOverTime = require('@bigteam/node-aot').ActionsOverTime; 
const config = require('../../config/config').actionsOverTime; 
let aotInstance; 

(function() { 
    if (!aotInstance) { 
    console.log('Create new aot instance'); 
    aotInstance = ActionsOverTime.createActionOverTimeEmitter(config); 
    } 
})(); 

exports = aotInstance; 

這樣做只會創建一個新的實例,並在包含文件的任何位置共享。我不確定是因爲變量被緩存還是因爲應用程序的內部引用機制(可能包括緩存)而導致的。關於節點如何解決這個問題的任何評論都會很棒。

或許也看過這讓如何要求工作要點: http://fredkschott.com/post/2014/06/require-and-the-module-system/

相關問題