#MVC 有一种设计模式叫做MVC,我们现在已经接触了可以被用户直接触发的C,也有了可以直接访问数据表的M,还差一个叫做视图的V(View)。 我们比喻的官方一些,MVC是这样的: 从用户发送数据开始,经历1-2-3-4-5-6步,再将数据返回给用户。如下图所示: ![](https://box.kancloud.cn/2016-06-13_575e5befcb576.png) 当然了,在没有使用V以前,我们传递数据的过程是1-2-3-6。 对于MVC的理解,下图可能更加直观: ![](https://box.kancloud.cn/2016-08-01_579ef65fad719.png) 推荐学习以下视频: http://www.imooc.com/video/5019 ## 引用V层 没错,V层就是用来对数据进行包装的。 那么C层呢,C层就是个大指挥官,它从这边拿点数据,从那边拿点数据,让这个处理处理,让那个处理处理。然后让这个包装一下,让那个包装一下,最后它感觉满意了,再把包装好的产品一并返回给用户。 M层呢?就是用来被C层调用的,我们前面已经讲过了怎么调用M层,本节主要讲怎么调用V层。 ### 引用think\Controller 引用后代码如下: ~~~ <?php namespace app\index\controller; // 该文件位于application\index\controller文件夹 use think\Controller; // 用于与V层进行数据传递 use app\common\model\Teacher; // 教师模型 /** * 教师管理,继承think\Controller后,就可以利用V层对数据进行打包了。 */ class TeacherController extends Controller { public function index() { $Teacher = new Teacher; $teachers = $Teacher->select(); // 向V层传数据 // 取回打包后的数据 // 将数据返回给用户 } } ~~~ ### 建立V层文件 和C层一样,V层文件的位置也是固定的,每一个V层文件默认对应一个action。 我们看到,V层的文件,位于同模块下的view文件夹下,与控制器的名字和方法的名字相对应。如下图所示: ![](https://box.kancloud.cn/0de080899f8c97d20d465ed4b767155a_713x248.png) **注意Teahcer文件夹名与控制器名完全对应(大小写),并省略Controller后缀。** V层文件(application\index\view\Teacher\index.html)代码如下: ~~~ Hello I am V of TeahcerController\index ~~~ V层代码位置如下图所示: ![](https://box.kancloud.cn/91b8f143d6f6d50d31543af76fc6b7b7_760x233.png) ### 补齐C层代码 ~~~ public function index() { $Teacher = new Teacher; $teachers = $Teacher->select(); // 向V层传数据 $this->assign('teachers', $teachers); // 取回打包后的数据 $htmls = $this->fetch(); // 将数据返回给用户 return $htmls; } ~~~ 测试结果显示如下: ![](https://box.kancloud.cn/726795404a0a5f9847dfa55f6e80845f_412x75.png) 在上述方法中,我们使用了$this->assign()调用了其父类(think\Controller)中的assign()函数。如果我们忘记在定义类时,做继承操作,那么将会出现以下错误: **Call to undefined method app\index\controller\TeacherController::assign()** 译为:调用了一个在app\index\controller\TeacherController中没有被定义的assign()方法。解决的方法当然也很简单了,将`class TeacherController`改为`class TeacherController extends Controller`就可以了。 > 什么是$this? 简单来说,$this = 我自己,$this->assign()调用我自己(自己没有就找父类,父类没有就找父父类)的assign()方法。前面已经讲过了,我们这个类是没有,但是它的父类有,正是我们继承了think\Controller,所以我们也就可以在TeacherController里面使用think\Controller中的方法。 ### 在V层中查看变量 我们在V层中的文件index.html中,输入以下代码: ~~~ <!--在V层中使用php的函数需要类似于这样使用--> {:var_dump($teachers)} ~~~ 测试结果显示如下: ![](https://box.kancloud.cn/b32820e3b2690c87199bd6d883c0fa84_678x368.png) 没有什么技巧,这东西是thinkphp规定好的,我们记住就可以了,至于为什么可以这样用,我们在后续进阶教程中会专门针对「标签」这个东西,与大家进行详细的交流。 #### assign() 我们再来看下Think\Controller中的assign()函数: ~~~ /** * 模板变量赋值 * @access protected * @param mixed $name 要显示的模板变量 * @param mixed $value 变量的值 * @return void */ protected function assign($name, $value = '') { $this->view->assign($name, $value); } ~~~ 有人说,什么乱七八糟的代码,我看不懂。没关系,注释能看懂就好了。 注释说的很清楚了,本函数的作用是给模板变量赋值,然后接收两个变量,一个是要显示在模板中的变量名,另一个是要传入的变量的值。 > 良好的注释习惯是通往优秀程序员的必经之路!重要的事情好像要说三遍:注释、注释、注释! 也就是说,我们也可以这样写: ~~~ public function index() { $Teacher = new Teacher; $teachers = $Teacher->select(); // 向V层传数据 $this->assign('hello', $teachers); // 取回打包后的数据 $htmls = $this->fetch(); // 将数据返回给用户 return $htmls; } ~~~ 然后我们在V层中这样输出: ~~~ {:var_dump($hello)} ~~~ 当然了,大多数情况下,我们都会这样用 ~~~ // 向V层传数据 $this->assign('teachers', $teachers); ~~~ 原因很简单,变量名统一,更加易于记忆。 ### 引入html html代码如下: ~~~ <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>教师管理</title> </head> <body> <table> <tr> <th>序号</th> <th>姓名</th> <th>性别</th> <th>邮箱</th> <th>用户名</th> </tr> <tr> <td>1</td> <td>张三</td> <td>男</td> <td>11@maol.com</td> <td>zhangsan</td> </tr> </table> </body> </html> ~~~ 测试效果: ![](https://box.kancloud.cn/c7c895005da4e70b2a18c967b10b1fd7_413x107.png) 测试发现整体没有问题后,我们继续,如果有界面不符合预期,需要先修改界面。 html的错误,直接通过firefox的查看源代码来检查,如果有错误,firefox会以红色的字体标明。 ~~~ git checkout -f step3.2.5.1 ~~~ 执行上述命令后,上述示例代码信息如下: C层: ![](https://box.kancloud.cn/dc1b22c4aaf68b691af75ea49b9ceb17_1112x501.png) V层: ![](https://box.kancloud.cn/5ae73b285f43d83c5f0dc2ffb753a37e_697x519.png) ### 加入动态数据 在这里,我们用到一个标签,叫做`volist`,作用是循环输出一个数组。关于标签的知识,我们以后需要参考官方的thinkphp5快速入门教程来进行单独的学习。 > 有人说,太多了,我记不住。是的,我们也记不住。现在我们能够不查手册使用的,也就那么几个常用的标签,记住的原因还仅仅是我们用的多了而已。记住标签不是我们学习的目标,每个框架的标签都不一样,记住去哪找标签才是我们学习的目标。去哪找呢?thinkphp5官方手册! 加入volist标签后的代码如下: ~~~ <table> <tr> <th>序号</th> <th>姓名</th> <th>性别</th> <th>邮箱</th> <th>用户名</th> </tr> {volist name="teachers" id="teacher"} <tr> <td>1</td> <td>张三</td> <td>男</td> <td>11@maol.com</td> <td>zhangsan</td> </tr> {/volist} </table> ~~~ 我们再测试一遍,测试的时候,我们只是刷新一次而已,并不麻烦,不要等写了很多代码后再统一刷新测试,并不是说那种方法不可以,而是说,我们现在的水平还没有达到。测试结果如下所示: ![](https://box.kancloud.cn/2016-06-13_575e70e44a1c4.png) 我们看到成功的将张三的信息输出了两遍,说明volist成功的执行了。 现在我们再加入一行测试代码,让我们能够更清晰的看到teachers变量的结构。如下所示: ~~~ <body> <table> <tr> <th>序号</th> <th>姓名</th> <th>性别</th> <th>邮箱</th> <th>用户名</th> </tr> {volist name="teachers" id="teacher"} <tr> <td>1</td> <td>张三</td> <td>男</td> <td>11@maol.com</td> <td>zhangsan</td> </tr> {/volist} </table> {:var_dump($teachers)} </body> ~~~ 测试结果如下所示: ![](https://box.kancloud.cn/1248c5790ac7afc91886501584f309ef_680x484.png) > 永远不要认为加入测试代码是件麻烦的事情,因为你盲人摸象才是真麻烦。在使用一个数据时,必须非常清楚的知道这个数据的类型及结构。 好了,现在我们可以根据var_dump()出来的信息,进行数据的定制了。 测试信息如下: ~~~ <body> <table> <tr> <th>序号</th> <th>姓名</th> <th>性别</th> <th>邮箱</th> <th>用户名</th> </tr> {volist name="teachers" id="teacher" key="key"} <tr> <td>{$key}</td> <td>{$teacher->getData('name')}</td> <td>{$teacher->getData('sex')}</td> <td>{$teacher->getData('email')}</td> <td>{$teacher->getData('username')}</td> </tr> {/volist} </table> </body> ~~~ 刷新页面,测试结果如下: ![](https://box.kancloud.cn/edf07f93bf29b70a37a31b7bdbac1c0c_491x129.png) ### 解决性别为0的问题 性别为0,显然不是我们想要的。这里,我们需要用到另外一个标签 eq:即判断如果是0,则显示男,如果不是0,则显示女。 将性别一栏改写为: ~~~ <td>{eq name='teacher->getData("sex")' value='0'}男{else /}女{/eq}</td> ~~~ >{eq}{/eq}我们叫做非自闭合标签,也就是肯定有自己的另一半的。 >{else /}我们叫做自闭全标签,不需要找自己的另一半。 >是的,这和HTML一样。 测试结果如下图所示: ![](https://box.kancloud.cn/1561e6aa07ba2c89a41b3caee48c0f9f_483x129.png) 测试的时候,我们往往需要测试一个正确的,再测试一个错误的。拿到这里来讲,就是我要测试一个男,还要测试一个女。 这里的方法有两个: 1、修改数据表:这个我们还没怎么学。 2、修改代码:是的,我们用这个。 代码修改为: ~~~ <td>{eq name='teacher->getData("sex")' value='1'}男{else /}女{/eq}</td> ~~~ 测试结果如下图所示: ![](https://box.kancloud.cn/2016-06-13_575e70e5171b3.png) 最后,我们恢复正常的代码,并且去除测试代码: ~~~ <body> <table> <tr> <th>序号</th> <th>姓名</th> <th>性别</th> <th>邮箱</th> <th>用户名</th> </tr> {volist name="teachers" id="teacher" key="key"} <tr> <td>{$key}</td> <td>{$teacher->getData('name')}</td> <td>{eq name='teacher->getData("sex")' value='0'}男{else /}女{/eq}</td> <td>{$teacher->getData('email')}</td> <td>{$teacher->getData('username')}</td> </tr> {/volist} </table> </body> ~~~ 最终,测试效果如下图所示: ![](https://box.kancloud.cn/2016-06-13_575e70e5331ed.png) ~~~ git checkout -f step3.2.5.2 ~~~ 执行上述命令后,上述示例代码信息如下: ![](https://box.kancloud.cn/394f9609a61de55ca5a66213e934a605_1098x568.png)