Original: Jingxiu.com web page instant push | Please indicate the source for reprinting
Link:
This series of tutorials is based on ThinkJS v2.x version (official website) Examples are introduced, and the tutorial focuses on practical operations.
This article continues to explain the use of Controller.
If you want to do something when the object is instantiated, the constructor method is the best choice. The constructor provided by ES6 isconstructor
.
The constructor method is the default method of the class. This method is automatically called when an object instance is generated through the new command. A class must have a constructor method. If not explicitly defined, an empty constructor method will be added by default.
Method
ECMAScript 6 Getting Started Author: Ruan Yifeng
The power of thinkjs is that we can not only follow the rules Theexport default class
declares Class by itself, and also provides a method to dynamically create Class:think.controller
.
But the Class dynamically created by thinkjs does not have aconstructor
, but provides aninit
as an alternative to the constructor method, which is used in the same way as theconstructor
Consistent.
The previous article (Node.js Domestic MVC Framework ThinkJS Development Controller Chapter Base Class and Inheritance Chain Part) also has examples of the use of theinit
method, look at the code again:
// src/home/controller/base.js'use strict';export default class extends think.controller.base { init(...args) {super.init(...args);// 要求全部 url 必须携带 auth 参数let auth = this.get('auth');if (think.isEmpty(auth)) { return this.error(500, '全部 url 必须携带 auth 参数');} }}
Of course, this does not mean that you cannot use theconstructor
method. If you are like me, you are used to usingexport default class
to declare the Class yourself. You can still use the standardconstructor
method.
For the method of dynamically creating Class in thinkjs, please refer to the official documentation and will not be repeated here.
thinkjs has implemented several very useful magic methods, which provides great convenience for development. Manually like ~
As the name suggests, the pre-operation will be executed before the specific Action in the Controller is executed, which means "executed before xxx". Let’s look at the code:
// src/home/controller/user.js'use strict';export default class extends think.controller.base { __before() {console.log('this is __before().'); } indexAction() {console.log('this is indexAction().');return this.end(); }}// 访问 /home/user/index 的执行结果如下:// this is __before().// this is indexAction().
Then someone may say: It seems that__before
has the same purpose asinit
. As usual, let’s look at the code:
// src/home/controller/user.js'use strict';export default class extends think.controller.base { init(...args) {super.init(...args);console.log('this is init().'); } __before() {console.log('this is __before().'); } indexAction() {console.log('this is indexAction().');return this.end(); }}// 访问 /home/user/index 的执行结果如下:// this is init().// this is __before().// this is indexAction().
Do you see it? There is still a sequence of execution, here is a more complicated one:
// src/home/controller/base.js'use strict';export default class extends think.controller.base { init(...args) {super.init(...args);console.log('this is base.init().'); }}// src/home/controller/user.js'use strict';export default class extends think.controller.base { init(...args) {super.init(...args);console.log('this is user.init().'); } __before() {console.log('this is user.__before().'); } indexAction() {console.log('this is user.indexAction().');return this.end(); }}// 访问 /home/user/index 的执行结果如下:// this is base.init().// this is user.init().// this is user.__before().// this is user.indexAction().
Okay, you would say "expected"~
After understanding the pre-operation, the post-operation is not difficult to understand. Look at the code:
// src/home/controller/user.js'use strict';export default class extends think.controller.base { init(...args) {super.init(...args);console.log('this is init().'); } __before() {console.log('this is __before().'); } __after() {console.log('this is __after().'); } indexAction() {console.log('this is indexAction().');return this.end(); }}// 访问 /home/user/index 的执行结果如下:// this is init().// this is __before().// this is indexAction().
Eh? Something seems wrong. . .__after
Not executed.
Of course this is not caused by__after
written aboveindexAction
! Modified code:
// src/home/controller/user.js'use strict';export default class extends think.controller.base { init(...args) {super.init(...args);console.log('this is init().'); } __before() {console.log('this is __before().'); } __after() {console.log('this is __after().');return this.end(); } indexAction() {console.log('this is indexAction().'); }}// 访问 /home/user/index 的执行结果如下:// this is init().// this is __before().// this is indexAction().// this is __after().
This time it’s OK, consistent with the expected results.
I know that you have noticed that the codereturn this.end()
has been moved fromindexAction
to__after
.
this.end()
Internally performs theNode.js HTTP response.end()operation, indicating that the entire response stream is over, so if you want to enable # If ##__after, this code must be run in
__after.
init## Part of #'s responsibilities: used to detect when a Controller is accessed by an Action that is not defined, and__call
will take over the operation.
// src/home/controller/user.js'use strict';export default class extends think.controller.base { init(...args) {super.init(...args);console.log('this is init().'); } __call() {console.log(this.http.action + 'Action is not exists.');return this.end(); } indexAction() {console.log('this is indexAction().');return this.end(); }}// 访问 /home/user/test 的执行结果如下:// this is init().// testAction is not exists.
does not exist, the framework will run__call
for processing, our processing Yes logs the error and ends the response output.The sample code places
in the second-level subclass, usually in the base class, which can control the illegal access processing of all subclasses.
If you want to capture the situation when the Controller does not exist, you need to extend the error class of the framework, which will be described in another article.External calling method
//实例化 home 模块下 user controllerlet instance = think.controller('user', http, 'home');
// src/home/controller/user.js 增加_getPoints() { return 8000;}// src/home/controller/index.jslet instance = think.controller('user', this.http, 'home');let points = instance._getPoints();console.log(points); // 打印:8000instance.indexAction(); // 与直接执行 /home/user/index 是一样的效果instance.testAction(); // 报错 [Error] TypeError: instance.testAction is not a function
At first glance, this method is very close to the running result of
this.redirect(except for the magic method that does not trigger 这是一个助手 Controller,一个“隐身”的 Controller,从 url 是无法直接访问到的,因为它的所有方法名均没有 Action 后缀。 这个场景下,运行时实例化 Controller 并操作其方法的方式就派上用场了。 控制器在实例化时,会将 http 传递进去。该 http 对象是 ThinkJS 对 req 和 res 重新包装的一个对象,而非 Node.js 内置的 http 对象。 thinkjs 框架并没有给我们准备这样一个过渡页面的功能,那么我们可以自己实现一个来练练手,上代码:__call
), so what does thinkjs provide with this method? What to use? Let’s look at the code:// src/home/controller/util.js'use strict';export default class extends think.controller.base { calcGPSDistance(lat, lng){// 计算 GPS 两点直线距离return distance; } calcBaiduDistance(lat, lng){// 计算 百度大地坐标 两点直线距离return distance; } calcSosoDistance(lat, lng){// 计算 Soso坐标 两点直线距离return distance; }}
内置 http 对象
Action 里如果想获取该对象,可以通过 this.http 来获取。
thinkjs 官网扩展应用:增加一个 n 秒后自动跳转的过渡页功能
// src/common/controller/complete.js'use strict';export default class extends think.controller.base { /** * 显示中转页面 * * 调用方式: * let complete = think.controller('complete', this.http, 'common'); * return complete.display('应用新增成功!', '/', 5); * * @param msg 提示文字,支持 HTML * @param url 后续自动跳转的目标地址 * @param delay 停留秒数 * @returns {think.Promise} */ display(msg, url='', delay=3) {let tpl = 'common/complete/200';let opt = think.extend({}, {type: 'base', file_depr: '_', content_type: 'text/html'});this.fetch(tpl, {}, opt).then(content => { content = content.replace(/COMPLETE_MESSAGE/g, msg); if (url) {content = content.replace(/TARGET_URL/g, url);content = content.replace(/WAIT_SECONDS/g, delay); }; this.type(opt['content_type']); return this.end(content);}).catch(function(err){ return this.end('');}); }}
<!-- view/common/complete_200.html --><!DOCTYPE html><html><head><title>正在跳转 - 荆秀网</title></head><body><p class="header"><p class="wrap"><p class="logo"><a href="/"><img src="/static/img/logo.png" alt="XxuYou" width="60"></a></p><p class="headr"> </p></p></p><p class="wrap"><p style="margin-top:20px;height:100px;background:url(/static/img/200.gif) top center no-repeat;"></p><h1>COMPLETE_MESSAGE</h1><p class="error-msg"><pre class="brush:php;toolbar:false">提示:页面将在 <span id="_count">WAIT_SECONDS</span> 秒后重定向到 <a href="TARGET_URL">TARGET_URL</a>