合成事件在san.js中的应用

news2024/12/25 23:33:46

一、 什么是合成事件

DOM3 Event 新增了合成事件(CompositionEvent ), 用于处理通常使用 IME 输入时的复杂输入序列。

二、合成事件常见事件

  1. compositionstart:文本合成系统如 IME(即输入法编辑器)开始新的输入合成时会触发 compositionstart 事件。
  2. compositionupdate :事件触发于字符被输入到一段文字的时候
  3. compositionend:当文本段落的组成完成或取消时,compositionend 事件将被触发

合成事件在很多方面与输入事件很类似。在合成事件触发时,事件目标是接收文本的输入字段。唯
一增加的事件属性是 data,其中包含的值视情况而异:

  • 在 compositionstart 事件中,包含正在编辑的文本(例如,已经选择了文本但还没替换);
  • 在 compositionupdate 事件中,包含要插入的新字符;
  • 在 compositionend 事件中,包含本次合成过程中输入的全部内容。

与文本事件类似,合成事件可以用来在必要时过滤输入内容。可以像下面这样使用合成事件:

<input id="myText" type="text"/>
 <script>![请添加图片描述](https://img-blog.csdnimg.cn/481e6c9238ad45dcaabedfb9adcbff26.png)

     let textbox = document.getElementById("myText");
     textbox.addEventListener("compositionstart", (event) => {
         console.log('compositionstart', event.data);
     });
     textbox.addEventListener("compositionupdate", (event) => {
         console.log('compositionupdate', event.data);
     });

     textbox.addEventListener("compositionend", (event) => {
         console.log('compositionend', event.data);
     });
 </script>

请添加图片描述

三、合成事件的使用场景

需求背景:根据input输入的文字进行列表过滤。
需求实现

<template>
  <div class="kh-idx">
    <input v-model="inputVal" type="text" />
    <ul class="kh-idx-ul">
      <li v-for="item in filteredList" :key="item" class="kh-idx-li">
        {{ item }}
      </li>
    </ul>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';

export default defineComponent({
  name: 'KhIndex',
  setup() {
    return {
      inputVal: ref(''),
      list: ref([
        '爱与希望',
        '花海',
        'Mojito',
        '最长的电影',
        '爷爷泡的茶'
      ])
    }
  },
  computed: {
    filteredList() {
      if (!this.inputVal) {
        return this.list;
      }
      return this.list.filter(item => item.indexOf(this.inputVal) > -1);
    }
  },
});
</script>

<style lang="less" scoped>
/** define kh-idx */
.kh-idx {

  &-ul {
    padding: 15px 8px;
    border: 1px solid #9c27b0;
  }

  &-li {
    padding: 4px 2px;
    border: 1px solid gainsboro;
  }
}
</style>

虽然能实现该功能,但是在使用中文进行输入时会有拼音到字符转变的时间,这段时间是没有办法实现过滤的。效果如下
请添加图片描述
为了优化该场景,可以使用compositionstart和compositionend相关事件进行优化。代码如下

<template>
  <div class="kh-idx">
    <input 
      v-model="inputVal"
      type="text"
      @compositionupdate="handleCompositionUpdate"
      @compositionend="handleCompositionEnd"
    />
    <ul class="kh-idx-ul">
      <li v-for="item in filteredList" :key="item" class="kh-idx-li">
        {{ item }}
      </li>
    </ul>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';

export default defineComponent({
  name: 'KhIndex',
  setup() {
    let inputVal = ref('');
    const handleCompositionUpdate = (e: CompositionEvent) => {
      console.log('handleCompositionUpdate', e.data);
      inputVal.value = e.data;
    };

    const handleCompositionEnd = (e: CompositionEvent) => {
      console.log('handleCompositionEnd', e.data);
      inputVal.value = e.data;
    };

    return {
      inputVal,
      list: ref([
        '爱与希望',
        '花海',
        'Mojito',
        '最长的电影',
        '爷爷泡的茶'
      ]),
      handleCompositionUpdate,
      handleCompositionEnd
    }
  },
  computed: {
    filteredList() {
      if (!this.inputVal) {
        return this.list;
      }
      return this.list.filter(item => item.indexOf(this.inputVal) > -1);
    }
  },
});
</script>

<style lang="less" scoped>
/** define kh-idx */
.kh-idx {

  &-ul {
    padding: 15px 8px;
    border: 1px solid #9c27b0;
  }

  &-li {
    padding: 4px 2px;
    border: 1px solid gainsboro;
  }
}
</style>

请添加图片描述
请添加图片描述

四、san.js 中合成事件的应用

function elementOwnAttached() {
    if (this._rootNode) {
        return;
    }

    var isComponent = this.nodeType === NodeType.CMPT;
    var data = isComponent ? this.data : this.scope;

    /* eslint-disable no-redeclare */

    // 处理自身变化时双向绑定的逻辑
    var xProps = this.aNode._xp;
    for (var i = 0, l = xProps.length; i < l; i++) {
        var xProp = xProps[i];

        switch (xProp.name) {
            case 'value':
                switch (this.tagName) {
                    case 'input':
                    case 'textarea':
                        if (isBrowser && window.CompositionEvent) {
                            elementOnEl(this, 'change', inputOnCompositionEnd);
                            elementOnEl(this, 'compositionstart', inputOnCompositionStart);
                            elementOnEl(this, 'compositionend', inputOnCompositionEnd);
                        }

                        // #[begin] allua
                        /* istanbul ignore else */
                        if ('oninput' in this.el) {
                        // #[end]
                            elementOnEl(this, 'input', getInputXPropOutputer(this, xProp, data));
                        // #[begin] allua
                        }
                        else {
                            elementOnEl(this, 'focusin', getInputFocusXPropHandler(this, xProp, data));
                            elementOnEl(this, 'focusout', getInputBlurXPropHandler(this));
                        }
                        // #[end]

                        break;

                    case 'select':
                        elementOnEl(this, 'change', getXPropOutputer(this, xProp, data));
                        break;
                }
                break;

            case 'checked':
                switch (this.tagName) {
                    case 'input':
                        switch (this.el.type) {
                            case 'checkbox':
                            case 'radio':
                                elementOnEl(this, 'click', getXPropOutputer(this, xProp, data));
                        }
                }
                break;
        }
    }

    var owner = isComponent ? this : this.owner;
    for (var i = 0, l = this.aNode.events.length; i < l; i++) {
        var eventBind = this.aNode.events[i];

        // #[begin] error
        warnEventListenMethod(eventBind, owner);
        // #[end]

        elementOnEl(
            this, 
            eventBind.name,
            getEventListener(eventBind, owner, data, eventBind.modifier),
            eventBind.modifier.capture
        );
    }

    if (isComponent && this.nativeEvents) {
        for (var i = 0, l = this.nativeEvents.length; i < l; i++) {
            var eventBind = this.nativeEvents[i];

            // #[begin] error
            warnEventListenMethod(eventBind, this.owner);
            // #[end]

            elementOnEl(
                this, 
                eventBind.name,
                getEventListener(eventBind, this.owner, this.scope),
                eventBind.modifier.capture
            );
        }
    }

    var transition = elementGetTransition(this);
    if (transition && transition.enter) {
        try {
            transition.enter(this.el, empty);
        }
        catch (e) {
            handleError(e, isComponent ? owner.parentComponent : owner, 'transitionEnter');
        }
    }
}

在上面的代码中,san对input 双向数据绑定时,监听了compositionstart和compositionend事件,然后两个事件处理函数也不是很麻烦,如下

/**
 * 双绑输入框CompositionEnd事件监听函数
 *
 * @inner
 */
function inputOnCompositionEnd() {
    if (!this.composing) { // 只有 composing 不为 1 时,后续才不执行
        return;
    }

    this.composing = 0;
    trigger(this, 'input'); // 触发 input 事件,trigger 函数中是自定义的 input 事件,这样用于定义的input事件就得意执行
}

/**
 * 双绑输入框CompositionStart事件监听函数
 *
 * @inner
 */
function inputOnCompositionStart() {
    this.composing = 1; // composing 为 1 表示正在合成(composing)
}

/**
 * 触发元素事件
 *
 * @inner
 * @param {HTMLElement} el DOM元素
 * @param {string} eventName 事件名
 */
function trigger(el, eventName) {
    var event = document.createEvent('HTMLEvents');
    event.initEvent(eventName, true, true);
    el.dispatchEvent(event); // 触发自定义事件
}

这样san就解决了使用input事件时,在输入汉字中没有出发input事件的情况。效果如下
请添加图片描述
参考文章

  1. js中compositionstart和compositionend事件
  2. javascript 高级程序设计(第四版)
  3. CompositionEvent

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1224295.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【STM32】DMA(直接存储器访问)

一、DMA本质 在ADC中使用FIFO&#xff08;先进先出&#xff09;&#xff0c;当FIFO快满的时候&#xff0c;产生一个中断。在中断的时候将数据传输到SRAM&#xff0c;但是此时还是需要CPU的参与&#xff0c;但是CPU就不会一直在等待。【但是这个方法还是不能完全解决问题】 此时…

【代码随想录】算法训练计划25

1、216. 组合总和 III 题目&#xff1a; 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9 每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 思路&am…

LeetCode Hot100之十:239.滑动窗口最大值

题目 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 提示&#xff1a; 1 < nums.length < 10^5 -10^4 < nums[i…

nginx关闭重启和配置检查

优雅关闭Nginx 找出nginx的进程号&#xff1a;ps -ef | grep nginx 执行命令&#xff1a;kill -QUIT 主pid 注意&#xff1a; 其中pid是主进程号的pid&#xff08;master process&#xff09;&#xff0c;其他为子进程pid&#xff08;worker process&#xff09; 这种关闭方式…

《全程软件测试 第三版》拆书笔记

第一章 对软件测试的全面认识&#xff0c;测试不能是穷尽的 软件测试的作用&#xff1a; 1.产品质量评估&#xff1b;2.持续质量反馈&#xff1b;3.客户满意度提升&#xff1b;4.缺陷的预防 正反思维&#xff1a;正向思维&#xff08;广度&#xff0c;良好覆盖面&#xff09;逆…

App测试经典面试题及参考答案

最近整理了一些关于App测试的面试题。 本参照答案是本人在工作实践中总结&#xff0c;仅代表个人观点&#xff0c;如有错误&#xff0c;请谅解。 1、说一些你在测试过程中常用到的adb命名 2、APP测试与web测试的区别&#xff1f; 3、APP闪退有哪些原因造成的&#xff1f; …

【C#】字符串拼接相关

目录 1.字符串拼接方式1 用号进行字符串拼接 复合运算符 2.字符串拼接方式2 3.控制台打印拼 4.例子 1.字符串拼接方式1 之前的算数运算符 只是用来数值类型变量进行数学运算的而 string 不存在算数运算符 不能计算 但是可以通过号来进行字符串拼接 用号进行字符串拼接 …

为了 Vue 组件测试,你需要为每个事件绑定的方法加上括号吗?

本文由华为云体验技术团队松塔同学分享 先说结论&#xff0c;当然不是&#xff01;Vue 组件测试&#xff0c;尤其是组件触发事件的测试&#xff0c;有成熟的示例。我们同样要关注测试的原则&#xff0c;例如将组件当成黑盒&#xff0c;不关心其内部实现&#xff0c;而只关心与其…

机器人制作开源方案 | 智能快递付件机器人

一、作品简介 作者&#xff1a;贺沅、聂开发、王兴文、石宇航、盛余庆 单位&#xff1a;黑龙江科技大学 指导老师&#xff1a;邵文冕、苑鹏涛 1. 项目背景 受新冠疫情的影响&#xff0c;大学校园内都采取封闭式管理来降低传染的风险&#xff0c;导致学生不能外出&#xff0c…

网络和Linux网络_3(套接字编程)TCP网络通信代码(多个版本)

目录 1. TCP网络编程 1.1 前期代码 log.hpp tcp_server.cc 1.2 accept和单进程版代码 1.3 多进程版strat代码 1.4 client.cc客户端 1.5 多进程版strat代码改进多线程 1.6 线程池版本 Task.hpp lockGuard.hpp thread.hpp threadPool.hpp 多个回调任务 tcp_client…

【电路笔记】-最大功率传输

最大功率传输 文章目录 最大功率传输1、概述2、最大功率传输定理 (MPTT)3、示例4、阻抗匹配5、总结 当工程师设计电子电路时&#xff0c;他们会跟踪许多不同的参数&#xff0c;但最重要的参数之一是功率。 在现代电路中&#xff0c;功率在多个阶段中不断变化&#xff0c;有时由…

(论文阅读46-50)图像描述2

46.文献阅读笔记 简介 题目 Learning a Recurrent Visual Representation for Image Caption Generation 作者 Xinlei Chen, C. Lawrence Zitnick, arXiv:1411.5654. 原文链接 http://www.cs.cmu.edu/~xinleic/papers/cvpr15_rnn.pdf 关键词 2014年rnn图像特征和文本特…

算法-二叉树-简单-二叉树的遍历

记录一下算法题的学习6 首先我们要回忆一下怎么样遍历一个树&#xff1a; 三种遍历概念 先序遍历&#xff1a;先访问根节点&#xff0c;再访问左子树&#xff0c;最后访问右子树。 后序遍历&#xff1a;先左子树&#xff0c;再右子树&#xff0c;最后根节点。 中序遍历&…

常见的近似算法

前言 最近有个项目要用到近似算法&#xff0c;就到处摸了下&#xff0c;整理了一个小结。 近似算法统计 在Java中&#xff0c;你可以使用各种近似算法来解决不精确但接近于最优解的问题。以下是几种常见的近似算法的实现方法&#xff1a; 贪心算法&#xff08;Greedy Algori…

常见的反爬+文字加解密

一、常见的反爬介绍 基于身份识别的反爬&#xff1a;1.User-agent 2.Referer 3.Captcha 验证码 4.必备参数 基于爬虫行为的反爬&#xff1a;1.单位时间内请求数量超过一定阈值 2.相邻两次请求之间间隔小于一定阈值3.蜜罐陷阱 通过对数据加密进行反爬&#xff1a;1.对文字加密…

记录联系ThinkPad T490扬声器无声音但插耳机有声音的解决办法

型号&#xff1a;联想ThinkPad T490&#xff0c;系统Win10 64位。 现象&#xff1a;扬声器无声音&#xff0c;插耳机有声音。且右下角小喇叭正常&#xff0c;设备管理器中驱动显示一切也都正常&#xff08;无黄色小叹号&#xff09;。 解决办法&#xff1a; 尝试了各种方法&a…

【机器学习Python实战】logistic回归

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;机器学习python实战 欢迎订阅&#xff01;后面的内容会越来越有意思~ ⭐内容说明&#xff1a;本专栏主要针对机器学习专栏的基础内容进行python的实现&#xff0c;部分…

带你快速掌握Linux最常用的命令(图文详解)- 最新版(面试笔试常考)

最常用的Linux指令&#xff08;图文详解&#xff09;- 最新版 ls&#xff1a;列出目录中的文件和子目录。&#xff08;重点&#xff09;cd&#xff1a;改变当前工作目录。绝对路径&#xff1a;相对路径 pwd&#xff1a;显示当前工作目录的路径。mkdir&#xff1a;创建一个新的目…

盘点60个Python各行各业管理系统源码Python爱好者不容错过

盘点60个Python各行各业管理系统源码Python爱好者不容错过 学习知识费力气&#xff0c;收集整理更不易。 知识付费甚欢喜&#xff0c;为咱码农谋福利。 源码下载链接&#xff1a;https://pan.baidu.com/s/1VdAFp4P0mtWmsA158oC-aA?pwd8888 提取码&#xff1a;8888 项目名…

c语言-浅谈指针(3)

文章目录 1.字符指针变量常见的字符指针初始化另一种字符指针初始化例&#xff1a; 2.数组指针变量什么是数组指针变量数组指针变量创建数组指针变量初始化例&#xff08;二维数组传参的本质&#xff09; 3.函数指针变量什么是函数指针变量呢&#xff1f;函数指针变量创建函数指…