自动补全多标签输入, 适合新闻标签/商品标签
2015-05-12 20:22
148 查看
2015年5月12日 20:16:48 星期二
效果:
原理:
1. 建立"单字"索引(倒排索引): 将汉字拆分成单个字, 作为redis hash 的一个键, 将所有包含该字的id作为hash的值
2. 每次输入一个字, 就去redis里将该字的所有id取出来, 输入第二个字的时候, 取出第二个字的所有id与第一个字的id求交集
求得同时包含这两个字的所有id, 再进一步获取id对应的信息并返回
另外:
1. 文中还建立了两个全词索引(redis hash), 一个是 {"完整汉字词语" : "id", .....} 另一个是 {"id" : "完整汉字词语" ,.......} 方便后续程序使用, 与这个自动补全关系不大
2. 小细节, 每次点选词语的时候, js自动补上"," 而且ajax请求数据的时候, 只把最后一个","后边的用户输入词语发送给服务端
话不多说, 上代码:
js+css
html (只用在原有的表单上加一个id, 并在下方添加一个隐藏的div, id/class如下)
php (php+redis:hash)
效果:
原理:
1. 建立"单字"索引(倒排索引): 将汉字拆分成单个字, 作为redis hash 的一个键, 将所有包含该字的id作为hash的值
2. 每次输入一个字, 就去redis里将该字的所有id取出来, 输入第二个字的时候, 取出第二个字的所有id与第一个字的id求交集
求得同时包含这两个字的所有id, 再进一步获取id对应的信息并返回
另外:
1. 文中还建立了两个全词索引(redis hash), 一个是 {"完整汉字词语" : "id", .....} 另一个是 {"id" : "完整汉字词语" ,.......} 方便后续程序使用, 与这个自动补全关系不大
2. 小细节, 每次点选词语的时候, js自动补上"," 而且ajax请求数据的时候, 只把最后一个","后边的用户输入词语发送给服务端
话不多说, 上代码:
js+css
<script type="text/javascript"> var ac_domain = 'http://'+document.domain+'/'; initAutoComplete(); function initAutoComplete() { var ac_input = document.getElementById('auto_complete_input'); if (!ac_input) {return false;} var ac_rebuildindex = document.getElementById('rebuild_autocomplete_index'); if (document.attachEvent) { ac_input.attachEvent('oninput', input_autocomplete); //输入时进行自动补全 // ac_input.attachEvent('onblur', hide_autocomplete); //鼠标点击其它地方隐藏div, 屏蔽 因为onblur 和 onclick 冲突 ac_input.attachEvent('onfocus', input_autocomplete); //输入框重新获取焦点时显示自动补全结果 ac_input.attachEvent('onkeydown', input_autocomplete_keydown); //处理按键信息 ac_rebuildindex.attachEvent('onclick', rebuild_autocomplete_index); } else { ac_input.addEventListener('input', input_autocomplete); //输入时进行自动补全 // ac_input.addEventListener('blur', hide_autocomplete); //鼠标点击其它地方隐藏div, 屏蔽 因为onblur 和 onclick 冲突 ac_input.addEventListener('focus', input_autocomplete); //输入框重新获取焦点时显示自动补全结果 ac_input.addEventListener('keydown', input_autocomplete_keydown); //处理按键信息 ac_rebuildindex.addEventListener('click', rebuild_autocomplete_index); } $(document).bind("click",function(e){ var target = $(e.target);//表示当前对象,切记,如果没有e这个参数,即表示整个BODY对象 if(target.closest(".form-input-autocomplete,#auto_complete_input").length == 0){ hide_autocomplete(); } }) } function input_autocomplete() { var ac_input = document.getElementById('auto_complete_input'); var userinput = ac_input.value; if (!userinput) {return false;} var arr_new_word = userinput.split(/,\s*/); var new_word = arr_new_word.pop(); var url = ac_domain+'getAutoComplete?word='+new_word; $.get(url, function(data) { if (!data) {return false;}; var objGame = eval('('+data+')'); html = '<ul>'; for (var i in objGame) { html += '<li class="auto_complete_li" data-id="'+i+'" data-name="'+objGame[i]+'">'+objGame[i]+'</li>'; } html += '</ul>'; var ac_div = $("#auto_complete_div"); ac_div.show(); ac_div.html(html); click_autocomplete_li(); //注册点击事件 } ); } function hide_autocomplete() { var ac_div = document.getElementById('auto_complete_div'); ac_div.style.display = 'none'; } function click_autocomplete_li() { var arr_ac_li = getElementsByClassName('auto_complete_li', 'ul'); for (var i = 0; i < arr_ac_li.length; i++) { arr_ac_li[i].addEventListener('click', function () { //获取列表li上的数据, 并组装 var data_id = this.getAttribute('data-id'); var data_name = this.getAttribute('data-name'); var data_info = data_id+'|'+data_name; ///////向输入框写数据 var already_input = document.getElementById('auto_complete_input'); //去掉用户的输入, 换做用户点击的li里的name var arr_already_input = already_input.value.split(/,\s*/); arr_already_input.pop(); arr_already_input.push(data_name); //去重 var hash_already_input = {}; for (var i in arr_already_input) { hash_already_input[arr_already_input[i]] = arr_already_input[i]; } arr_already_input = []; for (key in hash_already_input) { arr_already_input.push(key); } //回写入表单 var str_already_input = arr_already_input.join(", "); document.getElementById('auto_complete_input').value = str_already_input+", "; //如果只有一条匹配, 点击后就消失, 多条的话点击后不消失, 可以多次点选 if (arr_ac_li.length == 1) { hide_autocomplete(); }; }) }; } function rebuild_autocomplete_index() { var nodeParent = this.parentNode; var url = ac_domain+'buildTeamAutoComplete'; $.get(url, function(data) { nodeParent.innerHTML = '已经重建索引,再点击输入框试试'; } ); } function input_autocomplete_keydown(e) { switch(e.keyCode){ case '8': //按下删除键 input_autocomplete(); break; }; } function getElementsByClassName(className, tagName) { var t = typeof(document.getElementsByClassName); if (t == 'function') { return document.getElementsByClassName(className); } var tags, matchedTags; if (tagName) { tags = document.getElementsByTagName(tagName); } else { tags = document.getElementsByTagName('*'); } matchedTags = []; for (var i = 0; i < tags.length; i++) { if (tags[i].className.indexOf(className) != -1) { matchedTags.push(tags[i]); } } return matchedTags; } </script> <style type="text/css"> /*自动补全*/ .form-input-autocomplete {padding: 0px; width: 200px; border: 1px solid #aaa; display: none; z-index: 99; position: absolute; background-color: #fff; filter: alpha(opacity=100); opacity: 1;} .form-input-autocomplete ul {margin: 0px;padding: 0px; text-align: left; list-style: none; font:15px;} .form-input-autocomplete ul li{margin: 3px;} .form-input-autocomplete ul li:hover{background-color: #eee; cursor:hand;} </style>
html (只用在原有的表单上加一个id, 并在下方添加一个隐藏的div, id/class如下)
<input type="text" id="auto_complete_input" autocomplete="off" placeholder="新闻标签" value=""> <a href="javascript:;" id="rebuild_autocomplete_index">没找到? 点这里试试</a> <div class="form-input-autocomplete" id="auto_complete_div"></div>
php (php+redis:hash)
//创建索引 public function dobuildTeamAutoComplete() { $oneWordIndex = 'autocomplete_zi'; //单字索引 $allWordIndexByName = 'autocomplete_ci_name'; //全词索引, 键为全名(火箭:team_1_2) $allWordIndexById = 'autocomplete_ci_id'; //全词索引, 键名为id(team_1_2:火箭) $type = 'team_'; //删除之前所有的旧值 $this->redis->del($oneWordIndex); //重新构建 $team = $this->redis->hgetall('LeagueTeamsNames'); $oneWordInfo = array(); $allWordInfoName = array(); foreach ($team as $lid => $jsonTeam) { if ($lid != 8 && $lid != 12) { $arrTeam = json_decode($jsonTeam, true); foreach ($arrTeam as $name => $tid) { $value = $type.$tid.'_'.$lid; $allWordInfo[$name] = $value; $length = mb_strlen($name, 'UTF-8'); for ($i=0; $i < $length; $i++) { $strOne = mb_substr($name, $i, 1, 'UTF-8'); $oneWordInfo[$strOne][$value] = $value; //懒得去重了 } } } } $oneWordInfoRedis = array(); foreach ($oneWordInfo as $word => $ids) { $a = array_values($ids); $oneWordInfoRedis[$word] = json_encode($a); } //索引写入redis $this->redis->hmset($oneWordIndex, $oneWordInfoRedis); $this->redis->hmset($allWordIndexByName, $allWordInfo); $this->redis->hmset($allWordIndexById, array_flip($allWordInfo)); exit('over'); } //自动补全请求处理函数 public function dogetAutoComplete() { $oneWordIndex = 'autocomplete_zi'; //单字索引 $allWordIndexById = 'autocomplete_ci_id'; //全词索引, 键名为id(team_1_2:火箭) $word = common::request('word', 'G'); if (empty($word)) { exit('0'); } $intWordLength = mb_strlen($word, 'UTF-8'); $arrId = array(); if (1 == $intWordLength) { $jsonId = $this->redisSlave->hget($oneWordIndex, $word); $arrId = json_decode($jsonId, true); } else { for ($i=0; $i < $intWordLength; $i++) { $strOne = mb_substr($word, $i, 1, 'UTF-8'); $jsonIdTmp = $this->redisSlave->hget($oneWordIndex, $strOne); $arrIdTmp = json_decode($jsonIdTmp, true); $arrIdTmp = $arrIdTmp ? $arrIdTmp : array(); $arrId = empty($arrId) ? $arrIdTmp : $arrId; $b = array_intersect($arrId, $arrIdTmp); $arrId = empty($b) ? $arrId : $b; // 新输入的词如果跟之前的没有交集, 就维持原来的交集不变 } } $arrId = empty($arrId) ? array() : $arrId; //获取球队信息 $arrInfo = array(); foreach ($arrId as $v) { $arrInfo[$v] = $this->redisSlave->hget($allWordIndexById, $v); } $jsonInfo = json_encode($arrInfo); exit($jsonInfo); }
相关文章推荐
- ubuntu终端输入tab自动补全后,多一个空格
- 方维模板修改,发布分享、主题有商品时,标签需自动写到input里,不要再手动去点击添加,手动点击可取消
- Linux下解决sudo输入命令不能自动补全
- bigautocomplete实现联想输入,自动补全
- emacs: 文本输入中文件目录自动补全
- php截取html字符串自动补全html标签
- php使HTML标签自动补全闭合函数代码
- bigautocomplete实现联想输入,自动补全
- JS实现在输入框内输入@时,邮箱账号自动补全
- 控制台程序小工具:输入密码、指令指派、自动补全与帮助集成
- 自动完成autoComplete,自动补全插件,输入提示
- 详解jQuery UI库中文本输入自动补全功能的用法
- autocomplete实现联想输入,自动补全
- 安装auto-fu.zsh让命令输入自动补全
- jQuery - 综合实例 - 文本输入区域与标签自动更换
- Eclipse增强自动补全,取消“=”等号和空格自动输入
- 安装auto-fu.zsh让命令输入自动补全
- java web在不使用任何插件情况下实现文本框输入自动补全功能