Node.js + Express 上的多个视图路径
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11315351/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Multiple View paths on Node.js + Express
提问by Moshe Simantov
I'm writing a CMS on Node.js with Express Framework. On my CMS I have several modules for users, pages, etc.
我正在使用 Express Framework在Node.js 上编写 CMS 。在我的 CMS 上,我有几个用于用户、页面等的模块。
I want that each module will have his files on separate folder, including the view files. Anyone know how can I achieve that?
我希望每个模块都将他的文件放在单独的文件夹中,包括视图文件。有谁知道我怎样才能做到这一点?
I'm using swigas my template engine but I can replace it to something else if it will helps.
我使用swig作为我的模板引擎,但如果有帮助,我可以将其替换为其他内容。
回答by BFil
Last Update
最后更新
The multiple view folders feature is supported by the framework since Express 4.10
从 Express 4.10 开始,框架支持多视图文件夹功能
Just pass an array of locations to the viewsproperty, like so.
只需将一系列位置传递给views属性,就像这样。
app.set('views', [__dirname + '/viewsFolder1', __dirname + '/viewsFolder2']);
Express 2.0
快递2.0
As far as I know express doesn't support multiple view paths or namespaces at the moment (like the static middleware do)
据我所知,express 目前不支持多个视图路径或命名空间(就像静态中间件那样)
But you can modify the lookup logic yourself so that it works the way you want, for example:
但是您可以自己修改查找逻辑,使其按照您想要的方式工作,例如:
function enableMultipleViewFolders(express) {
// proxy function to the default view lookup
var lookupProxy = express.view.lookup;
express.view.lookup = function (view, options) {
if (options.root instanceof Array) {
// clones the options object
var opts = {};
for (var key in options) opts[key] = options[key];
// loops through the paths and tries to match the view
var matchedView = null,
roots = opts.root;
for (var i=0; i<roots.length; i++) {
opts.root = roots[i];
matchedView = lookupProxy.call(this, view, opts);
if (matchedView.exists) break;
}
return matchedView;
}
return lookupProxy.call(express.view, view, options)
};
}
You will enable the new logic by calling the function above and passing expressas a parameter, and then you will be able to specify an array of views to the configuration:
您将通过调用上面的函数并传递express作为参数来启用新逻辑,然后您将能够为配置指定一组视图:
var express = require('express');
enableMultipleViewFolders(express);
app.set('views', [__dirname + '/viewsFolder1', __dirname + '/viewsFolder2']);
Or, if you prefer, you can patch the framework directly (updating the view.jsfile inside it)
或者,如果您愿意,可以直接修补框架(更新其中的view.js文件)
This should work in Express 2.x, not sure if it will with the new version (3.x)
这应该适用于 Express 2.x,不确定它是否适用于新版本(3.x)
UPDATE
更新
Unluckily the above solution won't work in Express 3.x since express.viewwould be undefined
不幸的是,上述解决方案在 Express 3.x 中不起作用,因为express.view将是未定义的
Another possible solution will be to proxy the response.renderfunction and set the views folder config until it gets a match:
另一种可能的解决方案是代理response.render函数并设置 views 文件夹配置,直到它匹配:
var renderProxy = express.response.render;
express.render = function(){
app.set('views', 'path/to/custom/views');
try {
return renderProxy.apply(this, arguments);
}
catch (e) {}
app.set('views', 'path/to/default/views');
return renderProxy.apply(this, arguments);
};
I've not tested it, it feels very hacky to me anyway, unluckily this feature has been pushed back again: https://github.com/visionmedia/express/pull/1186
我没有测试过,反正我觉得很hacky,不幸的是这个功能又被推回了:https: //github.com/visionmedia/express/pull/1186
UPDATE 2
更新 2
This feature has been added in Express 4.10, since the following pull request has been merged: https://github.com/strongloop/express/pull/2320
此功能已在 Express 4.10 中添加,因为以下拉取请求已合并:https: //github.com/strongloop/express/pull/2320
回答by BananaAcid
In addition to @user85461 answer, the require view part did not work for me. What i did: removed the path stuff and moved it all to a module i could require, patch.ViewEnableMultiFolders.js (Works with current express):
除了@user85461 的回答之外,require 视图部分对我不起作用。我做了什么:删除路径内容并将其全部移到我可能需要的模块中,patch.ViewEnableMultiFolders.js(适用于当前快递):
function ViewEnableMultiFolders(app) {
// Monkey-patch express to accept multiple paths for looking up views.
// this path may change depending on your setup.
var lookup_proxy = app.get('view').prototype.lookup;
app.get('view').prototype.lookup = function(viewName) {
var context, match;
if (this.root instanceof Array) {
for (var i = 0; i < this.root.length; i++) {
context = {root: this.root[i]};
match = lookup_proxy.call(context, viewName);
if (match) {
return match;
}
}
return null;
}
return lookup_proxy.call(this, viewName);
};
}
module.exports.ViewEnableMultiFolders = ViewEnableMultiFolders;
and used:
并使用:
var Patch = require('patch.ViewEnableMultiFolders.js');
Patch.ViewEnableMultiFolders(app);
app.set('views', ['./htdocs/views', '/htdocs/tpls']);
回答by user85461
Here's a solution for Express 3.x. It monkey-patches express 3.x's "View" object to do the same lookup trick as @ShadowCloud's solution above. Unfortunately, the path lookup for the Viewobject is less clean, since 3.x doesn't expose it to express-- so you have to dig into the bowels of node_modules.
这是 Express 3.x 的解决方案。它猴子补丁表达 3.x 的“视图”对象来执行与上面@ShadowCloud 的解决方案相同的查找技巧。不幸的是,View对象的路径查找不太干净,因为 3.x 没有将它暴露给express——所以你必须深入了解 node_modules。
function enable_multiple_view_folders() {
// Monkey-patch express to accept multiple paths for looking up views.
// this path may change depending on your setup.
var View = require("./node_modules/express/lib/view"),
lookup_proxy = View.prototype.lookup;
View.prototype.lookup = function(viewName) {
var context, match;
if (this.root instanceof Array) {
for (var i = 0; i < this.root.length; i++) {
context = {root: this.root[i]};
match = lookup_proxy.call(context, viewName);
if (match) {
return match;
}
}
return null;
}
return lookup_proxy.call(this, viewName);
};
}
enable_multiple_view_folders();
回答by priyabagus
You can however, put all the view files inside the 'view' folder, but separate each module's view into it's own folders inside the 'view' folder. So, the structure is something like this :
但是,您可以将所有视图文件放在“view”文件夹中,但将每个模块的视图分开到“view”文件夹中它自己的文件夹中。所以,结构是这样的:
views
--moduleA
--moduleB
----submoduleB1
----submoduleB2
--moduleC
Set the view files like usual :
像往常一样设置视图文件:
app.set('views', './views');
And when render for each module, include the module's name :
当为每个模块渲染时,包括模块的名称:
res.render('moduleA/index', ...);
or even submodule's name :
甚至子模块的名称:
res.render('moduleB/submoduleB1/index', ...);
This solution is also works in express before version 4.x,
此解决方案也适用于 4.x 版之前的 express,
回答by Grady Woodruff
Install glob npm install glob
安装 glob npm install glob
If you have a viewsdirectory that looks something like:
如果您有一个views类似于以下内容的目录:
views
├── 404.ejs
├── home.ejs
├── includes
│ ├── header.ejs
│ └── footer.ejs
├── post
│ ├── create.ejs
│ └── edit.ejs
└── profile.ejs
You can use this glob function to return an array of subdirectories in the viewsdirectory (add the path.substringto remove the trailing /)
您可以使用此 glob 函数返回目录中的子目录数组views(添加path.substring以删除尾随/)
let viewPaths = glob.sync('views/**/').map(path => {
return path.substring(0, path.length - 1)
})
console.log(viewPaths)
>> ['views', 'views/post', 'views/includes']
So now you can set
所以现在你可以设置
app.set('views', viewPaths)
and now you can use
现在你可以使用
res.render('404')
res.render('home')
res.render('post/edit')
res.render('post/create')

