资讯专栏INFORMATION COLUMN

完善的输入框监听方案:兼容、高效和组合输入友好

Labradors / 2878人阅读

摘要:文章分享了,如何一步步优化输入框的监听事件,以达到兼容高效和组合输入友好等目标。完善的输入框监听方案监听输入框的输入,最原始的方法是使用事件。它只会在输入框的值发生变化后被触发,不过及以下不支持该事件。

文章分享了,如何一步步优化输入框的监听事件,以达到兼容、高效和组合输入友好等目标。

完善的输入框监听方案 keyup

监听输入框的输入,最原始的方法是使用keyup事件。
不使用change事件,它只会在输入框失去焦点后被触发。
此方式兼容性广,但效率较低,毕竟任意的按键都会触发该事件。



input

我们只希望当值发生变化后再触发监听,这样,input事件出现了。
它只会在输入框的值发生变化后被触发,不过IE8及以下不支持该事件。

网上很多人使用IE独有的propertychange事件,作为替代input的方案,这里不推荐。
一方面它会在任意属性值变化后被触发,没有专一性,不够语义,比较浪费。
二方面网上都是用jQuery等工具库操作,比较简单,而我们的目的是用原生代码实现。
三方面是不支持input事件的浏览器已经很少了,硬碰上了就用keyup对付。



接着上步,如何在不支持input事件时使用keyup事件呢?
直接检测事件不太靠谱,可以利用inputkeyup之前发生的性质,巧妙的实现此功能。



延迟函数

在搜索功能中,理想化的情景是当用户全部输入后,再立即执行搜索。
那么问题来了,如何在不需要用户点击搜索按钮的情况下,得知其过程的完成呢?没有办法。
虽然没有办法,但有优化的方式:假定用户每个单词的输入间隔,以此时间延迟执行搜索功能。

英文一般为 300ms ,中文可设置成 500ms 。



composition

中文、日文等需要借助输入法组合输入,即便是英文,现在也可借助组合输入进行选词等。
实际中,我们希望将用户组合输入完的一段文字,而不是每输入一个字母,算做一次输入的完成。

组合输入事件应运而生,常用的是compositionstart(组输开始)和compositionend(组输结束)事件。
结合组合事件不监听普通的输入,以及compositionstart发生在input事件之前,可以如此优化中文输入。



结合

最后是结合以上几步生成一个融合方法,代码加示例:地址。

里面还做了些增强:
比如监听函数返回的是一个,移除这一步所加的所有事件的方法。
比如配置是否监听组合输入事件,因为好的搜索框会直接根据拼音开始搜索,无需等到汉字的形成。

代码使用ES6语法,需使用支持ES6的浏览器(Chrome最新版)或转码后才能使用,谅解。

function listenInput(dom, callback, {
  timeout = 300,
  useCompositionEvent = true
} = {}) {
  let value = "";
  let inInputEvent = false;
  let inCompositionEvent = false;
  let trigger = createDelayFunction(valueChanged, timeout);

  // Return a function that can remove listeners added here.
  return enabledEvent(dom);

  function valueChanged(val) {
    if (val === value) {
      return ;
    } else {
      value = val;
    }

    callback(value, { dom: dom });
  }

  function enabledEvent(dom) {
    dom.addEventListener("keyup", keyup);
    dom.addEventListener("input", input);
    useCompositionEvent && dom.addEventListener("compositionstart", compositionstart);
    useCompositionEvent && dom.addEventListener("compositionend", compositionend);

    return function() {
      dom.removeEventListener("keyup", keyup);
      dom.removeEventListener("input", input);
      useCompositionEvent && dom.removeEventListener("compositionstart", compositionstart);
      useCompositionEvent && dom.removeEventListener("compositionend", compositionend);
    };

    function keyup() {
      if (inInputEvent) {
        dom.removeEventListener("keyup", keyup);
      } else {
        trigger(this.value);
      }
    }
    
    function input() {
      if (!inInputEvent) inInputEvent = true;
      if (!inCompositionEvent) trigger(this.value);
    }
    
    function compositionstart() {
      inCompositionEvent = true;
    }
    
    function compositionend() {
      inCompositionEvent = false;
      trigger(this.value);
    }
  }
}

function createDelayFunction(fn, timeout = 300) {
  let timeoutId = -1;
  return (...args) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      fn.apply(null, args);
    }, timeout);
  }
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95938.html

相关文章

  • 完善输入监听方案兼容高效组合输入友好

    摘要:完善的输入框监听方案监听输入框的输入,最原始的方法是使用事件。它只会在输入框的值发生变化后被触发,不过及以下不支持该事件。组合输入事件应运而生,常用的是组输开始和组输结束事件。 完善的输入框监听方案 keyup 监听输入框的输入,最原始的方法是使用keyup事件。 不使用change事件,它只会在输入框失去焦点后被触发。 此方式兼容性广,但效率较低,毕竟任意的按键都会触发该事件。 ...

    fuyi501 评论0 收藏0
  • 优秀博文收藏(不定期更新)

    摘要:我的书签我的书签谨慎导入,小心覆盖工具类版本管理快速切换源配置教程指南可视化工具前端工具集前端助手网络封包截取工具格式化工具标注工具模拟请求类深入浅出布局你所不知道的动画技巧与细节常用代码黑魔法小技巧,让你少写不必要的,代码更优雅一劳永 我的书签 我的书签(谨慎导入,小心覆盖) 工具类 nvm: node版本管理 nrm: 快速切换npm源 shell: zsh+on-my-zsh配...

    sunsmell 评论0 收藏0
  • 优秀博文收藏(不定期更新)

    摘要:我的书签我的书签谨慎导入,小心覆盖工具类版本管理快速切换源配置教程指南可视化工具前端工具集前端助手网络封包截取工具格式化工具标注工具模拟请求类深入浅出布局你所不知道的动画技巧与细节常用代码黑魔法小技巧,让你少写不必要的,代码更优雅一劳永 我的书签 我的书签(谨慎导入,小心覆盖) 工具类 nvm: node版本管理 nrm: 快速切换npm源 shell: zsh+on-my-zsh配...

    zhangfaliang 评论0 收藏0
  • javascript功能插件大集合 前端常用插件 js常用插件

    摘要:转载来源包管理器管理着库,并提供读取和打包它们的工具。能构建更好应用的客户端包管理器。一个整合和的最佳思想,使开发者能快速方便地组织和编写前端代码的下一代包管理器。很棒的组件集合。隐秘地使用和用户数据。 转载来源:https://github.com/jobbole/aw... 包管理器管理着 javascript 库,并提供读取和打包它们的工具。•npm – npm 是 javasc...

    netmou 评论0 收藏0

发表评论

0条评论

Labradors

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<