前几天paperen跟一位也是从事php行业的朋友聊天,之后他向paperen展示了他做的一个物质系统,那数据确实蛮多的,远程过去看他玩了会,paperen就看中了那个搜索提示功能,咦!当输入中文的时候也可以有提示哇~~从而又想起前前几天一位从事java的朋友问paperen一个中文索引的问题,咦!当时不就是想到一个如何对姓名排序的问题,就像paperen部索爱W550C的电话簿中输入L会找到李,梁的姓,当时看到那个搜索提示觉得很神奇(虽然google的时候也经常是有了……但是你总不能给google发个邮件问问你首页那个搜索提示是咋整的捏吧),paperen一直是以为用数据库来做这个功能,但是那位朋友说了一个神奇的功能“中文转拼音”。wow~~这次赚了,所以就有了这个“姑妈”啦。

中文转拼音的源代码去google一下就大把,这里随便放个链接,猛点here

good!总而言之,是一堆比较长的代码,看不懂就当养养眼吧。下面放出demo地址-猛点here,压缩包地址-猛点here

至于这个要说的东西其实是不太多的,对于前端固然要使用ajax,paperen使用的还是jquery的框架,注意是1.4.3的版本了,而且还是直接调用google那边的jquery框架文件,所以如果你本地不能上网的就需要下载下来然后改改引入jquery框架那一段了。

对于js的设计思路,其实也很明确,你需要出现搜索提示,那么搜索框里面一定需要有内容才能给你提示啦~~搜索提示的触发点放在keyUp事件时,也就是说keyUp事件发生后要判断一下搜索框里面是否有内容,有则ajax向服务端发送请求获得返回数据。

$.ajax({
type: "POST",
url: "search.php",
data: "skey=" + skey,
success: function(data){
if (data) {
var json_data = eval('(' + data + ')');
//alert(json_data.length);
for(i=0;i<json_data.length;i++) {
list_html += "<li><a href=\"javascript:void(0);\" onclick=\"do_search('" + json_data[i].k + "');\"><span class=\"key\">" + json_data[i].k + "</span><span class=\"s_num\">" + json_data[i].n + "</a></span></li>";
}
} else {
list_html = "<li><a href=\"javascript:void(0);\" onclick=\"do_search('今天囧了没');\"><span class=\"key\">今天囧了没</span><span class=\"s_num\">17</a></span></li>";
}
$("#search_tipbox").html(list_html);
}
});

而服务端返回的数据是使用json_encode封装的,在js接收返回的数据后要进行一定的处理eval('(' + data + ')'),将json数据转换成对象object的操作,当然你可以在$.ajax里面加一个参数datatype:json,那么就不用手动用eval转了,不过那样不方便调试。

然后根据数据的子元素数量一个一个拆下来,然后取出数据并封装到一个<li><a>...</a></li>这种html结构里面,最后将$("#search_tipbox")里面的内容填为list_html这个变量,则就是完成了DOM的操作了。之后就是效果,很简单就是show()。

不过为了让定位更加自动化,写了一个函数来获取搜索框的位置。

//获取输入框位置与宽度参数
function get_skbox_var() {
var tb_offset = $("#skey_container").offset();
var tb_height = $("#skey_container").height();
var tb_width = $("#skey_container").width() - 3;
var tmp = {
'top' : tb_offset.top + tb_height ,
'left' : tb_offset.left ,
'width' : tb_width
};
return tmp;
}

将搜索离顶端离左端的数值以及它的宽度值封装到一个对象中然后返回。之后的事情你也会的了,就是让设置提示框相应的属性。

$("#search_tipbox").css('top', tipbox_var.top);
$("#search_tipbox").css('left', tipbox_var.left);
$("#search_tipbox").css('width', tipbox_var.width);

最后还需要让提示框更人性化一些,就是当焦点不在搜索框的时候就不让它出来了。这个问题看上去是个小问题,但是在实际中paperen也想了一段时间。

解决办法是:

$("#keyword").click(function() {return false;});
$(document).click(function(){
$("#search_tipbox").slideUp('fast', function(){
$("#search_tipbox").html('');
});
});

如果不加入第一行,keyword的click事件的话,就会有个小bug,就是点击搜索框的时候提示框也会收回,因为它也会触发document的click事件,这个是与js的事件流有关,冒泡型事件,所谓冒泡事件就是触发某个元素最终会触发到最顶层的元素。paperen对这个也是有点模糊,你可以去看看《Javascript高级程序设计--Nicholas》这本关于javascript的书真的很好,如果没有这本书自己也不妨互联网一下。

$("#keyword").click(function() {alert(2);});
$(document).click(function(){
alert(1)
$("#search_tipbox").slideUp('fast', function(){
$("#search_tipbox").html('');
});
});

或者再试试将上面这段代码覆盖再刷新看看,当点击搜索框时首先是弹出一个警告框“2”,这个是理所当然的啦,但之后还会触发document的click事件接着弹出“1”,也就是说点击搜索框也会触发了根元素的click事件。那么解决办法就很简单了,在触发子元素后加上return中断事件流的继续,return false。

关于服务端的程序嘛,就是最简单的了,自己可以下那个整个压缩包打开里面看看php的代码,也就那么几行,里面将一个缓存文件data.php引过来后就用里面的$cache变量了,所以看到search.php里面的这一句时不要糊涂了,$data = $cache[$skey_fc];不要说cache变量没有声明。

将$cache变量分解然后弄到$result这个临时变量中,然后用json_encode对result封装(你可以要注意一下在你空间上的php版本有没有这个函数,paperen的就没有,所以在function_common.php文件里面有一个json_encode的函数,不然会出错)。

对于data.php文件就是已经写死了一个数据文件而已,如果要考虑到由数据库生成的话,可能还要涉及到一些生成缓存的操作,并组织成一个数据结构。下面也附件上三个函数,paperen也是很久之前从discuz的源代码上面摘的,好使好用,居家良药~~

function arrayeval($array, $level = 0) {
$space = '';
for($i = 0; $i <= $level; $i++) {
$space .= "\t";
}
$evaluate = "Array\n$space(\n";
$comma = $space;
foreach($array as $key => $val) {
$key = is_string($key) ? '\''.addcslashes($key, '\'\\').'\'' : $key;
$val = !is_array($val) && (!preg_match("/^\-?\d+$/", $val) || strlen($val) > 12 || substr($val, 0, 1)=='0') ? '\''.addcslashes($val, '\'\\').'\'' : $val;
if(is_array($val)) {
$evaluate .= "$comma$key => ".arrayeval($val, $level + 1);
} else {
$evaluate .= "$comma$key => $val";
}
$comma = ",\n$space";
}
$evaluate .= "\n$space)";
return $evaluate;
}

function cache_write($name, $var, $values) {
$cachefile = ROOT.'/data/'.$name.'.php';
$cachetext = "<?php\r\n".
//"if(!defined('INRUN')) exit('Access Denied');\r\n".
'$'.$var.'='.arrayeval($values).
"\r\n?>";
if (!swritefile($cachefile, $cachetext)) {
exit("File: $cachefile write error.");
}
}
function swritefile($filename, $writetext, $openmod='w') {
if(@$fp = fopen($filename, $openmod)) {
flock($fp, 2);
fwrite($fp, $writetext);
fclose($fp);
return true;
} else {
return false;
}
}

其中cache_write这函数里面的cachefile那个路径可能需要根据自己的项目改变一下,或者增加多一个参数用来接收生成缓存文件的路径这样就更加灵活了。而arrayeval这个函数就牛×了,自己看吧,真的厉害。

使用的时候直接调用cache_write('缓存文件名','缓存数据的变量名','变量数据可以是数组');

至于中文转拼音这个,就没啥好说的了,因为paperen没了解……代码是来自网络的,貌似就是将中文的ascii转来转去,然后又移位又运算……paperen没看明白是怎一个算法……感觉很神奇,有谁了解的话解析一下也好。用法很简单$skey_to_py = pinyin($skey, 'utf-8');如果你页面是gb2312的话这里第二个参数可以不填了,因为默认就是gb2312。

最后说明一下,GooMa,姑妈这个纯属恶搞而已,不过我觉得自己设计的那个logo还是挺cool的,字体好看,字体是BoomBox,有兴趣的可以去搜搜。