js中compositionstart和compositionend事件

需求

最近有个需求,根据input输入的文字进行列表过滤。这是个很常见的需求。于是大致的代码如下:

<template>
  <div id="app">
    <input type="text" :value="filterText" @input="onInput" />
    <ul>
      <li v-for="item in filteredList" :key="item">
        {{ item }}
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  name: "app",
  data() {
    return {
      filterText: "",
      list: [
        "爱与希望",
        "花海",
        "Mojito",
        "最长的电影",
        "爷爷泡的茶"
      ]
    };
  },
  computed: {
    filteredList() {
      if (!this.filterText) {
        return this.list;
      }
      return this.list.filter(item => item.indexOf(this.filterText) > -1);
    }
  },
  methods: {
    onInput(e) {
      this.filterText = e.target.value;
    }
  }
};
</script>

在输入框中监听input事件,然后触发filteredList列表的改变。

一切都是那么自然。

然而当我们输入中文的时候,由于拼音会先显示,导致在输入中文的过程中,触发筛选的列表空的,最后中文显示出来的时候,才会有显示结果。

compositionstart和compositionend

于是在网上搜索有这么两个事件, compositionstartcompositionend

MDN: https://developer.mozilla.org/zh-CN/docs/Web/Events/compositionstart

当用户使用拼音输入法开始输入汉字时,compositionstart事件就会被触发。当文本段落的组成完成或取消时, compositionend 事件将被触发。

也就是说,在我们开始输入中文的时候会触发一次compositionstart事件,中文输入过程中不会再出发compositionstart事件,最后输入中文完成触发compositionend 事件。

而且经过试验发现,在输入中文的时候,compositionstart先于input事件触发。

有了这个前提那这就好办了,我只需打个标 lock,当compositionstart触发时, lock=true,当compositionend触发时, lock=false。只有在lock为false的时候,才执行input事件中的筛选操作。

代码变成如下:

<template>
  <div id="app">
    <input type="text" :value="filterText" 
        @input="onInput" 
        @compositionstart="onCompositionStart"
        @compositionend="onCompositionEnd"
        />
    <ul>
      <li v-for="item in filteredList" :key="item">
        {{ item }}
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  name: "app",
  data() {
    return {
      filterText: "",
      list: [
        "爱与希望",
        "花海",
        "Mojito",
        "最长的电影",
        "爷爷泡的茶"
      ],
      lock; false, // 打标
    };
  },
  computed: {
    filteredList() {
      if (!this.filterText) {
        return this.list;
      }
      return this.list.filter(item => item.indexOf(this.filterText) > -1);
    }
  },
  methods: {
    onInput(e) {
      if (!this.lock) {
        this.filterText = e.target.value;
      }
    },
    onCompositionStart() {
      this.lock = true;
    },
    onCompositionEnd(e) {
      this.filterText = e.data;
      this.lock = false;
    }
  }
};
</script>

v-model形式

上面的代码我们使用的不是vue的 v-model双向绑定的形式,如果你使用 v-model的形式,你会发现在输入中文的过程中不会触发input事件。

查看vue的源码 src/platforms/web/runtime/directives/model.js,有这么几行代码:

export default {
  inserted (el, binding, vnode) {
    if (vnode.tag === 'select') {
      setSelected(el, binding, vnode.context)
      el._vOptions = [].map.call(el.options, getValue)
    } else if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
      el._vModifiers = binding.modifiers
      if (!binding.modifiers.lazy) {
        // Safari < 10.2 & UIWebView doesn't fire compositionend when
        // switching focus before confirming composition choice
        // this also fixes the issue where some browsers e.g. iOS Chrome
        // fires "change" instead of "input" on autocomplete.
        el.addEventListener('change', onCompositionEnd)
        if (!isAndroid) {
          el.addEventListener('compositionstart', onCompositionStart)
          el.addEventListener('compositionend', onCompositionEnd)
        }
        /* istanbul ignore if */
        if (isIE9) {
          el.vmodel = true
        }
      }
    }
  }
}
//...
function onCompositionStart (e) {
  e.target.composing = true
}
function onCompositionEnd (e) {
  // prevent triggering an input event for no reason
  if (!e.target.composing) return
  e.target.composing = false
  trigger(e.target, 'input')
}
function trigger (el, type) {
  const e = document.createEvent('HTMLEvents')
  e.initEvent(type, true, true)
  el.dispatchEvent(e)
}

可以发现,原来vue早已做了相同的操作,所以v-model帮我们做了很多优化处理,这也是vue如此优秀的原因之一。

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
JavaScript常用的事件有很多种,下面列举了一些常用的事件和相应的代码示例: 1. click事件:当用户点击某个元素时触发。 ```javascript const button = document.querySelector("button"); button.addEventListener("click", function() { console.log("Button clicked!"); }); ``` 2. mouseover事件:当用户将鼠标移动到某个元素上时触发。 ```javascript const element = document.querySelector("#my-element"); element.addEventListener("mouseover", function() { console.log("Mouse over!"); }); ``` 3. keydown事件:当用户按下某个键时触发。 ```javascript document.addEventListener("keydown", function(event) { console.log(`Key pressed: ${event.key}`); }); ``` 4. submit事件:当用户提交一个表单时触发。 ```javascript const form = document.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); // 阻止表单的默认提交行为 console.log("Form submitted!"); }); ``` 5. load事件:当页面或某个资源加载完成时触发。 ```javascript window.addEventListener("load", function() { console.log("Page loaded!"); }); ``` 6. scroll事件:当用户滚动页面时触发。 ```javascript window.addEventListener("scroll", function() { console.log("Scrolling..."); }); ``` 这些是JavaScript常用的一些事件和相应的代码示例,但并不是全部。在实际开发,可能会遇到更多的事件类型,开发者需要根据具体需求选择适合的事件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值