简介
一般网站的404页面包括两种类型:
1.路由匹配失败,没有此路由;
2.路由匹配成功,但参数不对,没有数据显示。
对于第一种情况,flow-router
和iron-router
都能轻松的处理,但对于第二种情况,iron-router
可以设置dataNotFound
的hook,而flow-router
文档中并没有提及。本文就是对这种情况的总结。
场景还原
例如,在imports/startup/routes.js
中,我定义了下面的路由,用于显示某个内容的详细信息:
1 | FlowRouter.route('/detail/:queryId',{ |
其中参数:queryId
对应于Mongo
数据库中的_id
字段,当_id
不存在时,我需要显示404页面,而不再渲染此页面的detail
模板。
其中BlazeLayout
需要添加kadira:blaze-layout
包:
1 | #终端执行 |
具体用法请看文档
第一次尝试
为了检查:queryId
是否存在,我想到了flow-router
中的triggersEnter
方法,当执行此路由时,先检查数据是否存在,如果不存在,就直接渲染notFound
,并且停止路由中action
方法的执行,如下所示:
1 | FlowRouter.route('/detail/:queryId',{ |
其中notExist
函数共有3个参数,context
必须,redirect
可以没有,stop
此方法必须。
从context
中,我们可以得到其id
,然后通过查询数据库,检查返回的数据是否为空,如果为空,就执行BlazeLayout.render('notFound');
,并且停止路由的下一步进行。
其中isEmpty
来源于lodash
库:
1 | #终端执行 |
分析结果
看起来逻辑没有错误,但是运行起来发现,当刷新页面时,就会显示404,而且浏览器终端也出现错误,通过console.log()
对数据返回值的检查,发现Resources.findOne({_id: id})
一直返回空对象,表示在route
中数据库不起作用。
第二次尝试
在路由中没有成功,我准备在模板imports/ui/template/detail.js
中再次尝试,如下:
1 | #在onCreated方法中订阅 |
通过FlowRouter.getParam
得到id
,然后数据库查找,如果数据库为空,显示404页面;如果不为空,储存返回值detailContent
到ReactiveDict
中,用于在模板中获取内容。
没想到,这次成功了,看来在路由文件声明中,不能使用数据库的查找。
小的改进
上面代码中,我使用了FlowRouter.go('/404')
,这样就必须定义一个新的路由,没有必要,并且,浏览器地址栏就会变成如www.example.com/404
;而如果使用BlazeLayout.render('notFound')
,浏览器地址不会改变,如www.example.com/detail/ddddddd
。
可以直接改为:
1 | if (isEmpty(detailContent)) { |
但是有一个问题,刷新页面时,会闪过mainLayout
布局文件的内容,如navbar
,需要继续改进:
1 | if (isEmpty(detailContent)) { |
这里,我新建了一个模板文件dataNotFound
,因为notFound
模板样式与mainLayout
的样式不一定兼容,最好是分开。
这样,对于文章开头的两种情况:
- notFound 对应于第一种,显示全局的404页面
- dataNotFound 对应于第二种,显示数据没有找到的404页面
小的问题
在Template.detail.helpers()
中,不止一个helper
,比如我还定义了isImage
方法,用于检查类型是否为图片:
1 | isImage(type) { |
但是在浏览器终端,就会出现这样的错误信息:
原因出在哪,不清楚,但使用lodash
中的startsWith
方法替代后,错误信息就没了。
1 | #首先引入 |
最后说明
Meteor版本: 1.4.1.1
Flow-router版本: 2.12.1
Meteor从1.3版本开始,就能使用npm
包了,并且项目结构有所改变,比如在detail.js
文件开头,使用ES6语法
来引入可能需要的包:
1 | #使用meteor add添加的包 |