效果图
1、html部分
<!-- 输入区域 -->
<view class="respon-area">
<textarea
v-model="inputVal"
class="respon-textarea"
placeholder="请输入"
maxlength="5000"
:cursor-spacing="20"
:adjust-position="false"
@focus="onFocus"
@blur="onBlur"
id="textarea"
/>
</view>
<button @click="setY('li')"></button>
<button @click="setY('ol')"></button>
2、参数定义
const inputVal = ref('');
const isFocused = ref(false);
let textareaContext = null;
3、js方法
// 焦点事件处理
const onFocus = () => {
isFocused.value = true;
getTextareaContext();
};
const onBlur = () => {
isFocused.value = false;
};
// 设置序号
const setY = async (type) => {
// #ifdef H5
const selection = document.getSelection();
const cursorPos = selection.anchorOffset;
handleNumbering(type, cursorPos);
// #endif
// #ifdef MP-WEIXIN
try {
if (!textareaContext) {
await getTextareaContext();
}
// 确保获得焦点
textareaContext.focus({
success: () => {
setTimeout(() => {
uni.getSelectedTextRange({
success: (res) => {
handleNumbering(type, res.end);
},
fail: () => {
// 如果获取失败,在文本末尾添加
handleNumbering(type, inputVal.value.length);
},
});
}, 100);
},
});
} catch (error) {
console.error('获取光标位置失败:', error);
// 降级处理:在文本末尾添加
handleNumbering(type, inputVal.value.length);
}
// #endif
};
// 处理编号逻辑
const handleNumbering = (type, cursorPos) => {
// 获取当前行的内容
const lines = inputVal.value.split('\n');
let currentLineIndex = 0;
let currentPos = 0;
let orderNumber = 1; // 用于有序列表的序号计数
// 找到光标所在行
for (let i = 0; i < lines.length; i++) {
currentPos += lines[i].length + 1; // +1 是因为换行符
if (currentPos > cursorPos) {
currentLineIndex = i;
break;
}
}
// 处理编号
const newLines = lines.map((line) => {
// 如果是空行,直接返回,不增加序号计数
if (!line.trim()) return line;
// 移除已有的编号
line = line.replace(/^(\d+\.|[\*\-])\s*/, '').trim();
if (type === 'ol') {
// 有序列表
const numberedLine = `${orderNumber}. ${line}`;
orderNumber++; // 只在非空行时增加序号
return numberedLine;
} else {
// 无序列表
return `* ${line}`;
}
});
// 更新文本内容
inputVal.value = newLines.join('\n');
// 更新文本内容后的光标处理
nextTick(async () => {
const newCursorPos = newLines.slice(0, currentLineIndex + 1).join('\n').length;
// #ifdef H5
const textarea = document.querySelector('.respon-textarea');
if (textarea) {
textarea.focus();
textarea.setSelectionRange && textarea.setSelectionRange(newCursorPos, newCursorPos);
}
// #endif
// #ifdef MP-WEIXIN
try {
if (!textareaContext) {
await getTextareaContext();
}
textareaContext.focus({
success: () => {
setTimeout(() => {
textareaContext.setSelection({
start: newCursorPos,
end: newCursorPos,
});
}, 100);
},
});
} catch (error) {
console.error('设置光标位置失败:', error);
}
// #endif
});
};
// 组件挂载时获取 textarea 上下文
onMounted(() => {
// #ifdef MP-WEIXIN
getTextareaContext();
// #endif
});