使用PHP和MySQL构建一个Dojo Tree控件

 
使用PHP和MySQL构建一个Dojo Tree控件
翻译时间:2006-12-12
目录
l        简介
l        修订记录
l        预备知识和提醒
l        联系作者
l        创建HTML和dojo控件
l        关联树选择器和事件,并显示所选内容
l        总结
本教程的目的是提供一个使用PHP和MySQL构建一个Dojo Tree控件的例子,同时演示了通过TreeSelector控件发出的选中事件,通知客户端的javascript用户选择了哪个叶节点。
本教程结束时得到的树控件工作如下:结果
修订记录
  • 06-06-2006
    • 为了方便无法访问Apache 配置(例如本地主机)的用户使用本教程,教程改为使用JSON-PHP 库。
    • 附上本教程使用的源代码和数据库脚本。
  • 05-30-2006加入Dojo wiki。
  • 05-23-2006创建
读者应当阅读并理解HelloWorld教程(http://dojo.jot.com/Tutorials/HelloWorld)。读者需要了解如何使用dojo.event.connect, dojo.io.bind,并掌握在HTML中定义dojo控件,这些是教程中必须使用的。同时,客户端到服务器端的调用是通过JSON完成的,因此需要在PHP中包含JSON-PHP 库(http://mike.teczno.com/json.html)。
几点提示,尽管笔者尽力使代码简洁明了,但由于对dojo和javascript的了解有限,如果读者有任何建议,能够使代码更加清晰,请通知笔者。另外,教程中使用objectId标记的方式可能并不是其本来的使用方式。为什么要使用objectId标记以及其使用方式的细节在“发送数据到服务器”一节中介绍。
联系作者
笔者的邮件地址为chasd00@gmail.com
在本例的树控件中,笔者将钟爱的乐队作为根节点,而他们的专辑作为根节点的下级子节点,最后将歌曲的名称作为叶节点。
首先建立HTML以及代表dojo控件的<div>。
基本的HTML头包含有dojo.js,之后回到文件体部分添加代码和我们需要部分的"require"声明语句。
<html>
<head>
<script type="text/javascript" src="dojo.js"></script>
</head>
<body>
现在在HTML中<body>中建立控件。在本例中,Dojo树控件需要一个TreeSelector和一个 TreeLoadingController控件协同工作。 TreeLoadingController负责准备树控件中所需的数据,而TreeSelector 负责树控件使用时的事件触发。
树相关控件及其属性:
TreeLoadingController
  • dojoType = 总是"TreeLoadingController"
  • widgetId = 控件ID, 本例中使用"treeController"
  • RPCUrl = 树控件的数据源地址,本例中使用一个PHP文件treelisten.php
  • DNDController = 用于拖放控制的数据,设置为dojo树控件演示用例中使用的值"create"
TreeSelector
  • dojoType =总是"TreeSelector"
  • widgetId =控件ID, 本例中使用"treeSelector"
Tree
  • dojoType =总是"Tree"
  • widgetId = 控件ID, 本例中使用"bandTree"
  • DNDMode = 设置为"between",拖放控制超出了本教程的范围
  • selector = 树控件使用的TreeSelector, 本例中应为"treeSelector"
  • controller = 树控件使用的TreeLoadingController,本例中应为"treeController"
TreeNode
  • dojoType =总是"TreeNode"
  • widgetId =控件ID, 本例中使用"eisleyRoot"
  • objectId = 对象名称,本例中使用"root"等值标示不同的节点层次,也许不是dojo控件中该属性本来的使用方式。
  • isFolder = 判断节点是否为叶节点,如果存在子节点为true,否则为false
下面是一个实际HTML代码, 其中dojo控件被定义在一个表中。
<table><tr><td>Bands
<div dojoType="TreeLoadingController" RPCUrl="treelisten.php" widgetId="treeController" DNDController="create"></div>
<div dojoType="TreeSelector" widgetId="treeSelector"></div>
<div dojoType="Tree" DNDMode="between" selector="treeSelector" widgetId="bandTree" controller="treeController">
<div dojoType="TreeNode" title="Eisley" widgetId="eisleyRoot" objectId="root" isFolder="true"></div>
</td></tr></table>
最后,添加一个<div>标记和HTML结束标记,用户选择的叶节点数据将显示在该div标记处。
<hr>
<div id="songDisplay"></div>
</body></html>
到此完成了所有的HTML代码。剩下的是javascript代码和后端的PHP。
为treeSelector控件关联事件
我们将关联dojo.TreeSelector 选择事件到一个javascript方法,以判断用户选择的节点,并将节点的标题输出到HTML中的songDisplay  div节点。
首先需要包含我们所需的dojo文件。将下列代码添加到HTML的<head>部分,并放在<script type="text/javascript" src="dojo.js"></script>之后。
<script type="text/javascript">
dojo.require("dojo.event.*");
dojo.require("dojo.io.*");
dojo.require("dojo.widget.Tree");
dojo.require("dojo.widget.TreeNode");
dojo.require("dojo.widget.TreeSelector");
dojo.require("dojo.widget.TreeLoadingController");
 
<!-- put code here -->
 
</script>
我们需要一个javascript方法以查看选中的节点,判断其是否是一个叶节点,如果是,则将节点标题显示在HTML中的songDisplay  div节点。
function treeSelectFired() {
 
   <!— 取得treeSelector 引用和选中的节点-->
    var treeSelector = dojo.widget.manager.getWidgetById('treeSelector');
    var treeNode = treeSelector.selectedNode;
 
    <!— 取得songDisplay div引用 -->
    var hostDiv = document.getElementById("songDisplay");
 
    <!— 判断是否为叶节点(!isFolder == leaf node ) -->
    <!— 取得节点标题并输出到songDisplay div -->
    var isFolder = treeNode['isFolder'];
    if ( !isFolder) {
       var song = treeNode['title']
       hostDiv.innerHTML = "You clicked on "+song;
    } else {
       hostDiv.innerHTHML = "";
    }
    hostDiv.style.display = "";
}
接下来将treeSelectFired 方法与TreeSelector 的选择事件关联起来。我们将定义一个在onLoad()事件中调用的init()方法。
function init() {
    <!— 取得treeSelector引用 -->
    var treeSelector = dojo.widget.manager.getWidgetById('treeSelector');
 
    <!— 将选择事件关联到treeSelectFired() -->
    dojo.event.connect(treeSelector,'select','treeSelectFired');
}
最后,将init方法作为参数添加到dojo.addOnLoad。
dojo.addOnLoad(init);
将所有javascript代码放在"dojo.require"声明下"put code here"注释和</script>标记之间。
到此我们完成了所有HTML和javascript代码,剩下唯一的工作是PHP代码,它负责根据选中的节点,将数据反馈到treeLoadingController 。
从浏览器发送数据到服务器并返回
下面是apache 访问日志中记录的树控件的数据请求,仔细查看能够发现调用行为,数据和dojo.preventCache 参数。
127.0.0.1 - - [21/May/2006:16:08:11 -0500] "GET /treelisten.php?action=getChildren&data=%7B%22node%22%3A%7B%22widgetId
%22%3A%22eisleyRoot%22%2C%22objectId%22%3A%22root%22%2C%22index%22%3A0%2C%22isFolder%22%3Atrue%7D%2C%22tree%22%3A%7B
%22widgetId%22%3A%22bandTree%22%2C%22objectId%22%3A%22%22%7D%7D&dojo.preventCache=1148245691371 HTTP/1.1" 200 335
treeLoadingController 希望得到一个JSON编码的treeNodes集合,然后在相应的节点下显示该集合。
在研究PHP代码之前,先解释一下数据存放的数据库表结构。数据库中包括两个表,album和song,两个表之间用外键关联。例子中使用了很简单,但希望是比较有用的表结构。
表结构 (2个表):
  1. 表 album 包括 id和 name 列
  2. 表 song 包括 id, albumId和name列
要从专辑y中取得所有的歌曲的SQL语句示例为 "select song.name from song,album where song.albumId=album.id and album.name=y;"
treelisten.php 的基本思路为:
1.      初始化头,使用$_REQUEST取得相关参数
2.      使用JSON解码,判断用户选择的是哪个父节点
3.      从数据库中取得相应的子节点,并放入一个集合
4.      使用JSON将子节点集合编码
5.      将编码后的集合返回浏览器
1.   下面是最初的PHP代码,设置了头信息并取得相关参数
<?php
 
   // 返回json编码的数据
   header('Content-type: text/json');
 
   $action = $_REQUEST["action"];
   $data = $_REQUEST["data"];
   $cache = $_REQUEST["dojo.preventCache"];
// PHP 会转义JSON数据中的"/""为"///"",所以必须避免这种转义存在,//以便解码成功
   $data = str_replace("///"","/"",$data);
 
   // 实例化一个json-php对象
   require_once('JSON.php');
   $json = new services_JSON();
 
2. 对于"getChildren"调用,必须使用JSON将data参数解码,并取得节点对象
   if ( $action == "getChildren") {
    $jsonData = $json->decode($data);
    // 得到选中节点对象
    $node = $jsonData->node;
   }
Node 对象中有以下数据
名称
objectId
  • title – 节点标题
  • objectId – 对象名
  • widgetId – 控件名
  • isFolder – 是否存在子节点
  • index – 树中的节点顺序,第一个子节点为0,第二个为1,以此类推
在PHP中使用"->" 操作符访问对象数据,例如$title = $node->title;
注:由于需要知道所选节点的父节点类型,因此在本例中使用了objectId,这可能不是该属性本来的用意。当用户选择一个节点并向treelisten.php发出一个调用,PHP函数应当知道用户在树中选择的节点,以便返回相应的数据。如果用户选择的是根节点,其objectId为"root"(这点可以在eisleyRoot TreeNode控件的HTML代码中看到),因此应当返回根节点的下级节点,也就是所有的album。通过设置album层节点的objectId为" album ",同样能够知道用户是否选择的是否是一个专辑。再强调一次,我确信这不是objectId本来的用法,如果谁知道正确的用法,请通知我。
这时我们得到了用户选择的节点对象,下面需要一个PHP方法,接收该节点对象,并返回其所有的子节点。
3. 根据父节点得到子节点列表
function getChildren($node) {
   // 建立数据库连接
   mysql_connect(<your connect parameters go here>);
   mysql_select_db(<your db goes here>);
 
   // 得到父节点类型
   $parent = $node->objectId;
 
   // 根据父节点查找相应的数据库表
   if ( $parent == "root" ) {
       $sql = "select * from album";
       $objectId = "album" // 专辑
       $isFolder = true; // 不是叶节点
   } else if ( $parent == "album" ) {
       // widgetId 为专辑名称
       $widgetId = $node->widgetId;
       $sql = "select song.name as name from song,album"
       $sql .= " where albumId=album.id and album.name='$widgetId'";
       $objectId = "song" // 歌曲
       $isFolder = false; // 是叶节点
   } else { /* 其它$parent类型 */ }
 
   // 将结果集组装为一个节点对象数组
   // PHP 中的每个节点对象用一个关联数组表示
   // 关联数组的集合使用JSON编码并返回到浏览器
   $result = mysql_query($sql);
   $i = 0;
   while ( $row = msql_fetch_array($result) ) {
       $node = array(
          "title"=> "".$row['name'],
          "widgetId" => "".$row['name'],
          "objectId"=> "".$objectId,
          "isFolder"=> $isFolder
       );
       $returnArray[$i] = $node;
       $i++;
   }
   return $returnArray;
}
?> // PHP 终止标记
好了,现在完成了取得子节点列表的PHP方法,让我们返回并完成第二步中的代码。
4. 使用JSON将子节点解码
    if ( $action == "getChildren") {
       $jsonData = $json->decode($data);
       // 得到选中节点对象
       $node = $jsonData->node;
   }
添加getChildren()方法调用,使用json_encode()编码并最终将结果返回客户端浏览器。
5. 将已编码的集合返回浏览器
    if ( $action == "getChildren") {
       $jsonData = $json->decode($data);
       // 得到选中节点对象
       $node = $jsonData->node;
       $nodeArray = getChildren($node);
       print json_encode($nodeArray);
   }
到此我们完成了所有的工作,PHP代码读取客户端发送的参数,将data部分解码,判断需要返回的节点,取得包含子节点的集合,使用JSON将其编码最后返回客户端浏览器。
总结
本教程涵盖了很多方面的知识。如果读者不能完整的运行本教程示例,可以将教程分为几个部分,一步步的实现。首先,定义控件,并在浏览HTML文件时看到准备展开的根节点。然后,选择根节点,查看访问日志中树控件的请求记录。读者可以在PHP中硬编码一个节点并返回到树控件(记住它必须是JSON编码的)。坚持一步步的工作,最终会得到完整的结果。希望该教程对你有所帮助:)。
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值