2013-05-08 20 views
59

Ok, vì vậy tôi đã tạo một blog bằng cách sử dụng Jekyll và bạn có thể xác định các biến trong một tệp _config.yml có thể truy cập được trong tất cả các mẫu/bố cục. Tôi hiện đang sử dụng Node.JS/Express với EJS mẫu và ejs-locals (ví partials/layouts. Tôi đang tìm kiếm để làm điều gì đó tương tự như các biến toàn cầu như site.title được tìm thấy trong _config.yml nếu có ai quen thuộc với Jekyll. Tôi có các biến như tiêu đề của trang web , (chứ không phải là tiêu đề trang), tên tác giả/công ty, trong đó giữ nguyên trên tất cả các trang của tôi.Làm thế nào để tạo các biến toàn cầu có thể truy cập trong tất cả các khung nhìn bằng Express/Node.JS?

Dưới đây là một ví dụ về những gì tôi hiện đang làm .:

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 
    }); 
}; 

tôi muốn có thể xác định các biến như tiêu đề, mô tả, tác giả của trang web của tôi ở một nơi và có thể truy cập chúng le trong bố trí/mẫu của tôi thông qua EJS mà không cần phải chuyển chúng như là các tùy chọn cho mỗi cuộc gọi đến res.render. Có cách nào để làm điều này và vẫn cho phép tôi vượt qua các biến khác cụ thể cho từng trang không?

Trả lời

80

Sau khi có cơ hội nghiên cứu Express 3 API Reference nhiều hơn một chút, tôi đã khám phá những gì tôi đang tìm kiếm. Cụ thể các mục nhập cho app.locals và sau đó một chút xa hơn res.locals đã giữ các câu trả lời tôi cần.

Tôi tự khám phá ra rằng hàm app.locals lấy một đối tượng và lưu trữ tất cả các thuộc tính của nó dưới dạng biến toàn cầu được phạm vi ứng dụng. Các hình cầu này được chuyển thành biến cục bộ cho mỗi chế độ xem. Tuy nhiên, hàm res.locals là phạm vi theo yêu cầu và do đó, phản hồi các biến cục bộ chỉ có thể truy cập vào (các) khung nhìn được hiển thị trong yêu cầu/phản hồi cụ thể đó.

Vì vậy, đối với trường hợp của tôi trong app.js tôi những gì tôi đã làm là add:

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]' 
    } 
}); 

Sau đó, tất cả các biến có thể truy cập trong quan điểm của tôi như site.title, site.description, author.name, author.contact.

Tôi cũng có thể xác định biến cục bộ cho mỗi phản hồi theo yêu cầu với res.locals hoặc chỉ cần chuyển các biến như tiêu đề của trang vào làm thông số options trong cuộc gọi render.

CHỈNH SỬA: Phương pháp này sẽ không cho phép bạn sử dụng những người dân địa phương này trong phần mềm trung gian của bạn. Tôi thực sự đã chạy vào điều này như Pickels cho thấy trong bình luận dưới đây. Trong trường hợp này, bạn sẽ cần tạo một hàm trung gian như vậy trong câu trả lời thay thế (và được đánh giá cao) của mình. Hàm trung gian của bạn sẽ cần thêm chúng vào res.locals cho mỗi câu trả lời và sau đó gọi next. Chức năng phần mềm trung gian này sẽ cần được đặt phía trên bất kỳ phần mềm trung gian nào khác cần sử dụng những người dân địa phương này.

EDIT: Một điểm khác biệt giữa người dân địa phương tuyên bố qua app.localsres.locals là với app.locals biến được đặt một lần duy nhất và tồn tại trong suốt vòng đời của ứng dụng. Khi bạn thiết lập người dân địa phương với res.locals trong phần mềm trung gian của mình, những điều này được đặt mỗi khi bạn nhận được yêu cầu. Về cơ bản, bạn nên thiết lập các hình cầu thông qua app.locals trừ khi giá trị phụ thuộc vào yêu cầu req biến được chuyển vào phần giữa. Nếu giá trị không thay đổi thì sẽ hiệu quả hơn khi nó được đặt một lần trong app.locals.

+1

app.locals có ý nghĩa hơn những gì tôi đề xuất. Nó có một bắt mặc dù, bạn không thể truy cập vào người dân địa phương trong middleware của bạn. Trong trường hợp này nó có thể không quan trọng nhưng đó là một trong những gotchas mà bạn đôi khi chạy vào. – Pickels

+0

Bueno! Cảm ơn bạn đã làm rõ các tài liệu không rõ ràng! –

+0

Bạn cũng có thể xác định cấu hình trong tệp js hoặc json và chỉ cần yêu cầu() ở mọi nơi bạn cần. Tệp sẽ chỉ tải một lần trong ứng dụng và mọi mô-đun yêu cầu nó sẽ truy cập vào các giá trị được xác định. Xem các câu trả lời khác nhau tại http://stackoverflow.com/questions/5869216/how-to-store-node-js-deployment-settings-configuration-files –

41

Bạn có thể thực hiện việc này bằng cách thêm chúng vào đối tượng địa phương trong phần mềm trung gian chung.

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

Người dân địa phương cũng là một chức năng mở rộng đối tượng địa phương thay vì ghi đè lên đối tượng địa phương. Vì vậy, các công trình sau đây cũng

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

Full dụ

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')); 

Tôi cũng đã thêm một render middleware generic. Bằng cách này bạn không phải thêm res.render vào mỗi tuyến đường có nghĩa là bạn có sử dụng lại mã tốt hơn. Một khi bạn đi xuống các tuyến đường middleware tái sử dụng bạn sẽ nhận thấy bạn sẽ có rất nhiều khối xây dựng mà sẽ tăng tốc độ phát triển rất nhiều.

+0

Tôi biết đây là một câu trả lời cũ, nhưng params trong 'globalLocals' chức năng của bạn cho' req' và 'res' là ngược. – brandon927

+0

Tôi có thể truy vấn dữ liệu được dự định là toàn cục hay không, theo cách này, ví dụ: dữ liệu thanh điều hướng tải trực tiếp từ db mỗi yêu cầu trang? Điều đó có vẻ là ý tưởng này có thể vượt quá mức sử dụng của người dân địa phương, ví dụ: một cuộc gọi mongoose. Tôi đang tìm tải trực tiếp, trên mọi tuyến đường, vì thanh điều hướng là toàn cục, sẽ xem xét bộ nhớ đệm sau. Ngoài ra, có lẽ tôi cần một chức năng chạy một lần, sau đó tải các chức năng này cho người dân địa phương sau khi thu thập dữ liệu. – blamb

6

Trong app.js của bạn, bạn cần thêm một cái gì đó như thế này

global.myvar = 100; 

Bây giờ, trong tất cả các file mà bạn muốn sử dụng biến này, bạn chỉ có thể truy cập vào nó như myvar

+0

Tôi đang sử dụng các mô-đun yêu cầu và phải tham chiếu nó là 'global.myvar' ở mọi nơi và hoạt động. Đây là một giải pháp dễ dàng cho socket.io, nơi tôi muốn phát ra các tin nhắn từ các trình xử lý trong các tệp khác. Tôi đặt đối tượng "io" của tôi vào 'global.myIO' và tất cả đều hoạt động tốt. –

+3

Điều này thực sự không được khuyến khích hoặc được coi là một thực hành tốt trong phát triển Node. Node.JS bao gồm việc triển khai hệ thống mô-đun dựa trên hệ thống CommonJS và hoàn toàn tập trung vào ý tưởng các mô-đun không chia sẻ phạm vi toàn cục, thay vì sử dụng phương thức require. Điều này cũng thiết lập một biến js toàn cầu trong Node thay vì một cục bộ cho Express view/templates như câu hỏi yêu cầu. –

+0

@CoryGross Có thực hành tốt để đặt đối tượng yêu cầu dưới dạng biến toàn cục như thế này không? –

9

Đối Express 4.0 Tôi tìm thấy rằng việc sử dụng các biến cấp ứng dụng hoạt động hơi khác nhau & Câu trả lời của Cory không hiệu quả đối với tôi.

Từ các tài liệu: http://expressjs.com/en/api.html#app.locals

tôi thấy rằng bạn có thể khai báo một biến toàn cầu cho các ứng dụng trong

app.locals 

ví dụ

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

Và sau đó trong ứng dụng của bạn, bạn có thể truy cập vào các biến & trong phần mềm trung gian thể hiện của bạn, bạn có thể truy cập chúng trong đối tượng req dưới dạng

req.app.locals.baseUrl 

ví dụ:

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

Cũng cần phải khởi động lại máy chủ tốc hành khi người dân địa phương mới được thêm vào mã. – Wtower

1

Một cách để làm điều này bằng cách cập nhật biến app.locals cho ứng dụng đó trong app.js

Đặt qua sau

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

Nhận/Access

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

Xây dựng với một ảnh chụp màn hình từ ví dụ @RamRovi với tăng cường nhẹ.

enter image description here

1

bạn cũng có thể sử dụng "toàn cầu"

Ví dụ:

tuyên bố như thế này:

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

Sử dụng như thế này: trong bất kỳ quan điểm hay EJS nộp < % console.log (site_url); %>

trong các tệp js console.log (site_url);

1

Điều tôi làm để tránh phạm vi toàn cầu bị ô nhiễm là tạo tập lệnh mà tôi có thể đưa vào bất kỳ đâu.

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

Làm điều này sẽ chỉ tạo một phiên bản mới một lần và chia sẻ ở mọi nơi tệp được bao gồm. Tôi không chắc chắn nếu nó là do biến được lưu trữ hoặc của nó vì một cơ chế tham khảo nội bộ cho các ứng dụng (có thể bao gồm bộ nhớ đệm). Bất kỳ ý kiến ​​về cách giải quyết nút này sẽ là tuyệt vời.

lẽ cũng đọc này để có được những ý chính về cách yêu cầu các công trình: http://fredkschott.com/post/2014/06/require-and-the-module-system/

Các vấn đề liên quan