AI改了一下就好了
function initInsertAtCaret() {
const SELECTOR = '#h-emot-select';
const TA_SELECTOR = 'textarea.h-post-form-textarea[name="content"]';
document.querySelectorAll(SELECTOR).forEach(select => {
if (select.dataset.kaoBound === '1') return;
select.dataset.kaoBound = '1';
const form = select.closest('form');
const textarea = form ? form.querySelector(TA_SELECTOR) : null;
if (!textarea) return;
let lastStart = 0;
let lastEnd = 0;
// 记录光标位置
const remember = () => {
lastStart = textarea.selectionStart ?? lastStart;
lastEnd = textarea.selectionEnd ?? lastEnd;
};
['keyup', 'mouseup', 'select', 'input', 'focus', 'blur'].forEach(ev =>
textarea.addEventListener(ev, remember, true)
);
// 只在 select 上监听 focus 相关事件来记录位置
['focus', 'mousedown'].forEach(ev =>
select.addEventListener(ev, remember, true)
);
// 防抖保护
let isInserting = false;
// 统一使用 input 事件来处理插入
select.addEventListener('input', function handleInsert(e) {
// 第一时间阻止所有传播
e.stopImmediatePropagation();
e.preventDefault();
e.stopPropagation();
// 防抖检查
if (isInserting) return;
const val = select.value;
if (!val) return;
isInserting = true;
insertAtCaret(textarea, val, lastStart, lastEnd);
// 延迟重置选择器和解除防抖
setTimeout(() => {
select.value = '';
isInserting = false;
}, 50);
textarea.focus();
}, true); // 捕获阶段
// 移除 change 事件的监听,避免重复触发
select.addEventListener('change', function(e) {
e.stopImmediatePropagation();
e.preventDefault();
e.stopPropagation();
}, true);
function insertAtCaret(textarea, text, selStart, selEnd) {
// 记录插入前的滚动位置
const prevScrollTop = textarea.scrollTop;
// 确定插入位置
let start = Number.isInteger(selStart) ? selStart : textarea.selectionStart;
let end = Number.isInteger(selEnd) ? selEnd : textarea.selectionEnd;
if (!Number.isInteger(start) || !Number.isInteger(end)) {
start = end = textarea.value.length;
}
// 拼接新内容
const before = textarea.value.slice(0, start);
const after = textarea.value.slice(end);
textarea.value = before + text + after;
// 插入后的光标位置
const newPos = start + text.length;
// 关键:重新 focus 并设置光标位置
textarea.focus();
textarea.setSelectionRange(newPos, newPos);
// 延迟触发 input 事件,避免与原生逻辑冲突
setTimeout(() => {
textarea.dispatchEvent(new Event('input', { bubbles: true }));
}, 0);
// 恢复滚动条位置
textarea.scrollTop = prevScrollTop;
// 更新记忆位置
lastStart = lastEnd = newPos;
}
});
}