1 前言

最近在项目中涉及表单的情况下,需要对用户输入进行过滤,比如填写用户名的时候不可以使用空格或者特殊符号,这里有几个解决方法:

  1. 使用 Angular 的正则同步验证器
  2. 使用 RxJS对输入的值进行替换或者删除
  3. 使用 Event对象 ,阻止事件的默认表现(非禁止传播)

2 各种方案的分析

2.1 正则同步验证器

使用验证器配合输入提示是最直观最容易了解的,但是背后有几个痛点难以解决

  1. 即使知道特定的非法字符,用户也可能在不经意的情况下输入这些字符,在看到错误之后需要用户主动查看自己输入了哪些非法字符并手动删除
  2. 即使将实现的验证器抽取出来成为一个公共方法,在判断表单合法性的时候还要多加一层判断,举个栗子:usernameControl.hasError('invalidChar'),并且显示一个错误

该方法需要实现的 process:

  1. 一个正则同步验证器;
  2. 一个维护非法字符的 Array;
  3. 一层显示输入非法字符的判断与用户提示语句;

由于解决过于繁琐,这里不给出实例。

2.2 RxJS 同步删除值

在习惯了响应式编程后,对于这个场景我们会顺手写下下边的语句

   @ViewChild('usernameInput', {static: true})
usernameInputRel: ElementRef;
invalidChars: string[] = [',', '.', ';', '\[', '\]', '`']; ngAfterViewInit(): void {
this.initI18NMessages();
const usernameE = this.usernameInputRel.nativeElement as HTMLInputElement;
fromEvent(usernameE, 'input')
.pipe(
debounceTime(1000),
)
.subscribe((e: KeyboardEvent) => {
const invalid = asSequence(this.invalidChars).find((c) => usernameE.value.indexOf(c) !== -1);
if (invalid !== null) {
this.messageService.error(`非法输入: ${invalid}`);
}
usernameE.value = usernameE.value.replace(/[,.\/;'\[\]`]/, '');
});
}

让我们审视上边的语句,该方法需要实现的 process:

  1. 在Component 传入一个 Input的 reference;
  2. 根据非法值 Array 维护对应的 RegExp 对象;
  3. 在 Component 的视图渲染完成后订阅这个 reference 的 'input' 事件,查找是否输入中是否含有非法字符;
  4. 给用户非法输入提示;
  5. 同步删除非法字符的值;

2.3 使用 Event对象

2.3.1 使用原生的方法

我们将的 Javascript 代码中的监听模式应用到元素上,当输入的值在禁止范围内,则阻止默认行为,我们不会使用 stopPropagation() 方法,因为它阻止了事件冒泡,如果之后需要在它的扩展父元素上监听事件,代码将会需要修改;同时应该注意到,由于我们没有删除值的步骤,所以需要禁用粘贴功能;

   @ViewChild('passwordInput', {static: true})
passwordInput: ElementRef; ngAfterViewInit(): void {
const input = this.passwordInput.nativeElement as HTMLInputElement;
input.addEventListener('paste', ev => ev.preventDefault());
input.addEventListener('keydown', ev => {
const regExp: RegExp = new RegExp(['\\', ',', '/', '\"'].join('|'), 'gi');
if (regExp.exec(ev.key) !== null) {
ev.preventDefault();
}
});
}

让我们审视这次的实现并与上边对比

  1. 在Component 传入一个 Input的 reference;
  2. 根据非法值 Array 维护对应的 RegExp 对象;
  3. 在 Component 的视图渲染完成后订阅这个 reference 的 'input' 事件,查找是否输入中是否含有非法字符; 在 Component 的视图渲染完成后订阅这个 reference 的 'keydown'与 ‘paste’ 事件,如果事件的 key 在禁止值数组中,调用 preventDefault ,并禁止粘贴动作
  4. 给用户非法输入提示;
  5. 同步删除非法字符的值;

2.3.1 使用 Directive

如果需要在多个表单元素上应用上边的代码,代码将变得非常臃肿,因此我们将借助 Angular 的 Directive ,先构想一些组件中需要的实现:

  1. 组件需要知道哪些值是被禁止的,并且禁止相应的输入
  2. 组件需要禁止粘贴动作

那么,当应用到 Input 元素上,它应该是这样子的:

 <input  [crxBlockKeys]="blockNameChars" type="text"    />

blockNameChars 是从 component 获得的,它的值是:

const blockNameChars: string[] = [' ', '/', '\''];

或者这样子应用:

 <input  [crxBlockKeys]="[' ', '\\', '\'']" type="text"    />

现在让我们手动实现:

 @Directive({selector: '[crxBlockKeys]'})
export class BlockKeysDirective {
@Input('crxBlockKeys')
blockKeys: string[]; /**
* @see DocumentAndElementEventHandlersEventMap.paste
* @param e ClipboardEvent
*/
@HostListener('paste', ['$event'])
preventPaste(e: Event): void {
e.preventDefault();
} /**
* @see WindowEventMap.keydown
* @param e KeyboardEvent
*/
@HostListener('keydown', ['$event'])
preventEmptyInput(e: KeyboardEvent): void {
const regExp: RegExp = new RegExp(this.blockKeys.join('|'), 'gi');
if (regExp.exec(e.key) !== null) {
e.preventDefault();
}
}
}

现在我们的代码得到了复用,当需要使用的时候,只需要在 input 内加入这个属性,并传入禁止的数值组;

如果你抗拒写转义字符,可以使用下边的 Directive,我们更改传入数值组为 Code  (eg: ['Semicolon', 'NumpadDivide', 'Space']):

 @Directive({selector: '[crxBlockCodes]'})
export class BlockCodesDirective {
@Input('crxBlockCodes')
blockCodes: string[]; /**
* @see DocumentAndElementEventHandlersEventMap.paste
* @param e ClipboardEvent
*/
@HostListener('paste', ['$event'])
preventPaste(e: Event): void {
e.preventDefault();
} /**
* @see WindowEventMap.keydown
* @param e KeyboardEvent
*/
@HostListener('keydown', ['$event'])
preventEmptyInput(e: KeyboardEvent): void {
const regExp: RegExp = new RegExp(this.blockCodes.join('|'), 'gi');
if (e.code.match(regExp).length !== 0) {
e.preventDefault();
}
}
}

让我们审视这次的实现并与上边对比

  1. 在Component 传入一个 Input的 reference;  在输入标签中加入 属性 crxBlockKeys 并传入禁止的数值组;
  2. 根据非法值 Array 维护对应的 RegExp 对象;
  3. 在 Component 的视图渲染完成后订阅这个 reference 的 'keydown'与 ‘paste’ 事件,如果事件的 key 在禁止值数组中,调用 preventDefault ,并禁止粘贴动作 

3 总结

我们的实现需要的步骤变化为: 5  >  3 > 1 ,这个改变是巨大的,同时,代码的复用性与稳定性也有了很大改善

4 额外的内容

你可以从这里查找 key 值或者这里查找 code  值

你也可以使用这个在线工具快速获取 key 与 code 值

Angular 输入中的禁止特定输入值--Validator 与 Directive 实现的更多相关文章

  1. gulp 在 angular 项目中的使用

    gulp 在 angular 项目中的使用 keyword:gulp,angularjs,ng,ngAnnotate,jshint,gulpfile 最后附完整简洁的ng项目gulpfile.js 准 ...

  2. 一个Angular模块中可以声明哪些组件?

    一个Angular模块中可以声明哪些组件? (1) controller        控制器 (2) directive                指令 (3) function         ...

  3. JS-只能输入中文和英文

    <span style="font-family:KaiTi_GB2312;">转自:<a target=_blank href="http://www ...

  4. 怎样在PDF文件中查找某个特定的词?

    不得不说中国的修饰词太多了例如:“滚”可以这样说,请你以一种圆润的方式离开:上次小编在路上听到某男子打电话,好像是给女孩子,那口才,是真的牛,夸人不带重复的.要不是我男孩子,我都想以身相许了.人们常常 ...

  5. nginx禁止特定UA访问

    一.UA是什么? User Agent 简称UA,就是用户代理.通常我们用浏览器访问网站,在网站的日志中,我们的浏览器就是一种UA. 二.禁止特定UA访问 最近有个网站(www.C.com)抄袭公司主 ...

  6. 如何在Word中批量选中特定文本

    如何在Word中批量选中特定文本 举个例子,我们对如下文本进行操作,将文本中所有的“1111111”标红,所有的“2222222”标绿,所有的“3333333”标蓝 在Word中找到“查找”下的“高级 ...

  7. emacs: 文本输入中文件目录自动补全

    emacs: 文本输入中文件目录自动补全 // */ // ]]> UP | HOME   emacs: 文本输入中文件目录自动补全 Table of Contents 1 引言 2 补全过程演 ...

  8. Angular JS中的依赖注入

    依赖注入DI angularjs中与DI相关有angular.module().angular.injector(). $injector.$provide. DI 容器3要素:服务的注册.依赖关系的 ...

  9. 解决eclipse-helios中Errors running builder JavaScript Validator的问题

    原文:http://blog.ywxyn.com/index.php/archives/713 解决eclipse-helios中Errors running builder JavaScript V ...

随机推荐

  1. Sql批量插入时如果遇到相同的数据怎么处理

    测试数据 -- 创建测试表1 CREATE TABLE `testtable1` ( `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `UserId` I ...

  2. LeetCode Lect7 堆及其应用

    概述 堆是一颗完全二叉树.分为大根堆(父节点>=所有的子节点)和小根堆(父节点<=所有的子节点). 插入.删除堆顶都是O(logN),查询最值是O(1). 完全二叉树(Complete B ...

  3. 浅谈原生JavaScript的动画和特效

    一.JavaScript中的动画原理 动画效果的实现总的来说可分为两种,一种是利用纯css实现,该方法在css3成熟后广泛应用:另外一种是通过JavaScript(或者一些封装的库如jQuery的an ...

  4. v-cloak解决Vue双大括号闪烁问题

    相信不少人和我一样,初次查看一个技术的文档的时候,知识吸收的很慢,因为对这个技术的不熟悉导致不清楚各种操作的应用场景,当我意识到这件事之后,我决定换种学习思路,即以实战为主,卡壳就查文档,会对这个技术 ...

  5. passwd - 密码文件

    描述 Passwd 是个文本文件, 它包含了一个系统帐户列表, 给出每个帐户一些有用的信息,比如用户 ID,组 ID, 家目录, shell,等. 通常它也包含了每个用户经过加密的密码. 它通常应该是 ...

  6. mysql清空表数据并重置自增ID

    mysql清空表数据并重置自增ID: ## 查看mysql> select * from work_order_company;mysql> show create table work_ ...

  7. python的list内存分配算法

    前提:python为了提高效率会为list预先分配一定的内存空间供其使用,避免在每次append等操作都去申请内存,下面简单分析下list的内存分配算法,主要就是两段. 1.当没有元素时,newsiz ...

  8. window 批处理脚本获取上级目录

    1 SET CurrDir=%CD% CD.. SET InstPath=%CD% CD %CurrDir% 2 pushd.. set parent=%cd% popd 参考: https://ms ...

  9. Multisim

    万用表 测量电压.电流.电阻 直流.交流 函数发生器XFG 正极.负极.公共端 可以产生正弦波.三角波和矩形波,可以设置信号参数:频率.占空比.幅度和偏移量等 示波器XSC 双通道示波器 4个连接点, ...

  10. 2019届校招前端面试题整理——HTML、CSS篇

    前言 2019届校招陆陆续续开始了,整理了一些高频的面试题. HTML部分 1. 什么是<!DOCTYPE>? DOCTYPE是html5标准网页声明,且必须声明在HTML文档的第一行.来 ...