uniapp+vue3 textarea中选中段落添加序号

效果图

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
});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值