Node.js + Express上的多个View视图路径

时间:2012-07-03 16:36:56

标签: node.js express

我正在使用Express Framework Node.js编写CMS。在我的CMS上,我有几个用户,页面等模块。

我希望每个模块的文件都在单独的文件夹包括视图文件。 任何人都知道如何实现这一目标?

我正在使用 swig 作为我的模板引擎,但如果有帮助我可以将其替换为其他内容。

5 个答案:

答案 0 :(得分:41)

上次更新

自Express 4.10

以来,框架支持多视图文件夹功能

只需将一组位置传递给views属性,就像这样。

app.set('views', [__dirname + '/viewsFolder1', __dirname + '/viewsFolder2']);

Express 2.0

据我所知,express目前不支持多个视图路径或命名空间(如静态中间件那样)

但是您可以自己修改查找逻辑,使其按您希望的方式工作,例如:

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

您将通过调用上面的函数并将 express 作为参数传递来启用新逻辑,然后您将能够为配置指定一组视图:

var express = require('express');
enableMultipleViewFolders(express);
app.set('views', [__dirname + '/viewsFolder1', __dirname + '/viewsFolder2']);

或者,如果您愿意,可以直接修补框架(更新其中的 view.js 文件)

这应该在Express 2.x 中工作,不确定它是否适用于新版本(3.x)

<强>更新

不幸的是,上述解决方案在Express 3.x中不起作用,因为 express.view 未定义

另一种可能的解决方案是代理 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);
};

我没有对它进行过测试,无论如何我觉得非常hacky,不幸的是这个功能再次被推回: https://github.com/visionmedia/express/pull/1186

更新2

此功能已在Express 4.10中添加,因为已合并以下拉取请求: https://github.com/strongloop/express/pull/2320

答案 1 :(得分:11)

除了@ user85461 answer之外,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;

并使用:

var Patch = require('patch.ViewEnableMultiFolders.js');
Patch.ViewEnableMultiFolders(app);
app.set('views', ['./htdocs/views', '/htdocs/tpls']);

答案 2 :(得分:5)

这是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();

答案 3 :(得分:4)

但是,您可以将所有视图文件放在&#39;视图中。文件夹,但将每个模块的视图分隔到其视图中的自己的文件夹中。夹。所以,结构是这样的:

views  
--moduleA    
--moduleB  
----submoduleB1  
----submoduleB2  
--moduleC  

像往常一样设置视图文件:

app.set('views', './views');

为每个模块渲染时,请包含模块的名称:

res.render('moduleA/index', ...);

甚至是子模块的名称:

res.render('moduleB/submoduleB1/index', ...);

此解决方案也适用于版本4.x之前的快递,

答案 4 :(得分:0)

安装glob npm install glob

如果您的views目录看起来像这样:

views
├── 404.ejs
├── home.ejs
├── includes
│   ├── header.ejs
│   └── footer.ejs
├── post
│   ├── create.ejs
│   └── edit.ejs
└── profile.ejs

您可以使用此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']

现在您可以进行设置

app.set('views', viewPaths)

现在您可以使用

res.render('404')
res.render('home')
res.render('post/edit')
res.render('post/create')