本文同时也发布在了个人 我的博客中
不少网站发帖的时候标签输入框看起来像是在 <input>
元素中直接显示标签. 好比这种bash
一开始觉得是把 <span>
放在 <input>
中, 看了下 Stack Overflow 和 SegmentFault 的实现方式, 原来是用一个 <div>
把 <span>
和 <input>
包起来, 而后让 <div>
模仿出输入框的样式. 再给 <div>
加上eventListensor, 点击 <div>
时, 使 <input>
得到焦点.app
将各个tag用 <span>
显示, 在同一行放一个 <input>
用来输入新的标签, 而后用一个 <div>
将它们包起来网站
<div>
<span *ngFor="let tag of tags">{{tag}}</span>
<input type="text">
</div>复制代码
以后给 <div>
加上一个事件监听器, 点击 <div>
的时候, 激活 <input>
. 为了可以获取 <input>
元素, 使用 Angular的 Template reference variables 来命名 <input>
.ui
<div (click)="focusTagInput()">
<span *ngFor="let tag of tags">{{tag}}</span>
<input #tagInput type="text">
</div>复制代码
在component中得到 <input>
元素this
export class EditorComponent {
// 用 @ViewChild 得到 DOM 元素
@ViewChild('tagInput') tagInputRef: ElementRef;
focusTagInput(): void {
// 让 input 元素得到焦点
this.tagInputRef.nativeElement.focus();
}
}复制代码
到此基本上总体思路就实现了. 接下来就是完善一下细节. 好比spa
咱们一步一步来.code
给 <input>
元素添加一个事件监听, 能够监听键盘按下了哪一个键. 和键盘按键有关的事件有 keydown
, keypress
, keyup
.component
根据 MDN 上的解释, keydown
和 keypress
都是在按键按下以后触发, 不一样点在于, 全部按键均可以触发 keydown
, 而 keypress
只有按下能产生字符的键时才触发, shift
, alt
这些按键不会触发 keypress
. 并且 keypress
从 DOM L3 以后就弃用了.orm
keyup
就是松开按键的时候触发.
首先给 <input>
标签添加事件监听 (这里用的 keyup
, 后面会解释为何不用 keydown
).
<input #tagInput type="text" (keyup)="onKeyup($event)">复制代码
component 中对接收到的 KeyboardEvent
进行处理
onKeyup(event: KeyboardEvent): void {
// 这里将标签输入框做为 FormGroup 中的一个 control
const inputValue: string = this.form.controls.tag.value;
// 检查键盘是否按下了逗号或者空格, 并且得要求
if (event.code === 'Comma' || event.code === 'Space') {
this.addTag(inputValue);
// 将新输入的标签加入标签列表后, 把输入框清空
this.form.controls.tag.setValue('');
}
}
addTag(tag: string): void {
// 去掉末尾的逗号或者空格
if (tag[tag.length - 1] === ',' || tag[tag.length - 1] === ' ') {
tag = tag.slice(0, -1);
}
// 有可能什么也没输入就直接按了逗号或者空格, 若是已经在列表中, 也不添加
// 这里使用了 lodah 的 find
if (tag.length > 0 && !find(this.tags, tag)) {
this.tags.push(tag);
}
}复制代码
使用
keyup
而不是keypress
的缘由:一开始我是用的
keypress
, 可是keypress
触发的时候,<input>
还没接收到按键的值, 因此就会出现标签添加到列表, 而且清空输入框后, 输入框才接收到按下的逗号, 因而刚刚清空的输入框中就出现了一个逗号.
keyup
是在释放按键以后才触发, 此时输入框已经接收到按下的逗号的值, 再清空输入框的时候就能把逗号一块儿清除掉
就在每一个标签旁边添加一个叉号 ×
, 点击的时候, 把标签从列表中移除就好了
<div (click)="focusTagInput()">
<span *ngFor="let tag of tags">
{{tag}}
<span (click)="removeTag(tag)">×</span>
</span>
<input #tagInput type="text" (keyup)="onKeyup($event)">
</div>复制代码
removeTag(tag: string): void {
this.tags.splice(-1);
}复制代码
不须要给DOM添加别的事件监听, 只须要对component中的方法稍加修改便可
onKeyUp(event: KeyboardEvent): void {
const inputValue: string = this.form.controls.tag.value;
// 按下退格键, 且输入框是空的时候, 删除最后一个标签
if (event.code === 'Backspace' && !inputValue) {
this.removeTag();
return;
} else {
if (event.code === 'Comma' || event.code === 'Space') {
this.addTag(inputValue);
this.form.controls.tag.setValue('');
}
}
}
// 修改参数为可选参数, 当没有参数时, 删除列表中最后一个,
// 有参数时, 删除传入的标签
removeTag(tag?: string): void {
if (!!tag) {
// 这里使用了 lodash 的 pull
pull(this.tags, tag);
} else {
this.tags.splice(-1);
}
}复制代码
接下来就是调整样式了. 就略过了