注: 只要你会做了这道题目, 你的能力已经可以进入百度了! 如果别的部门不要你, 请你给我发邮件, 我一定尽我所能强烈推荐你! 如果你不想加入百度, 而别的公司又不要你, 只能说明那家公司瞎眼了.
题目: 见图片, 该图是某网页的一个区域的截图, 用于显示商品或者其它信息的分类. 该分类的每一项可以折叠和收起(展开和收缩, 如果有子分类的话). 分类的级数不固定. 现有一个PHP变量:
$cats = array( array( 'id' => 1, 'name' => '学术和教育', 'children' => array( array( 'id' => 2, 'name' => '自然科学', 'children' => null, ), // ... ), ), // ... );
请写一段PHP代码, 将该数组所包含的分类数据生成一段能实现如图片所示功能的HTML/JavaScript代码, 可不考虑CSS样式.
----------
注解: 这道题目考察的范围非常广, 包括PHP, HTML, JavaScript, CSS, 递归, 只有真正掌握了如上几种全部技能, 才能实现完整的功能, 否则必须依赖分工. 应聘者所能实现的程度越大, 得分就越高.
如果应聘者的应聘职位不包括HTML/JS/CSS, 那么题目可改为: 把上面的PHP数据用缩进换行文本的形式保存到文件, 并读取文件生成一个同样的PHP数组.(自定义格式的序列化和反序列化)
看到这篇日志的读者, 如果已经做了出来, 并且个人想加入百度, 请在评论中回复URL并说明你的意愿, 我会主动联系你. 或者你可以把程序打包发给我.
----------
Loading ...
$str.="<ul>";
foreach($cats as $item){
$str.="<li><span>".$item['name']."</span>";
if($item['children'])
$str.=getTree($item['children']);
$str.='</li>';
}
$str.="</ul>";
return $str;
}
如果要实现点击隐藏和显示字内容,加入一下两行jquery代码即可
$("span").click(function(){
$(this).siblings(‘ul’).toggle();
}); Reply
/**
* 无限级(受尾节点描述算法限制, 详见tree_parse注释)递归菜单
* author: selfimpr
* blog: http://blog.csdn.net/lgg201
* mail: lgg860911@yahoo.com.cn
*/
define(‘MAX_NODES’, 3); /* 最大子节点数 */
define(‘MAX_NODE_INDEX’, MAX_NODES – 1); /* 子节点最大索引值 */
define(‘NAME_FMT’, ‘name-%08d’); /* 节点内容输出格式串 */
/* 树节点数据结构 */
define(‘K_ID’, ‘id’);
define(‘K_NAME’, ‘name’);
define(‘K_CHILD’, ‘children’);
/* 输出构造时使用的拼装字符 */
define(‘PREFIX_TOP’, ‘┏’); /* 第一层第一个节点的标识符 */
define(‘PREFIX_BOTTOM’, ‘┗’); /* 每一个父节点的最后一个子节点的标识符 */
define(‘PREFIX_MIDDLE’, ‘┠’); /* 所有非上面两种情况的节点的标识符 */
define(‘PREFIX_LINE’, ‘┇’); /* 祖先节点的连线符 */
define(‘SPACE’, ‘ ‘); /* 空白占位(所有尾节点不显示连线符) */
define(‘WIDE_SPACE’, str_repeat(SPACE, 4)); /* 宽的空白占位, 为了让树的层次清晰 */
/**
* data_build
* 构造一个节点
* @param mixed $id 节点id
* @param mixed $is_leaf 是否叶子
* @access public
* @return void
*/
function node_build($id, $is_leaf = FALSE) {
return array(
K_ID => $id,
K_NAME => sprintf(NAME_FMT, $id),
K_CHILD => $is_leaf ? NULL : array(),
);
}
/**
* tree_build
* 构造一棵树(树中每个节点的子节点数由MAX_NODES确定)
* @param mixed $datas 要返回的树引用
* @param mixed $id 起始ID
* @param mixed $level 树的层级
* @access public
* @return void
*/
function tree_build(&$datas, &$id, $level) {
if ( $level < 1 ) return ;
$is_leaf = $level == 1;
$i = -1;
$next_level = $level – 1;
while ( ++ $i < MAX_NODES ) {
$data = node_build($id ++, $is_leaf);
if ( !$is_leaf )
tree_build($data[K_CHILD], $id, $next_level);
array_push($datas, $data);
}
}
/**
* node_str
* 输出一个节点自身的信息
* @param mixed $string 返回结果的字符串(引用传值)
* @param mixed $data 节点数据
* @access public
* @return void
*/
function node_str(&$string, $data) {
$string .= sprintf(‘ %s[%d]‘, $data[K_NAME], $data[K_ID]);
}
/**
* node_sign
* 输出一个节点的标志符号
* @param mixed $string 返回结果的字符串(引用传值)
* @param mixed $level 当前深度
* @param mixed $i 当前节点在父节点中的索引(下标)
* @access public
* @return void
*/
function node_sign(&$string, $level, $i) {
switch ( $i ) {
case 0:
$string .= $level == 0 ? PREFIX_TOP : PREFIX_MIDDLE;
break;
case MAX_NODE_INDEX:
$string .= PREFIX_BOTTOM;
break;
default:
$string .= PREFIX_MIDDLE;
break;
}
}
/**
* node_prefix
* 输出一个节点的前缀
* @param mixed $string 返回结果的字符串(引用传值)
* @param mixed $level 当前深度
* @param mixed $is_last 当前节点(含)所有祖先节点是否尾节点标记
* @access public
* @return void
*/
function node_prefix(&$string, $level, $is_last) {
if ( $level > 0 ) {
$i = 0;
/* 前缀格式: "父级连线" ["宽空白符" "父级连线" ...] "宽空白符" */
$string .= ($is_last & 1 << ($level – $i) ? SPACE : PREFIX_LINE);
while ( ++ $i < $level )
$string .= WIDE_SPACE . ($is_last & 1 << ($level – $i) ? SPACE : PREFIX_LINE);
$string .= WIDE_SPACE;
}
}
/**
* node_out
* 输出一个节点
* @param mixed $string 返回结果的字符串(引用传值)
* @param mixed $data 要处理的节点数据
* @param mixed $level 节点深度
* @param mixed $i 节点在父节点中的索引(下标)
* @param mixed $is_last 当前节点(含)所有祖先节点是否尾节点标记
* @access public
* @return void
*/
function node_out(&$string, $data, $level, $i, $is_last) {
/* 处理前缀字符串: 祖先的连接符及空白 */
node_prefix($string, $level, $is_last);
/* 处理本节点的标识符号 */
node_sign($string, $level, $i);
/* 处理本节点数据信息 */
node_str($string, $data);
/* 追加换行 */
$string .= "\n";
}
/**
* tree_parse
* 输出一棵树
* 1. 由于使用了整型的$is_last作为祖先是否尾节点的标记, 所以最多支持PHP_INT_MAX的深度
* 2. 如果需要扩展, 修正$is_last的数据类型及校验方法即可
* @param mixed $string 返回结果的字符串(引用传值)
* @param mixed $datas 要处理的树数据
* @param int $level 当前处理的深度
* @param int $is_last 当前深度所有祖先是否尾节点标记
* @access public
* @return void
*/
function tree_parse(&$string, $datas, $level = 0, $is_last = 0) {
if ( !is_array($datas) || count($datas) < 1 ) return ;
$max_index = count($datas) – 1;
/* 处理本层的所有节点 */
foreach ( $datas as $i => $data ) {
/* 当前节点及所有祖先是否尾节点标记 */
$tmp_is_last = $is_last << 1 | 1 & $i == $max_index;
/* 输出当前节点 */
node_out($string, $data, $level, $i, $tmp_is_last);
/* 如果有子节点, 递归子节点 */
if ( is_array($data[K_CHILD]) && !empty($data[K_CHILD]) )
tree_parse($string, $data[K_CHILD], $level + 1, $tmp_is_last);
}
}
/* 计算实际节点数 */
function n_node($n, $s) {
$sum = 0;
while ( $n > 0 )
$sum += pow($s, $n –);
return $sum;
}
/* 计算ruage时间 */
function ru_time($info, $type) {
return floatval(sprintf(‘%d.%d’, $info[$type . '.tv_sec'], $info[$type . '.tv_usec']));
}
/* 输出资源使用情况 */
function resource_usage($lv, $nodes, $cb, $ce, $mb, $me, $rb, $re) {
printf("\nresource usage[level: %d, node number: %d]: \n%20s%0.6fs\n%20s%0.6fs\n%20s%0.6fs\n%20s%d byte\n",
$lv, $nodes,
‘clock time: ‘, $ce – $cb,
‘system cpu: ‘, ru_time($re, ‘ru_stime’) – ru_time($rb, ‘ru_stime’),
‘user cpu: ‘, ru_time($re, ‘ru_utime’) – ru_time($rb, ‘ru_utime’),
‘memory usage: ‘, $me – $mb);
}
/* 用法 */
function usage($cmd) {
printf("usage: \n%s <tree deepth>\n", $cmd);
exit;
}
/* 测试入口函数 */
function run() {
global $argc, $argv;
if ( $argc != 2 || intval($argv[1]) < 1 )
usage($argv[0]);
$datas = array();
$id = 1;
$string = ”;
$level = intval($argv[1]);
/* 初始构造测试树 */
tree_build($datas, $id, $level);
$clock_begin = microtime(TRUE);
$memory_begin = memory_get_usage();
$rusage_begin = getrusage();
/* 解析树 */
tree_parse($string, $datas);
$rusage_end = getrusage();
$memory_end = memory_get_usage();
$clock_end = microtime(TRUE);
/* 输出结果 */
echo $string . "\n";
resource_usage($level, n_node($level, MAX_NODES),
$clock_begin, $clock_end,
$memory_begin, $memory_end,
$rusage_begin, $rusage_end);
}
/* 执行入口函数 */
run();
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* indent-tabs-mode: t
* End:
*/ Reply
header(‘content-type:text/html;charset=utf-8;’);
$cats = array(
array(
‘id’ => 1,
‘name’ => ‘学术和教育11′,
‘children’ => array(
array(
‘id’ => 11,
‘name’ => ‘自然科学11′,
‘children’ => array(
array(
‘id’ => 111,
‘name’ => ‘自然科学111′,
‘children’ => null,
)
),
),
array(
‘id’ => 12,
‘name’ => ‘自然科学12′,
‘children’ => null,
),
),
),
array(
‘id’ => 2,
‘name’ => ‘学术和教育222′,
‘children’ => array(
array(
‘id’ => 21,
‘name’ => ‘自然科学21′,
‘children’ => null,
),
array(
‘id’ => 22,
‘name’ => ‘自然科学22′,
‘children’ => null,
),
),
),
array(
‘id’ => 3,
‘name’ => ‘学术和教育33′,
‘children’ => array(
array(
‘id’ => 31,
‘name’ => ‘自然科学31′,
‘children’ => array(
array(
‘id’ => 331,
‘name’ => ‘自然科学331′,
‘children’ => null,
),
),
),
array(
‘id’ => 32,
‘name’ => ‘自然科学32′,
‘children’ => null,
),
),
),
);
menu($cats);
function menu($cats,$id=NULL)
{
if(!empty($id))
{
$class="class=’children’";
}
echo"<ul $class>";
foreach($cats as $k=>$v)
{
echo "<li>$v[name]";
if($v['children']!=NULL)
{
menu($v['children'],$v['id']);
}
echo "</li>";
}
echo "</ul>";
}
?>
<style>
<!–
ul{ list-style-type:none; }
ul li{cursor :pointer; background: url("img/1.png") no-repeat 0px 6px; padding-left:10px;}
ul li.click{ background: url("img/2.png") no-repeat 0px 6px;}
–>
</style>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("ul.children").hide();
$("li").click(function(){
$(this).addClass(‘click’).children(‘ul’).show();
});
});
</script> Reply
function treat($cats, &$html){
// if(!is_array($cats))
// return;
if(!array_key_exists(‘id’, $cats)){ //root
$html .= "<ul>";
foreach($cats as $item){
$html .= "<li>";
treat($item, $html);
$html .= "</li>";
}
$html .= "</ul>";
}else{
$html .= "<p id='{$cats["id"]}’>{$cats['name']}</p>";
if(count($cats['children']) > 0){
$html .= "<ul>";
foreach($cats['children'] as $child){
$html .= "<li>";
treat($child, $html);
$html .= "</li>";
}
$html .= "</ul>";
}
}
}
treat($cats, $html);
echo $html; Reply
我的邮箱是:421034509@qq.com Reply
下面是代码~
————————————————————————————
<?php
$cats = array(
array(
‘id’ => 1,
‘name’ => ‘学术和教育’,
‘children’ => array(
array(
‘id’ => 2,
‘name’ => ‘自然科学’,
‘children’ => array(
array(
‘id’ => 3,
‘name’ => ‘生物’,
‘children’ => null
)
)
),
array(
‘id’ => 4,
‘name’ => ‘人文社科’,
‘children’ => null
)
)
),
array(
‘id’ => 5,
‘name’ => ‘生活’,
‘children’ => null
)
);
class treemenue{
private $tree=array();
private $treeinfo=array();
public function __construct($arr){
$this->tree=$arr;
}
private function gettree($arr,$position){
foreach($arr as $key=>$value){
$tmp=$position;
$position.=$key;//记录当前的节点位置
$this->treeinfo["$position"]=array(‘id’=>$value['id'],’name’=>$value['name']);
if($value['children']!=null){
$this->gettree($value['children'],$position);
}
$position=$tmp;
}
}
public function creattree(){
$this->gettree($this->tree,null);
return $this->treeinfo;
}
public function countitem(){
return count($this->treeinfo);
}
public function getdepth(){
$maxdepth=0;
foreach($this->treeinfo as $key=>$value){
$maxdepth=$maxdepth>strlen($key)?$maxdepth:strlen($key);
}
return $maxdepth;
}
}
$t=new treemenue($cats);
$trinfo=$t->creattree();
$max=$t->getdepth();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>树形菜单</title>
<script>
var a=new Array();
var n=<?php echo $t->countitem(); ?>;
<?php
$j=0;
foreach($trinfo as $key=>$value){
?>
a[<?php echo $j;?>]="<?php echo $key; ?>"+"-";
<?php
$j++;
}
?>
// alert(a[0]+","+a[1]+","+","+a[2]+","+a[3]+","+a[4]);
function rollmenue(id){//伸缩菜单的函数
for(var i=0;i<n;i++){
if(a[i].substr(0,a[i].length-1)==id){
if(a[i].substr(a[i].length-1,1)=="+")
a[i]=id+"-";
else
a[i]=id+"+";
break;
}
}
var clmenue="";
for(var q=0;q<n;q++){
if(a[q].substr(a[q].length-1,1)=="-"){//展开的菜单
for(var k=q+1;k<n;k++){
if(a[k].length>a[q].length)
document.getElementById(a[k].substr(0,a[k].length-1)).style.display="inline-table";
else
break;
}
}
else{//缩起的菜单
for(var k=q+1;k<n;k++){
if(a[k].length>a[q].length)
document.getElementById(a[k].substr(0,a[k].length-1)).style.display="none";
else{
q=k-1;
break;
}
}
}
}
}
</script>
<style type="text/css">
#tree{
float:left;
}
<?php
for($i=0;$i<=$max;$i++){
$pos=20*$i;
$color=220*$i;
echo ".n".$i."{margin-left:{$pos}px;}";
echo ".n".$i." a{text-decoration:none;color:#ff8000;}";
echo ".m".$i."{" .
"font-weight:bold;" .
"background-color:#".$color.";".
"}";
}
?>
</style>
</head>
<body>
<div id="tree">
<?php foreach($trinfo as $key=>$value){ ?>
<div class="<?php echo "m".strlen($key);?>" id="<?php echo $key;?>" onclick="rollmenue(‘<?php echo $key;?>’);">
<div class="<?php echo "n".strlen($key);?>">
<a href="#?id=<?php echo $value['id']; ?>"><?php echo $value['name'];?> </a>
</div>
</div>
<?php } ?>
</div>
</body>
</html> Reply
php只输出第一层级的数据,其他数据通过ajax实现 Reply