在 Weex 中兼容搜狗输入法,核心就是尊重“组合输入”流程:监听 compositionstart/compositionend,在 composition 阶段不把中间文本当作最终值写回界面,确保 v-model 与 selection(光标位置)分离处理,避免频繁更新导致光标跳动;针对 Android/iOS 的 imeOptions/keyboardType 做差异化设置,并处理好软键盘遮挡与候选窗覆盖问题。下面用通俗的原理讲清,再给出可直接上手的实践和调试清单。

By admin 2026年7月25日

先把概念讲清楚(费曼式)

在 Weex 中兼容搜狗输入法,核心就是尊重“组合输入”流程:监听 compositionstart/compositionend,在 composition 阶段不把中间文本当作最终值写回界面,确保 v-model 与 selection(光标位置)分离处理,避免频繁更新导致光标跳动;针对 Android/iOS 的 imeOptions/keyboardType 做差异化设置,并处理好软键盘遮挡与候选窗覆盖问题。下面用通俗的原理讲清,再给出可直接上手的实践和调试清单。

说清楚三件事就够用了:输入事件长什么样、第三方输入法有什么特别、Weex 的输入控件如何和原生键盘“握手”。

  • 组合输入(composition):像搜狗输入法这样的中文输入,是先在候选栏里组字(拼音或其他),这期间会产生 compositionstartcompositionupdatecompositionend 等事件。中间状态不是最终文本,不能当 final value 处理。
  • 普通 input 事件:在 composition 之外,input 事件表示用户已经确定了字符。这时可以安全地把值同步回业务层并触发校验、搜索等逻辑。
  • Weex 的绑定与光标:Weex(基于 Vue 风格)往往用 value/v-model 双向绑定。如果在 composition 未结束时,把绑定值频繁写回,会触发原生控件重新渲染,从而导致光标跳到末尾或丢失选择区。

常见问题与对应思路

1. 光标跳动或候选词被中断

现象:输入拼音后选词,光标突然跳到末尾,或者选词无法插入。

原因:在 composition 阶段前端把 value 写回(比如 v-model 触发了 set),导致原生输入框内部状态被重置。

解决思路:

  • 监听 compositionstart,设置一个 flag(isComposing = true);监听 compositionend,把 isComposing 设为 false 并在 end 时统一处理最终值。
  • 在 input 事件里,如果 isComposing 为 true,尽量只记录临时内容,不做强制的 value 回写或触发高消耗逻辑。
  • 如果必须在输入中做格式化(比如自动大写、加空格),务必在 compositionend 后统一执行,并尝试恢复 selectionStart/selectionEnd。

2. 安卓上搜狗候选窗遮挡输入区域

现象:候选窗覆盖输入框或遮住页面关键控件。

原因:候选窗是 IME 的浮层,和页面布局独立,Weex 页面没有自动调整视图。

解决思路:

  • 在 focus 时获取键盘高度(如果能通过原生回调拿到),并把页面上移或调整滚动容器的 padding-bottom。
  • 利用 android:windowSoftInputMode(在容器 Activity 端)设置适当模式,如 adjustResize 或 adjustPan,根据实际效果选取。
  • 如果是 Weex 容器里,建议在 native 端暴露一个 resize 回调,前端收到后做平滑滚动到输入框位置。

3. emoji、手写、语音输入导致的特殊字符问题

现象:粘贴或语音输入的结果包含不可见字符、联合字符,或长度计算错乱。

原因:某些输入方式会产生组合字符(grapheme)或零宽字符,简单的 length 统计会误判。

解决思路:

  • 做字符限制时,使用基于 Unicode Grapheme Cluster 的分割库(如 grapheme-splitter)或用正则按 Unicode 模式清洗。
  • 对于 emoji 建议允许而不是简单剔除;如果业务必须限制,则在 compositionend 或 blur 时做最终校验并给出用户友好提示。

简洁可用的实践代码(Weex + Vue 风格)

下面是一个常见的输入组件模板,核心是处理 composition 与 selection:

<input
  :value="value"
  @input="onInput"
  @compositionstart="onCompositionStart"
  @compositionend="onCompositionEnd"
  @focus="onFocus"
  @blur="onBlur"
/>

对应的逻辑:

data() {
  return {
    value: '',
    isComposing: false,
    pendingValue: ''
  }
},
methods: {
  onCompositionStart(e) {
    this.isComposing = true
  },
  onCompositionEnd(e) {
    this.isComposing = false
    // e.target.value 是最终选字后的值
    this.value = e.target.value
    // 如果需要恢复光标,可调用原生接口或记录 selection 后恢复
  },
  onInput(e) {
    const val = e.target.value
    if (this.isComposing) {
      // 临时显示,不触发昂贵操作
      this.pendingValue = val
      return
    }
    // 非组合阶段,正常同步
    this.value = val
    // 触发搜索或校验
  }
}

注意事项:上面示例里尽量避免在 composition 阶段调用 setState 导致重新渲染。如果业务需要格式化输入,延后到 compositionend。

iOS 与 Android 的差异要点

平台 常见表现 调优建议
iOS 智能标点、候选条行为更“规范”、UITextInputTraits 可控 设置 keyboardType、disableSmartPunctuation、在 native 侧处理 inputAccessoryView
Android 第三方键盘差异大、候选窗更容易遮挡、IME options 多样 在 Activity 设置 windowSoftInputMode,native 侧可调整 imeOptions 或 onCreateInputConnection

如何在原生层协同改进体验(可选项)

  • 暴露一个键盘高度回调给前端,前端收到后平滑调整页面滚动。
  • 在 Android 原生 EditText 上,重写 onCreateInputConnection 来控制输入类型和 imeOptions,尽量与搜狗等主流输入法兼容。
  • 在 iOS 端,利用 UITextInputTraits(如 keyboardType、autocapitalizationType、smartQuotesType)降低自动替换带来的问题。

调试与测试清单(必做)

  • 在真机上用搜狗输入法测试:拼音选词、英文输入、符号、表情、语音与手写。
  • 测试光标定位:快速连续输入、删除、选中再输入,检查光标是否稳定。
  • 测试候选窗遮挡:在页面底部有固定按钮或重要表单时,确保输入时页面不会被遮挡关键交互。
  • 跨键盘测试:搜狗、百度、系统自带、Gboard 等,确保兼容性。
  • 边界情况:超长粘贴、多次撤销(undo)、组合字符、emoji 限制等。

常见误区(顺便说两句)

  • 误区一:一律把所有 input 事件都当 final。这会造成组合输入中断和光标跳动。
  • 误区二:只在浏览器仿真器测试。第三方输入法行为在真机上才会暴露问题。
  • 误区三:把所有平台都用同一套 imeOptions。不同平台需要不同微调。

若还想更稳:进一步优化的几个小技巧

  • 在 compositionend 后短延时(例如 0-50ms)再进行格式化,能兼顾流畅性和稳定性。
  • 为重要输入(如银行卡号、手机号)提供纯数字键盘或分段输入,减少中文输入法参与。
  • 在输入频繁触发搜索或请求时,使用节流或防抖,且在 isComposing 时不触发异步请求。
  • 记录并在必要时恢复 selectionStart/selectionEnd,必要时配合 native 接口设置光标。

调试时可打印的若干关键值

  • composition 状态(isComposing)
  • 每次 input 的 e.target.value
  • selectionStart / selectionEnd
  • 键盘高度(若 native 可提供)和 windowSoftInputMode

参考的概念名词(方便查资料)

  • compositionstart / compositionupdate / compositionend
  • input event / keydown / keyup
  • IME(Input Method Editor)
  • windowSoftInputMode / imeOptions / UITextInputTraits

就这些要点了——如果你在实现过程中遇到具体的光标位置恢复、原生回调或候选窗遮挡的例子,把最小可复现场景和日志贴出来,我可以基于那份数据给出更精确的改法。不过先按上面的流程改改,往往就能把搜狗输入法在 Weex 下的体验提升很多。反正写到这儿我又想起之前修复过一个因频繁 setState 导致连选词都点不开的问题,细节挺容易忽略的……