組件組成:HTML模板 + JS文件
組件原理:HTML模板就是規定組件由哪些元素構成,這些元素是什么結構的,既組件是長啥樣的;JS文件是用來聲明和定義組件功能的,相當於JSP文件中<script>標簽中JS代碼的功能;
聯想搜索:用戶在輸入框中輸入關鍵字,並自動向后端發送異步請求,得到請求回來的數據后,以列表的形式展示在搜索框下方,用戶通過鼠標懸停或者上下鍵選擇選項,鼠標點擊或者Enter鍵實現搜索並列表消失的功能,功能如下圖:
代碼部分:
- HTML模板:
1 <span class="relative"> 2 <input type="text" placeholder="請輸入關鍵字..." ng-model="inputModel" ng-change="method.timeflash()" ng-blur="method.closeSearch()" ng-focus="method.searchData()" ng-keydown="method.keyDownEvent($event)"> 3 <i class="iconfont searchBtn"></i> 4 <span class="search-list" ng-show="vm.dataList.length > 0" id="forhide"> 5 <a href="javascript:void(0)" ng-repeat="data in vm.dataList | limitTo:10" 6 ng-mouseover="method.mouseOverEvent($index)" ng-click="method.enterKeyEvent(data)">{{data.value}}</a> 7 </span> 8 </span>
注解:輸入框對象$scope.inputModel用於保存輸入的關鍵字,輸入框提供change、blur、focus、keydown事件的監聽。
change事件:當輸入框內容變化時,觸發計時器,400毫秒后開始搜索;
blur事件:搜索框失焦時,清空並隱藏數據列表;
focus事件:輸入框獲得焦點時,直接搜索;
keydown事件:按鍵監聽事件,監聽上下鍵及Enter事件,上下鍵選擇列表中的數據項,Enter鍵做用戶指定操作。
- CSS類:
1 .relative{position: relative!important;} 2 .absolute{position: absolute!important;} 3 4 .search-list { 5 position: relative; 6 width: 100%; 9 background: #fff; 10 border: solid 1px #5093e1; 11 z-index: 10; 12 } 13 14 .search-list a { 15 width: 100%; 16 height: 30px; 17 line-height: 30px; 18 float: left; 19 color: #666; 20 display: block; 21 font-size: 13px; 22 padding: 0 10px; 23 text-decoration: none; 24 } 25 26 .search-list a:hover { 27 color: #666; 28 } 29 30 .search-list .selected { 31 background: #5093e1; 32 color: #fff!important; 33 }
注解:數據列表相對於搜索框相對布局。
- JS文件
1 APP.directive('search', ['Postman','$timeout', function (Postman,$timeout) { 2 return { 3 scope: {// 傳入的參數 4 inputModel: '=',// 輸入框對象 5 enterKeyEvent: '='// 用戶指定操作 6 }, 7 restrict: 'E',// 封裝成Element(元素)類型 8 templateUrl: 'directive/search/search.html',// 模板路徑 9 replace: false, 10 link: function ($scope) { 11 var timer; 12 var selectListIndex;// 數據列表索引 13 $scope.vm = {};// 模板視圖對象 14 $scope.method = {};// 模板方法對象 15 16 function initParams(){// 初始化參數 17 $scope.vm = { 18 selectedData: {},// 選中數據對線 19 dataList: []// 數據列表 20 }; 21 $scope.method.enterKeyEvent = $scope.enterKeyEvent;//將傳過來的用戶指定的方法賦值給組件 22 } 23 24 function init() {// 程序初始化執行部分 25 initParams(); 26 } 27 28 $scope.method.searchData = function () { // 根據關鍵字搜索聯想詞 29 if ($scope.inputModel === undefined) {// 為空時不做搜索 30 return; 31 } 32 if ($scope.inputModel.length > 0) {// 非空時異步請求聯想詞 33 var promise = Postman.httpGet('data/fuzzy', {// Postman為自己封裝的Http請求服務,這里用Get方法請求數據 34 keyWord: $scope.inputModel}); 37 promise.then(function (data) { 38 if (data && data.code === 0) { 39 $scope.vm.dataList = data.data;// 請求回來的數據賦值給視圖對象中的dataList數組 40 selectListIndex = -1;// 索引置為-1,不選中任何項 41 $('#forhide').show();// 顯示列表 42 } 43 }); 44 } 45 }; 46 47 $scope.method.keyDownEvent = function ($event) { 48 $event.stopPropagation();// 阻止其他按鍵事件冒泡 49 var listArry = $('#forhide>a'); 50 switch ($event.keyCode) { 51 case 38:// 'UP' 52 selectListIndex--; 53 if (selectListIndex >= 0 && selectListIndex < listArry.length) { 54 for (var i = 0; i < listArry.length; i++) { 55 listArry.eq(i).removeClass('selected');// 清除選中樣式 56 if (i === selectListIndex) { 57 listArry.eq(i).addClass('selected');// 添加選中樣式 58 $scope.inputModel = listArry.eq(i).text();// 將選中項的文本賦值給輸入框 59 } 60 } 61 } else if (selectListIndex < 0) {// 第0項跳轉到最后一項 62 selectListIndex = listArry.length - 1; 63 listArry.eq(0).removeClass('selected'); 64 listArry.eq(selectListIndex).addClass('selected'); 65 $scope.inputModel = listArry.eq(selectListIndex).text(); 66 } 67 break; 68 case 40:// 'Down' 69 selectListIndex++; 70 if (selectListIndex >= 0 && selectListIndex < listArry.length) { 71 for (var i = 0; i < listArry.length; i++) { 72 listArry.eq(i).removeClass('selected'); 73 if (i === selectListIndex) { 74 listArry.eq(i).addClass('selected'); 75 $scope.inputModel = listArry.eq(i).text(); 76 } 77 } 78 } else if (selectListIndex >= listArry.length) {// 最后一項跳轉到第0項 79 selectListIndex = 0; 80 listArry.eq(listArry.length - 1).removeClass('selected'); 81 listArry.eq(selectListIndex).addClass('selected'); 82 $scope.inputModel = listArry.eq(selectListIndex).text(); 83 } 84 break; 85 case 13:// Enter鍵觸發用戶指定操作 86 $scope.method.enterKeyEvent($scope.vm.dataList[selectListIndex]); 87 $scope.method.closeSearch();// 關閉聯想詞列表 88 break; 89 } 90 }; 91 92 $scope.method.mouseOverEvent = function (index) {// 鼠標懸停事件:獲取懸停數據項的索引,並添加選中樣式 93 selectListIndex = index; 94 var listArry = $('#forhide>a'); 95 for (var i = 0; i < listArry.length; i++) { 96 listArry.eq(i).removeClass('selected'); 97 if (i === selectListIndex) { 98 listArry.eq(i).addClass('selected'); 99 $scope.inputModel = listArry.eq(i).text(); 100 } 101 } 102 }; 103 104 $scope.method.timeflash = function () {// 定時器控制,400ms后才發送請求 105 $timeout.cancel(timer);// 關閉400ms內的上一個計時器,400ms后認為用戶停止輸入,即輸入完成,開始搜索,從而減少多余的請求次數 106 timer = $timeout(function () { 107 $scope.method.searchData();// 發送搜索請求 108 }, 400); 109 }; 110 111 $scope.method.closeSearch = function () {// 關閉聯想詞列表 112 $scope.vm.dataList = []; 113 $('#forhide').hide(); 114 }; 115 116 init();// 程序入口
122 } 123 }; 124 }]);
- 使用樣例:
1 <search input-model="inputBox" enter-key-event="search"></search>
傳遞組件需要的兩個參數:inputModel和enterKeyEvent。"search"為用戶指定的操作、方法。
