点选词高亮算法
开发项目的过程中要求做一个点击词选定一句话的功能,当时想了好多办法并且复杂化了,现在整理下思路,其实总共就几个部分:
1、点击词的位置记录,首个词和末尾词的位置
2、将选定词高亮
3、有2个词后,再次选词的逻辑
下面就来代码:
<!DOCTYPE html> <html ng-app='myApp'> <head> <meta charset='utf-8'> <script src='angular.js'></script> <script src='jquery-1.11.3.js'></script> <style> .margin-r-10 { margin-right: 10px; } .word { margin-right: 5px; cursor: pointer; } .selected { background-color: #63a855; color: #fff; } </style> </head> <body> <div ng-controller='myCtrl'> <ul> <li ng-repeat="sentence in textContent"> <span class='margin-r-10'>{{sentence.role}}</span> <span class="word cursor-pointer" ng-repeat="word in sentence.textContent" title="{{$parent.$index+'_'+$index}}" ng-click="selectWord($parent.$index, $index)" ng-class="{selected:word.selected}">{{word.word}}</span> </li> </ul> </div> <script> angular.module("myApp",[]) .controller("myCtrl",function($scope){ //文本数据 $scope.textContent = []; var chars = '呃苏先生您好我这边是应答人寿的客户服务人员.感谢您对我公司的信任最近在福建很会.购买了我公司的安康宝两全保险分红型.附加安康保提前给付重大疾病保险.为了保障您的权益我们购买了我公司保险产品的客户.都会进行售后回访,服务.现在这样您几分钟您看方便吗?'; var arr = chars.split(''); var len = arr.length; var wordId = 0; for (var i = 0; i < 30; i++) { var textContent = []; for (var k = 0; k < Math.floor(Math.random() * 1000) % 100; k++) { var word = ''; for (var j = 0; j < Math.floor(Math.random() * 10) % 5; j++) { word += arr[Math.floor(Math.random() * 1000) % len]; } textContent.push({word: word, id: wordId}); wordId++; } var role = Math.round(Math.random()) == 0 ? 'A' : 'B'; $scope.textContent.push({role: role, textContent: textContent}); } //记录文本中选择词的位置的数组,最多纪录两个 $scope.selectWordsArr = []; /** * 选择文本内容方法 */ $scope.selectWord = function (parentIndex, index) { var wordInfo = {s:parentIndex,w:index}; //如果arr为空,则直接压入 if($scope.selectWordsArr.length == 0) { $scope.selectWordsArr.push(wordInfo); //高亮该词 $scope.highLightFnc($scope.selectWordsArr, true); } //否则判断当前点击是否存在于arr中,判断是否点击相同节点,如果是,则取消高亮 else if($scope.selectWordsArr.length == 1) { //如果arr长度为1,说明只有一个词 if($scope.isInSignWordArr($scope.selectWordsArr, wordInfo)) { //如果arr中存在相同词,说明再次点击,则取消该词高亮 $scope.highLightFnc($scope.selectWordsArr, false); //并移出数组 $scope.selectWordsArr = $scope.removeWordFromArrFnc($scope.selectWordsArr, wordInfo); }else{ //否则,将该词信息压入arr $scope.selectWordsArr.push(wordInfo); //排序,方便后面操作 $scope.selectWordsArr = $scope.sortArr($scope.selectWordsArr); //高亮该区间 $scope.highLightFnc($scope.selectWordsArr, true); } } //如果数组中已有2个,则对第三个点击词进行判断 else if ($scope.selectWordsArr.length == 2) { //如果点击词的位置小于arr中较小位置,则进行对较小位置替换 //如果点击词的位置大于arr中较大位置,则对较大值进行替换 //如果点击词存在于arr中,则进行区间取消高亮,后将相同词移除,单个词高亮 if($scope.isInSignWordArr($scope.selectWordsArr, wordInfo)) { //当前词存在,取消区间高亮 $scope.highLightFnc($scope.selectWordsArr, false); //将对应词移出数组 $scope.selectWordsArr = $scope.removeWordFromArrFnc($scope.selectWordsArr, wordInfo); //设置剩余单词高亮 $scope.highLightFnc($scope.selectWordsArr, true); } else { //进行区间外的判断,如果小于小值,则替换小值,否则什么都不做 if(wordInfo.s < $scope.selectWordsArr[0].s){ //如果行小于,直接记录小值 $scope.selectWordsArr[0] = wordInfo; }else if(wordInfo.s == $scope.selectWordsArr[0].s && wordInfo.w < $scope.selectWordsArr[0].w) { //行等于且词小于才记录 $scope.selectWordsArr[0] = wordInfo; } //进行区间外判断,大于大值则替换,否则什么都不做 if(wordInfo.s > $scope.selectWordsArr[1].s){ //行大于直接记录 $scope.selectWordsArr[1] = wordInfo; }else if (wordInfo.s == $scope.selectWordsArr[1].s && wordInfo.w > $scope.selectWordsArr[1].w){ //行等于且词位置大于才记录 $scope.selectWordsArr[1] = wordInfo; } //处理完后,高亮该区间 $scope.highLightFnc($scope.selectWordsArr, true); } } angular.forEach($scope.selectWordsArr, function (obj, i) { console.dir(i+ ' : '+obj.s+'_'+obj.w); }) } //判断当前点是否存在于已纪录词位置的数组中 $scope.isInSignWordArr = function(arr, data) { var isIn = false; angular.forEach(arr, function (obj) { if(obj.s == data.s && obj.w == data.w) { isIn = true; return; } }) return isIn; } //将对应词位置从数组中移除 $scope.removeWordFromArrFnc = function (arr, data) { var sub = 0; angular.forEach(arr, function (obj, i) { if(obj.s == data.s && obj.w == data.w) { sub = i; return; } }) arr.splice(sub, 1); return arr; } //对位置数组进行排序操作,小在前,大在后,并返回 $scope.sortArr = function (arr) { var maxSub,minSub; if(arr[0].s> arr[1].s){ //如果前者大 maxSub = 0; minSub = 1; }else if(arr[0].s == arr[1].s){ //句子行数相同,判断词位置 if(arr[0].w>arr[1].w){ //如果前者大 maxSub = 0; minSub = 1; } else { //否则后者大 maxSub = 1; minSub = 0; } } else { //否则后者大 maxSub = 1; minSub = 0; } return [arr[minSub],arr[maxSub]]; } //高亮或取消对应文本位置 $scope.highLightFnc = function (arr, highLight) { //如果arr中词为一个,则对一个词进行是否高亮 if(arr.length == 1){ $scope.textContent[arr[0].s].textContent[arr[0].w].selected = highLight; } else { if(arr[0].s == arr[1].s) { //同一行 for(var i = arr[0].w; i <= arr[1].w; i++) { $scope.textContent[arr[1].s].textContent[i].selected = highLight; } }else { //不同行操作 for(var i = arr[0].s; i <= arr[1].s; i ++) { for(var j = 0; j < $scope.textContent[i].textContent.length; j ++) { if(i == arr[0].s) { if(j >= arr[0].w){ //如果遍历的是选择前词的行,则判断从选词开始高亮或取消 $scope.textContent[i].textContent[j].selected = highLight; } } else if(i == arr[1].s) { if(j <= arr[1].w){ //如果遍历的是选择后词的行,则判断从0位置搭配选词结束高亮或取消 $scope.textContent[i].textContent[j].selected = highLight; } } else { //否则就高亮或取消 $scope.textContent[i].textContent[j].selected = highLight; } } } } } } }) </script> </body> </html>