0.前言
前些时间顺着Yeelink学习了RESTFUL,使用PHP和Slim框架尝试实现简单的REST API,树莓派可通过GET方法获得JSON数据包,通过这种方式实现了树莓派和服务器(我的PC)的互动。但是由于没有WEB前端,所以只能使用cURL工具或直接修改数据库的方式改变LED状态,体验非常差。
REST API入门体验可参考
受到【开源IOT——一个最小的物联网系统设计方案及源码】一文的影响。我决定除了服务器和嵌入式侧之外,我应该再多做一些。
WEB前端涉及到非常多的知识,下面提供一些学习资料。下面各种技术您可能不知道但是您一定用过。
【HTML】——超文本标记语言
【CSS】——级联样式表,能够对网页中的对象的位置排版进行像素级的精确控制
【Javascript】——网络的脚本语言
【Jquery】——JavaScript 库,极大地简化了 JavaScript 编程
【Ajax】——异步的 JavaScript 和 XML,与服务器交换数据并更新部分网页的艺术
本例部分源代码——【HTML代码】
1.前端框架——Bootstrap
由于前端的内容太多了,需要学习很长的时间(技术可学习,但是审美我真学不来)。还好各路高手开发了前端框架可以让我们方便而美观的实现网页开发,而把精力放在真正的idea上。推荐使用Bootstrap框架,Bootstrap是Twitter推出的一个用于前端开发的开源工具包,是一个CSS/HTML框架。
学习资料
2.简单例子
下面一个简单的例子来自于Bootstrap中文网,仅修改了title和h1元素中等内容。
[html] view plaincopy
- <!DOCTYPE html>
- <html>
- <head>
- <title>LED Remote Control Template</title>
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <!-- Bootstrap -->
- <link rel="stylesheet" href="http://cdn.bootcss.com/twitter-bootstrap/3.0.3/css/bootstrap.min.css">
- </head>
- <body>
- <h1>LED Remote Control using REST API!</h1>
- <!-- jQuery (necessary for Bootstrap‘s JavaScript plugins) -->
- <script src="http://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script>
- <!-- Include all compiled plugins (below), or include individual files as needed -->
- <script src="http://cdn.bootcss.com/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
- </body>
- </html>
图1 简单例子
【若干说明】
【CDN】在这里并没有把Bootstrap框架放置于本地服务器,而是使用了CDN服务。CDN的全称是Content Delivery Network,即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。
【JQuery】Bootstrap需要JQuery的支持
【CSS和JS】先载入Bootscript的CSS样式,然后载入Bootscript的JS包。
3.加个表格
【设计思路】
上面的例子未免有些单薄,可再加入一些表格和DIV块。基本思路——网页分为3个部分,一个部分为Header,包含一些作者信息;第二部分为主要内容——表格,表格中包含LED设备的编号、描述和当前状态(打开或关闭)等,该部分内容和数据库中的表结构对应。最后一部分为footer,可包含一些其他的信息例如我的邮箱等。
【HTML】
[html] view plaincopy
- <body>
- <div class="container">
- <div class="row">
- <div class="span12">
- <p class="lead">徐凯经验分享小站</p>
- </div>
- </div>
- <div class="row">
- <div class="span12">
- <table class="table table-hover">
- <thead>
- <tr>
- <th>编号 ID</th>
- <th>描述 DESC</th>
- <th>状态 STATUS</th>
- <th>动作 ACTION</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>1</td>
- <td>RPi.PCF8574.IO0</td>
- <td>ON</td>
- <td>ACTION</td>
- </tr>
- <tr>
- <td>2</td>
- <td>RPi.PCF8574.IO1</td>
- <td>OFF</td>
- <td>ACTION</td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- <div class="row">
- <div class="span12">
- <p class="text-right lead">如果有问题请邮件我,别客气</p>
- <p class="text-right lead">
- <em>Email:[email protected]</em>
- </p>
- </div>
- </div>
- </div>
图2 加入表格后的效果
【几点说明】
【container】 <div class="container"> container可理解为一个容器,该容器包裹了页面上的所有内容。
【网格布局】 bootstrap采用网格布局,<div class="row"> <div class="span12">row代表一行,span代表一行中的内容。在一行中最多可分为12个单元,最小单元用span1标记,最大单元用span12标记。举个例子<div class="span6">占用该行的6个单元,占用该行的一半。
【table】在bootstrap中可选择表格的风格, <table class="table table-hover">本例选择了hover形式,当鼠标移动到某一行时,该行的背景会变得灰色一些。这种简单的动态效果给用户更好的体验。
【thead tbody tr td】thead为表头标签,tbody为表格内容标签,tr为表格行标签,td为表格中的具体单元标签。
4.按钮热身
【设计思路】
在表格每行最后一个td标签中加入一个Button,点击该Button可以翻转stauts。例如点击Button,同行的Status会从ON变为OFF,再次点击从ON变为OFF。为了实现这种对应关系的操作,在tr标签中加入一个设备编号取名为dev_id。
【HTML】
[html] view plaincopy
- <table class="table table-hover">
- <thead>
- <tr>
- <th>编号 ID</th>
- <th>描述 DESC</th>
- <th>状态 STATUS</th>
- <th>动作 ACTION</th>
- </tr>
- </thead>
- <tbody>
- <tr dev_id="1">
- <td>1</td>
- <td>RPi.PCF8574.IO0</td>
- <td >off</td>
- <td>
- <button type="button" class="btn btn-primary btn-xs">Toggle</button>
- </td>
- </tr>
- <tr dev_id="2">
- <td>2</td>
- <td>RPi.PCF8574.IO1</td>
- <td>off</td>
- <td>
- <button type="button" class="btn btn-primary btn-xs">Toggle</button>
- </td>
- </tr>
- </tbody>
- </table>
图3 加入按钮后的效果
【几点说明】
【tr编号】 <tr dev_id="1"> 给每一行加入一个编号,1、2、3以此类推逐个排列。
【Button】<button type="button" class="btn btn-primary btn-xs"> bootstrap提供了多种标签风格,在这里选择最小号的Button——btn-xs 。
5.按钮互动
【设计思路】
要实现按钮互动就需要写点javascript代码,幸好Javascript不算复杂非常容易学习。编程之前需要理解一下HTML节点的概念。在HTML中所有的元素都是节点,如此之多的节点组成了“树”,节点有父节点、有子节点也会有邻居节点。例如本例中,tr标签有4个td子节点(td子节点的编号从0开始),在最后一个td节点中又有一个button节点。
【tr dev_id="1"】——> 【td(id)】【td(desc)】【td(status)】【td(action)】
【td(action)】——> 【button】
那么如果点击button想要获得表格中该行dev_id的信息,那么就需要找button的“爷爷”索要。
【javascript】
[javascript] view plaincopy
- <script>
- $(document).ready(function(){
- $(‘.btn‘).on("click",function(){
- // 获得 tr元素
- var trobj = $(this).parent().parent();
- // tr元素中包含 dev_id属性
- var dev_id = trobj.attr(‘dev_id‘);
- console.log( dev_id );
- // 访问该tr元素的所有子td元素
- var tdobj = $(trobj).children("td");
- var status_obj = $(tdobj).eq(2);
- var status_str = status_obj.text();
- console.log(status_str);
- if( status_str == "on"){
- status_obj.text("off");
- sendLedControl( dev_id , "off" );
- }else{
- status_obj.text("on");
- sendLedControl( dev_id , "on" );
- }
- });
- });
- </script>
【控制台查看效果】
web浏览器中的控制台有点和串口调试相似,在chrome浏览器中 工具->开发者工具。
图4 控制台调试
【若干说明】
【$(document).ready()】当 DOM(文档对象模型) 已经加载,并且页面(包括图像)已经完全呈现时,会发生 ready 事件。
【$(‘.btn‘).on("click",function())】按钮点击事件响应,$(‘.btn‘)代表所有所有class为btn的按钮——表格中最后一列按钮。
【this】在按钮点击事件中,this为button标签。如果使用console.log打印的话,输出内容为<button type="button" class="btn btn-primary btn-xs">Toggle</button>。但是$(this)则代表一个文件对象模型,$(this)
是一个完整的对象包含很多属性和方法。
【选择tr】var trobj = $(this).parent().parent(); 试图寻找button的爷爷
【获得dev_id】var dev_id = trobj.attr(‘dev_id‘); dev_id在td标签中,使用attr方法便可获得目标属性。
【获得所有的td标签】var tdobj = $(trobj).children("td"); 此时td标签共有4个——返回4个td对象
【定位第2个td标签】var status_obj = $(tdobj).eq(2); eq(2)代表选择第2个(从0开始)td标签——对应status标签,var status_str = status_obj.text(); 取出当前内容并通过console.log打印。
【翻转操作,修改text】status_obj.text("off"); 使用text方法重新修改td标签的属性。
【发送PUT请求】 sendLedControl 请查看下节内容。
6.PUT更新
【设计思路】
使用ajax发送一个PUT请求,更多信息请参考【PHP再学习5——RESTFul框架 远程控制LED】,PUT请求的格式如下:
PUT /api/leds/1
Host: localhost
Content-Length: 15
{"status":"on"}
【代码实现】
[javascript] view plaincopy
- function sendLedControl( dev_id , cur_status ){
- $.ajax({
- url: ‘/api/leds/‘ + dev_id, // /api/leds/1
- async: true,
- dataType: ‘json‘,
- type: ‘PUT‘,
- data: JSON.stringify({status:cur_status}),
- success: function(data , textStatus){
- console.log("success");
- },
- error: function(jqXHR , textStatus , errorThrown){
- console.log("error");
- },
- });
- }
【执行结果】
chrome浏览器 工具->开发者工具 选择Network Tag
图5 发送PUT请求
图6 查看status新状态
【若干说明】
【url】 /api/leds/1(和【PHP再学习5——RESTFul框架 远程控制LED】略有差异),LED设备的"网址"。
【dataType】请求内容为JSON格式
【type】请求方法为PUT——更新某LED设备信息
【data】请注意使用JSON.stringify方法,转换之后的格式为{"status":"on"},若没有stringify方法转换的结果为status:on,这并不符合PUT上传内容的规范。
【 success 和 error】正确处理和错误处理方法。
【遗留问题】虽然PUT请求和响应完全正确,但是Jquery总是调用error。网上查找了众多博客和帖子依然没有解决。再思考是不是PUT请求没有响应导致的,修改服务器侧代码问题,使得PUT响应中包含更新之后的LED状态问题,问题随之解决。
7.总结和源码
因为对前端相关技术不熟悉,所以我以很认真的态度写完了这篇博文。如果您觉得内容中说的不清楚或者错误的地方请留言或者Email我。认真学完这篇博文,发现前端技术javascript,ajax和jquery没有想象的那么可怕甚至还挺好用的。这几天关注了espruino——使用javascript开发MCU的平台,总觉得工程师应该多学一些,见多识广才才行。
【HTML代码】
bootstrap与REST应用