请问Koa2 中 怎样可以像 express 的 locals 那样在jade内获取对象
发布于 8 年前 作者 thomas0836 7182 次浏览 来自 问答

如题


// set static, dynamic helpers
_.extend(app.locals, {
    config: config
});

express 可以通过这样的方式,然后在jade 中 调用 config 内的 属性。 Koa 中 我了解有一个state 。 但是 貌似同样的写法


// set static, dynamic helpers
_.extend(app.state, {
    config: config
});

在jade 中也不能调用到

15 回复

statecontext的属性,应该是

_.extend(ctx.state, {config})

@hellopao 亲,请问 ctx 是从哪里获取到的?我debug 看 屏幕快照 2016-08-04 下午5.45.58.png

app 内没有 屏幕快照 2016-08-04 下午5.47.04.png context 内没有

屏幕快照 2016-08-04 下午5.48.02.png request 内没有

屏幕快照 2016-08-04 下午5.48.24.png response 内没有

@hellopao 我在用的是 Koa2 ,不是 koa1 ,ctx 在使用中间件的时候 就没有了 ,用 this 来代替

没太明白你想要的效果。 你用jade,我就当做你在做的是一个MVC的项目,那么我们想在渲染的时候拿到数据,在koa1中可以这样:

  yield this.render('see', {
        users: users,
        pager: {
            totalCount: totalCount,
            pageSize: pageSize,
            pageNum: pageNum
        }

配置好模板之后使用render,“see” 是将要被渲染的模板,后面的object对象,是你将要给这个模板传递的数据。koa2与koa1大体是一样的,在年初它还有很多坑的时候也捣鼓过,如果要在模板中得到你传递的数据,可参考

@wfsovereign web对象 有个生命周期的嘛 page ,request ,session , application ,每个阶段 都有可以调用包括它之上的变量, 就好似 在 page 中 可以 获取 request 的对象,session 的对象,application 的对象。在 request 中 可以 获取 session 的对象,application 的对象。

var express = require('express');
var session = require('express-session');

var app = express(); //这里 就是 创建了一个 application

//locals 可以在 其它层 获取 want_to_use_in_page
_.extend(app.locals, {
    want_to_use_in_page: 'test'
});

这样写后 就可以在 jade 这个 page内 调用want_to_use_in_page ,而不用在 request 哪里去声明, 而且是任何一个 page内都可以。 而且在request 哪里也可以通过 res.locals.want_to_use_in_page 来 获取

span #{want_to_use_in_page}  // 会输出  test

这样就可以用来 做 当前用户,权限等功能,在jade 内直接去判断,不用 每次都找出来吧。

现在的问题是 在使用koa的时候 有没有类似 express 的 locals这样的参数 可以 做 所有阶段的数据传递。 请问,我这样描述有清楚一点嘛?

@wfsovereign 在cnodeclub 这项目中的 middlewares/auth.js 就用这样的用法

ep.all('get_user', function (user) {
        if (!user) {
            return next();
        }
        user = res.locals.current_user = req.session.user = new UserModel(user);

        if (config.admins.hasOwnProperty(user.loginname)) {
            user.is_admin = true;
        }
        next();
    });

app.js 中 也有

_.extend(app.locals, {
    config: config
});

koa比较完整的 开源项目 我还没有找到,看到的那些 都没有涉及到 菜单的权限控制部分,所以不了解这么在jade 内去获取 session 层的东西

koa2给的例子里不就有ctx吗

// Koa application is now a class and requires the new operator.
const app = new Koa();

// uses async arrow functions
app.use(async (ctx, next) => {
  try {
    await next(); // next is now a function
  } catch (err) {
    ctx.body = { message: err.message };
    ctx.status = err.status || 500;
  }
});

app.use(async ctx => {
  const user = await User.getById(ctx.session.userid); // await instead of yield
  ctx.body = user; // ctx instead of this
});

express中其实app.locals能在ejs里面被找到的原因很简单,因为 app.render(name, options)方法里面 会进行如下的操作:

let renderoptions = {}
//将app.locals内容合并入renderoptions
merge(renderoptions, this.locals );
//将开发者调用的render方法传入的参数,合并入renderoptions
merge(renderoptions, options );
//...调用render方法
tryRender( view, renderoptions, done);

所以对于开发者来说,渲染页面的参数里其实被express自动加上了app.locals的内容,这也是为什么可以在模板里面直接调用app.locals中定义的方法或者变量的原因 我翻了下Koa2.x的源码,可以把你的属性挂载到ctx.state上实现一样的功能

当然明白了express的原理,我们在项目中也可以自己构造一个封装myRender中间件,来实现app.locals一样的功能,类似下面这样的:

funtion myRender(locals){
	locals = locals || {};
	return co.wrap(function * (ctx, next){
		ctx.myRender = function * (view, options){
			options = lodash.extend(locals, options);
			yiled ctx.render(view, options);
		}
		yiled next()
	})
}

一楼其实就给你正确的答案了

他说的ctx就是你认为的context,每个http请求都会根据中间件顺序动态生成一个context,这个ctx贯穿单个http请求在node服务器的整个生命周期 另外,koa1.x中的this,其实指向的就是这个ctx,只是在koa2.x中作为一个中间件参数显示传入了而已

@thomas0836 表述的很清楚了,你是想要有一个设置公共返回信息的地方,这里设置之后,每个view都能收到这个信息。

@hyj1991 童鞋已经给你方向了,十分详细,你可以参考参考。

此外,昨晚是看到你在微信群里问的,并且发了链接,所以你可以在那里找我的- -

@FoghostCn 我没有用 async ,只是用 Generator 函数

@wfsovereign 是吗?不知道 那个是你呢

@hyj1991 嗯嗯,其实我想了解的是,Koa 内 是否已经有 类似的接口可以直接用而已,不用自己又去做一个

koa本身并没有针对模板引擎做任何工作,在koa的源码里也仅仅只有初始化context.state = {};的一行代码 如果不引入其他依赖的话可以自己写一个:

function myRender(dir, opts)  {
  return function* (next) {
    this.render = (filename, locals) => {
      this.body = jade.compileFile(path.join(dir, filename) + '.jade', opts)(locals);
    };
    yield next;
  }
};

如果你用了co-render这样的模块的话可以这么写:

const render = require('co-render');
function myRender(dir, opts)  {
  opts = _extend({
    engine: 'jade'
  }, opts);
 return function* (next) {
   this.render = function* (filename, locals) {
     this.body = yield render(path.join(dir, filename) + '.jade', _extend(opts, locals));
   };
   yield next;
 }
};

我这是koa1的写法,你可以在opts上挂载全局的locals对象 可以用中间件的形式使用app.use(myRender('path/to/views', locals))

@FoghostCn thx 我了解是什么问题了

回到顶部