在Angular中实现一个级联效果的下拉框的示例代码

实现一个具有级联效果的下拉搜索框,实现的结果如下图所示

我们主要通过这个组件,来学习一些细微的逻辑,比如: 如何计算input框内文字的长度; 如何获取光标的位置;如何实现滚动条随着上下键盘的按动进行移动......

具体需求如下

  1. 级联搜索最多不超过三级,以”.“作为级联搜索的连接符
  2. 搜索框跟着文本框中的”.“进行向后移动,向右移动的最大距离不能超过文本框的宽度
  3. 当用户修改之前的级联内容,则不进行搜索,并隐藏搜索框;若用户在之前输入的是”.“, 则将此”.“之后的内容全部删除并搜索当前的相关内容

接下来我们根据需求,来写我们的逻辑

首先我们搭建html页面

   <input
    #targetInput
    autocomplete="off"
    nz-input
    [(ngModel)]="searchValue"
    (keydown)="handlePress($event)"
    (input)="handleSearchList()"/>

   <div #searchList class="search-popup" [hidden]="!visible" (keyDown)="onKeydown($event)">
     <nz-spin [nzSpinning]="searchLoading" [class.spinning-height]="searchLoading">
      <div class="data-box" *ngIf="searchData && searchData.length !== 0">
       <ul>
       // 这里在上篇文章中已经讲解过,如何实现让匹配的文字高亮显示~
        <li
         id="item"
         *ngFor="let item of searchData;let i = index;"
         [class.item-selected]="curIndex === i"
         (mouseover)='hoverDataItem(i)'
         (click)="onSelectClick(item)">
         <span [innerHTML]="item | highlightSearchResult:searchValue | safe: 'html'"></span>
        </li>
       </ul>
      </div>
     </nz-spin>
   </div>
.search-popup {
 height: 376px;
 width: 246px;
 overflow-y: auto;
 box-shadow: 0 2px 8px rgba(0,0,0,.15);
 border-radius: 4px;
 position: absolute;
 background-color: #fff;
 z-index: 999;
 top: 92px;
 right: 61px;

 .data-box {
  margin: 0 10px;

  &:not(:last-child) {
   border-bottom: 1px solid #E4E5E7;
  }

  .no-search-data {
   display: inline-block;
   width: 100%;
   text-align: center;
   color: #C3C9D3;
   line-height: 40px;
  }
 }

 & ul {
  margin: 0 -10px;
  margin-bottom: 0;
  text-align: left;
 }

 & li {
  padding: 3px 10px;
  position: relative;
  list-style: none;
  height: 32px;
  line-height: 26px;
  &:hover {
   cursor: pointer;
   background-color: #e6f7ff;
  }
  &.item-selected {
   background-color: #E6F7FF;
  }
 }

 &.item-selected {
  background-color: #E6F7FF;

 }

.hidden-box {
 display: inline-block;
 border: 1px solid #ddd;
 visibility: hidden;
}

实现相关的逻辑

根据前两个需求,我们需要根据文本框中的”.“进行向后移动,向右移动的最大距离不能超过文本框的宽度。

思路: 我们需要将文本框中的字符串根据”.“来转换成数组,并且要想办法获取文本框中文字的长度。
如何获取文本框中文字的长度呢?
我们可以将文字的内容,重新放到一个display: inline-block的div容器中,然后获取容器的宽度,如下代码所示~

// html
 <!-- 用于测量input框的文字宽度 -->
 <div class="hidden-box" #firstLevel></div> // 以”.“转化的数组,下标为0的内容的宽度
 <div class="hidden-box" #secondLevel></div> // 以”.“转化的数组,下标为1的内容的宽度
 <div class="hidden-box" #allLevel></div> // 整个文本框的文字的宽度

 // ts
 import { ElementRef, Renderer2 } from '@angular/core';

 export class SearchListComponent {
  @ViewChild('searchList', { static: true }) public searchList: ElementRef;
  @ViewChild('firstLevel', { static: true }) public firstLevel: ElementRef;
  @ViewChild('secondLevel', { static: true }) public secondLevel: ElementRef;
  @ViewChild('allLevel', { static: true }) public allLevel: ElementRef;
  constructor(private _renderer: Renderer2) {}

  public setSearchPosition(rightValue: string): void {
    this._renderer.setStyle(
     this.searchList.nativeElement,
     'right',
     rightValue);
   } 

  public setSearchListPosition(targetValue: string): void {
  const inputWidth = 217;
  const defaultRightPosition = 60;
  const maxRightPosition = -148;
  const firstLevel = this.firstLevel.nativeElement;
  const secondLevel = this.secondLevel.nativeElement;
  const allLevel = this.allLevel.nativeElement;
  const targetValueArr = targetValue ? targetValue.split('.') : [];

  // 将input中的内容,根据”.“转换成数组之后,将相关的内容赋值到新的div容器中,为了便于获取文字的宽度
  allLevel.innerHTML = targetValue;
  firstLevel.innerHTML = targetValueArr && targetValueArr[0];
  secondLevel.innerHTML = targetValueArr && targetValueArr.length > 1 ? targetValueArr[1] : '';

  // 得到相关宽度之后,实现下拉框移动的逻辑
  if (firstLevel.offsetWidth >= inputWidth
   || (firstLevel.offsetWidth + secondLevel.offsetWidth) >= inputWidth
   || allLevel.offsetWidth >= inputWidth) {
    this.setSearchPosition(this._renderer, this.searchList, `${maxRightPosition}px`);
   } else if (targetValueArr.length <= 1) {
   this.setSearchPosition(this.renderer, this.searchList, '61px');
  } else if (targetValueArr.length <= 2) {
   this.setSearchPosition(this.renderer, this.searchList, `${defaultRightPosition - firstLevel.offsetWidth}px`);
  } else if (targetValueArr.length <= 3) {
   this.setSearchPosition(renderer,
               this.searchList,
               `${defaultRightPosition - firstLevel.offsetWidth - secondLevel.offsetWidth}px`);
  }
 }
 }

到这里,我们可以完成第一和第二个需求,我们再来看看第三个需求: 主要是根据用户输入的位置以及修改的内容,来决定是否显示搜索和显示下拉框,如果用户输入的不是”.“我们则不显示,如果用户在之前的级联中输入”.“我们就需要进行再次帮用户搜索结果。

思路: 要想完成需求三,我们需要知道用户到底是在哪里操作,即我们要是可以知道光标的位置就更完美了~

 // 获取光标的位置
 public getCursorPosition(element: HTMLInputElement): number {
  let cursorPosition = 0;
  if (element.selectionStart || element.selectionStart === 0) {
   cursorPosition = element.selectionStart;
  }
  return cursorPosition;
 }

 // 用来获取用户输入的内容是什么
 public handlePress(event: KeyboardEvent): void {
   this.curPressKey = event.key;
  }

 // 用户input的时候调用的核心方法
 public handleSearchList(value: string): void {
  this.curIndex = 0;
  const cursorPosition = this.getCursorPosition(this.targetInput.nativeElement); // 获取光标位置
  let targetValue = value;
  const targetValueArr = targetValue ? targetValue.split('.') : [];
  const valueArrLength = targetValueArr.length;
  this.setSearchListPosition(targetValue); // 调整位置
  // 判断那些情况下应该搜索并显示下拉框
  if (valueArrLength === 1
   || valueArrLength === 2 && cursorPosition >= targetValueArr[0].length + 1
   || valueArrLength === 3 && cursorPosition >= targetValueArr[0].length + targetValueArr[1].length + 2) {
    this.searchLoading = true;
    this.visible = true;
    ...获取下拉框中的数据
  } else {
   this.hidePopup();
  }
 }

最后为了更好的提高用的体验,我们还需要让下拉框支持键盘事件哦~方法也很简单,如下所示

 public onKeydown(keyDownInfo: {index: number, code: number, e: KeyboardEvent}): void {
  const { code, e } = keyDownInfo;
  e.stopPropagation();
  if (code === 38) { // 键盘上
   e.preventDefault(); // 防止光标由最后边移动到前边,只是在开发中遇到的一点体验上小问题
   if (this.curIndex > 0) {
    this.curIndex--;
   }
  } else if (code === 40) { // 键盘下
   if (this.curIndex < this.searchData.length - 1) {
    this.curIndex++;
   }
  } else if (code === 13) {  // 回车,即相当于用户点击
   this.ruleModal.showModal();
   const curData = this.searchData[this.curIndex];
   if (curData) {
    this.onSelectClick(curData);
   }
  }
  // 实现下拉框的滚动条随着键盘的上下键按动时一起移动
  const lis = document.querySelectorAll('#item');
  const curLiEle = lis[this.curIndex] as HTMLElement;
  const searchList = this.searchList.nativeElement;
  const liEleHeight = 32;
  //(当前选中li标签的offsetTop + li标签自身的高度 - 下拉框的高度)
  searchList.scrollTop = curLiEle.offsetTop + liEleHeight - searchList.clientHeight;
 }

总结

其实这个级联搜索的组件,他的通用性可能并不是很强,但是在实现的过程中,一些细节逻辑的通用性还是比较强的~ 希望这些细节可以给同在开发中的你带来一些帮助~❤

到此这篇关于在Angular中实现一个级联效果的下拉框的示例代码的文章就介绍到这了,更多相关Angular级联下拉框内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • angularjs下拉框空白的解决办法

    搜索angularjs下拉框空白,可以出现很多解决方案,但是对于静态字段来说,网上目前还没有找到解决方案,如下: <select class="form-control" ng-model="UserState" ng-init="UserState=0"> <option value="-1">选择状态</option> <option value="0">

  • Angular实现下拉框模糊查询功能示例

    本文实例讲述了Angular实现下拉框模糊查询功能.分享给大家供大家参考,具体如下: 前两天研究了一下angularjs,不得不说angularjs的mvc思想还是很强大的.对应偏重于数据处理的项目还是非常有优势的. 写了个搜索下拉框的demo,注释在里边都写了,就不再这罗嗦了. 1. 普通方式实现 <!DOCTYPE html> <html> <head lang="zh_CN"> <meta charset="utf-8"

  • Angular.js中下拉框实现渲染html的方法

    前言 大家都知道angualrjs处于安全的考虑,插值 指令会对相应字符串进行过滤,避免出现html攻击.但是在一些时候,我们需要渲染html,比如实现一个分级的下拉框 代码如下: <body ng-app="app" ng-controller="controller"> <select ng-model="value" ng-options="t.text for t in testList">&l

  • Angularjs实现带查找筛选功能的select下拉框示例代码

    前言 对于select的下拉列表,像国家选择这样的功能,全世界那么多国家,一直拉滚动条多辛苦,眼睛也要盯着找,累!所以为优化用户体验,带查找功能的下拉框是非常非常有必要的.都知道jquery里有这样的插件,但我们用的是Angularjs,更希望用双向绑定,指令的方式优雅地解决这个问题. 分析 我们的目标是在原来的<select ng-options="">标签上新加一个属性 select-search 就能支持查找的功能.如果这个属性没起作用,也不影响原来的select的功

  • AngularJS使用ng-repeat指令实现下拉框

    AngularJs 的 ng-repeat 让我们非常方便的遍历数组生成 Dom 元素,但是使用不当也会有性能问题.下面给大家分享在项目中使用ng-repeat指令实现下拉框. 1.问题背景 select下拉框里option组装成下拉框,这里利用ng-repeat指令来创建 2.实现源码 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>AngularJS之

  • AngularJS中下拉框的高级用法示例

    本文实例讲述了AngularJS中下拉框的高级用法.分享给大家供大家参考,具体如下: HTML正文: <body ng-app="myApp"> <!-- 对象内部属性遍历:x--key y---value --> <div ng-controller="myctr01"> {{sites}}<br> <select ng-model="site" ng-options="x for

  • Angular.JS中select下拉框设置value的方法

    前言 本文主要给大家介绍的是关于Angular.JS中select下拉框设置value的相关内容,非常出来供大家参考学习,下面来一起看看详细的介绍: 最近在系统中增加一个查询的筛选条件,通过下拉框选取,用的是Angular常见的ng-options 指令: <select id="selectDetectUnit" class="form-control" ng-model="detectUnits" ng-options="de

  • angularjs 动态从后台获取下拉框的值方法

    angularjs 动态从后台获取下拉框的值,只要是使用repeat指令,后台提供的是一个list的对象,里面包含value和显示的值,如下: js文件: //职务等级和档次/军衔等级和档次,需要从后台获取:poslist,type:2/3/4/5 $scope.getDyActivityInforItems=function(){ serviceData.getData('inforinput/getAllSelectValueByType','POST',{ type:2 }).then(f

  • AngularJS中下拉框的基本用法示例

    本文实例讲述了AngularJS中下拉框的基本用法.分享给大家供大家参考,具体如下: HTML正文: <div ng-app="myApp" ng-controller="myCtrl"> <select ng-model="selectedName" ng-options="x for x in names"></select> 等价于: <select> <option

  • AngularJS动态生成select下拉框的方法实例

    一.select相关知识 <select> <option value="0">HTML</option> <option value="1">Java</option> <option value="2">Python</option> </select> 其中,value 是存储到数据库的值,在此处为0,1,2这些数值,label 为显示在页面的值

  • Angularjs实现下拉框联动的示例代码

    第一种联动方式,在网上看到的,感觉对于我的使用性不高,比较后端不会提供这种json... 实现截图 html <select ng-model="s1" ng-options="selectData.name for selectData in selectDatas"> <option value="">--产品类目--</option> </select> <select ng-model

  • angularjs 实现带查找筛选功能的select下拉框实例

    一.背景 对于select的下拉列表,像国家选择这样的功能,全世界那么多国家,一直拉滚动条多辛苦,眼睛也要盯着找,累!so,为优化用户体验,带查找功能的下拉框是非常非常有必要的.都知道jquery里有这样的插件,但我们用的是Angularjs,更希望用双向绑定,指令的方式优雅地解决这个问题. 分析:    目标 在原来的<select ng-options="">标签上新加一个属性 select-search 就能支持查找的功能.如果这个属性没起作用,也不影响原来的sele

随机推荐