惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

腾讯CDC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 叶小钗
人人都是产品经理
人人都是产品经理
博客园 - 聂微东
The Cloudflare Blog
爱范儿
爱范儿
阮一峰的网络日志
阮一峰的网络日志
WordPress大学
WordPress大学
小众软件
小众软件
博客园 - 三生石上(FineUI控件)
Last Week in AI
Last Week in AI
Jina AI
Jina AI
V
V2EX
罗磊的独立博客
V
Visual Studio Blog
A
About on SuperTechFans
IT之家
IT之家
P
Proofpoint News Feed
B
Blog
博客园 - Franky
Blog — PlanetScale
Blog — PlanetScale
Google DeepMind News
Google DeepMind News
Y
Y Combinator Blog

zodream梦想开源/个人编程日记

文件解析笔记-zodream梦想开源/个人编程日记 密码本开发笔记之读写与保存-zodream梦想开源/个人编程日记 SkiaSharp 把 pixel byte[] 转成 SKBitmap-zodream梦想开源/个人编程日记 nas 使用 Docker 安装 gogs-zodream梦想开源/个人编程日记 复制 android 手机中的文件到电脑-zodream梦想开源/个人编程日记 周报:寻找优质的周刊-zodream梦想开源/个人编程日记 开发日志:对Markdown的代码块新增引用来源支持-zodream梦想开源/个人编程日记 周报:怎么写技术类的教程文章-zodream梦想开源/个人编程日记 css display:flex 布局尺寸超出问题-zodream梦想开源/个人编程日记 周报:SEO优化的思考-zodream梦想开源/个人编程日记 Edge 浏览器不适用 Edge Image Viewer 打开图片 -zodream梦想开源/个人编程日记 SEO 学习笔记(一) 内容来源-zodream梦想开源/个人编程日记 PHP 实现双因素身份认证(2FA)-zodream梦想开源/个人编程日记 WPF MVVM 获取List 多选数据-zodream梦想开源/个人编程日记 Burp Suite 抓包-zodream梦想开源/个人编程日记 使用 indexnow 注意事项-zodream梦想开源/个人编程日记 Godot 使用字体图标 例如: Iconfont、FontAwesome-zodream梦想开源/个人编程日记 angular 15 对指定页面进行访问限制-zodream梦想开源/个人编程日记 CSS 使用 column-count 实现瀑布流出现内容分割的解决办法-zodream梦想开源/个人编程日记 input 确认按键事件在手机端不生效-zodream梦想开源/个人编程日记 C# 使用socket 进行通讯-zodream梦想开源/个人编程日记 Maui开发中Windows应用开启管理员权限-zodream梦想开源/个人编程日记 Maui 中自定义控件-zodream梦想开源/个人编程日记 angular 14 使用 ng-template 实现tree 结构显示-zodream梦想开源/个人编程日记 c# 动态安装和卸载dll-zodream梦想开源/个人编程日记 慎用 CompositionTarget.Rendering-zodream梦想开源/个人编程日记 c# 重写 c++ 程序笔记:数据初始化-zodream梦想开源/个人编程日记 源码编译 aseprite-zodream梦想开源/个人编程日记 记录一下字符串分隔split各语言之间的不同-zodream梦想开源/个人编程日记 c# Gzip解码无头内容-zodream梦想开源/个人编程日记
angular 15 实现按下确认键,焦点移动到下一个表单或提交表单...
zodream · 2023-03-30 · via zodream梦想开源/个人编程日记

angular 15 实现按下确认键,焦点移动到下一个表单或提交表单

需求:登录界面,输入账户后,按下回车键,焦点移动到密码输入框,再次按下回车键,直接提交表单

实现方法

import { Directive, ElementRef, HostListener, Input, OnDestroy, OnInit } from '@angular/core';


@Directive({
    selector: '[appFocusNext]'
})
export class FocusNextDirective implements OnInit, OnDestroy {

    static InputItems: FocusNextDirective[] = [];

    /**
     * 分组
     */
    @Input() public appFocusNext: any = 0;
    /**
     * 排序,越大越往后
     */
    @Input() public order = 0;

    constructor(
        private elementRef: ElementRef,
    ) { }

    @HostListener('keydown', ['$event'])
    onKeydown(e: KeyboardEvent) {
        if (e.key !== 'Enter') {
            return;
        }
        e.preventDefault();
        e.stopPropagation();
        FocusNextDirective.FocusNext(this);
    }


    ngOnInit(): void {
        FocusNextDirective.Add(this);
    }

    ngOnDestroy(): void {
        FocusNextDirective.Remove(this);
    }

    /**
     * 移动焦点到当前项
     * @returns 
     */
    public focus() {
        if (!this.elementRef.nativeElement) {
            return;
        }
        const element = this.elementRef.nativeElement;
        const tagName = element.tagName.toLocaleLowerCase();
        if (tagName === 'textarea' || tagName === 'select') {
            (element as HTMLTextAreaElement).focus();
            return;
        }
        if (tagName === 'input') {
            const type = (element as HTMLInputElement).type.toLocaleLowerCase();
            console.log(type);

            if (type === 'button' || type === 'submit' || type === 'reset') {
                element.click();
                return;
            }
            (element as HTMLInputElement).focus();
            return;
        }
        if (tagName === 'form') {
            (element as HTMLFormElement).submit();
            return;
        }
        element.click();
    }

    /**
     * 注册到可操作项
     * @param item 
     * @returns 
     */
    private static Add(item: FocusNextDirective) {
        if (this.InputItems.indexOf(item) >= 0) {
            return;
        }
        this.InputItems.push(item);
    }

    /**
     * 移除当前
     * @param item 
     */
    private static Remove(item: FocusNextDirective) {
        const i = this.InputItems.indexOf(item);
        if (i >= 0) {
            this.InputItems.splice(i, 1);
        }
    }

    /**
     * 根据当前触发,移动焦点到下一项
     * @param source 
     */
    private static FocusNext(source: FocusNextDirective) {
        let found = false;
        let next: FocusNextDirective = undefined;
        for (const item of this.InputItems) {
            if (item.appFocusNext !== source.appFocusNext) {
                continue;
            }
            if (item === source) {
                found = true;
                continue;
            }
            if (item.order < source.order || (!found && item.order === source.order)) {
                continue;
            }
            if (item.order === source.order && found) {
                next = item;
                break;
            }
            if (!next) {
                next = item;
                continue;
            }
            if (next.order > item.order) {
                next = item;
                continue;
            }
        }
        next?.focus();
    }
}

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132

使用方法


<input appFocusNext>
<input appFocusNext>
<button appFocusNext>提交</button>


<input appFocusNext="1">
<button appFocusNext="1" [order]="1">提交</button>
<input appFocusNext="1">

123456789

参数说明

appFocusNext 属性值是作为分组使用

order 作为排序用,数字越大排在后面,最后触发,默认按照初始化顺序

缺陷或不足

  1. 自定义的组件,暂时没有找到办法获取对象,只获取到了HTMLElement
  2. 不会验证表单的内容
  3. 不会自动触发上层表单

转载请保留原文链接: https://zodream.cn/blog/id/238.html