更新记录

1.0.0(2026-07-06) 下载此版本

核心能力:

  • @提及:输入 @ 自动唤起用户选择面板,选择后插入不可编辑的 @原子标签,支持远程搜索过滤
  • #话题:输入 # 自动唤起话题选择面板,选择后插入不可编辑的 #原子标签,支持远程搜索过滤
  • 图片插入:通过 insertImage() API 插入图片,支持 contenteditable 内渲染和反显
  • 表情面板:通过 #emoji 插槽自定义表情面板,与编辑器完全解耦
  • 结构化消息输出:send 事件产出的 message 使用不可见字符编码,后端可直接存储;同时返回结构化 model,前端可直接反显渲染
  • v-model 双向绑定:外部可随时读写编辑器内容,setValue 自动还原 @/#/图片
  • 字数统计:实时显示当前字数 / 上限,超限时数字变红并阻止发送
  • 发送防抖:loading prop 控制发送中状态 + 300ms 内置防抖,防止重复提交
  • CSS 变量定制:11 个 CSS 变量全覆盖,业务方可按需覆写适配主题色
  • 三端统一 API:props / events / slots / ref 方法在 H5、App、小程序三端行为一致
  • 小程序 @/# 自动检测:diff 算法实时追踪 textarea 输入,支持末尾/中间/粘贴场景的 @/# 触发
  • 空内容/超限 toast 提示:内容为空或超出字数限制时自动提示用户
  • 多实例安全:data-uid 属性选择器 + class 兜底,多个编辑器实例互不干扰

平台兼容性

uni-app(3.7.13)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- - × 4.4 12
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - -

l-editor 富文本评论编辑器

基于 uni-app (Vue 3) 的富文本输入组件,renderjs 驱动,支持 H5 和 App 端。 提供 @提及、#话题、图片插入、结构化消息输出、反显解析。

平台支持

平台 支持
H5 (Web) ✅ 完整支持 (renderjs)
App (Android/iOS/Harmony) ✅ 完整支持 (renderjs)
小程序 ✅ 降级支持 (textarea + 自动 @/# 检测)

小程序降级说明:组件内部通过 #ifdef MP 条件编译自动切换为 <textarea> 实现。用户在 textarea 中输入 @# 时会自动通过 diff 检测唤起对应候选面板,选择后自动替换为原子标签。图片暂不支持(转为 [图片] 占位文),对外 API(props / events / expose)与 H5/App 端保持一致。发送产出的 message 编码格式完全兼容。

安装

uni_modules/l-editor 放入项目的 uni_modules 目录,通过 easycom 自动引入。

快速开始

<template>
  <l-editor v-model="content" @send="handleSend" @search-change="onSearch">
    <!-- @ 面板 -->
    <template #at="{ show, keyword, , close }">
      <view v-show="show">
        <view v-for="u in filteredUsers" :key="u.id" @touchend.prevent="(u)" @click.stop="(u)">
          {{ u.name }}
        </view>
        <button @click="close">关闭</button>
      </view>
    </template>

    <!-- # 话题面板 -->
    <template #hot="{ show, keyword, , close }">
      <view v-show="show">
        <view v-for="t in filteredTags" :key="t.id" @touchend.prevent="(t)" @click.stop="(t)">
          #{{ t.name }}
        </view>
        <button @click="close">关闭</button>
      </view>
    </template>
  </l-editor>
</template>

<script setup>
  const onSearch = ({ type, keyword }) => {
    // type: 'ate' | 'tag' — 根据 keyword 远程搜索并更新面板列表
  };
  const handleSend = (data) => {
    console.log(data.message); // '你好{at_0}' — 编码后的下发格式
    console.log(data.model); // ParsedModel[] — 结构化模型
    console.log(data.ateUsers); // [{ value:'@张三', id:1 }]
    console.log(data.tags); // [{ value:'#前端开发', id:1 }]
  };
</script>

Props

属性 类型 默认值 说明
modelValue ParsedModel[] undefined v-model 绑定值
placeholder string "说点什么..." 占位文本
maxNum number 300 最大字数
loading boolean false 发送中状态
disabled boolean false 禁用状态
clearOnSend boolean true 发送后自动清空
sendText string "发送" 发送按钮文字

Events

事件 参数
send { model, message, num, ateUsers, tags }
change { model, message, num }
update:modelValue ParsedModel[]
input { model, message, num }
search-change { type, trigger, keyword, content }

Slots

插槽 作用域参数
#at { show, keyword, content, , close }
#hot { show, keyword, content, , close }
#emoji { show, , close }

暴露方法

方法 说明
focus() 编辑器获取焦点
clear() 清空编辑器和面板
getValue() 获取当前值快照
setValue(model) 回填结构化内容
insertAtom(atom) 插入内容 { type, value, id? }
insertText(text) 插入纯文本
insertImage(url, id?) 插入图片

图片上传集成示例

<script setup>
  const uploadAndInsert = async () => {
    const tempFile = await uni.chooseImage({ count: 1, sourceType: ["album", "camera"] });
    const filePath = tempFile.tempFilePaths[0];

    // 上传到服务器
    const uploadRes = await uni.uploadFile({
      url: "https://your-api.com/upload",
      filePath,
      name: "file",
    });
    const data = JSON.parse(uploadRes.data);

    // 将返回的 CDN URL 插入编辑器
    refEditor.value?.insertImage(data.url, data.id || Date.now());
  };
</script>

CSS 变量

组件颜色使用 CSS 变量,方便业务方按需覆写以适配自己的主题色:

CSS 变量 默认值 说明
--l-editor-bg #fff 编辑器背景
--l-editor-text #333 正文颜色
--l-editor-text-muted #999 辅助文字
--l-editor-placeholder #808080 占位文字
--l-editor-link #09408e @提及颜色
--l-editor-primary #07c160 主题色/#话题
--l-editor-danger #f56c6c 警告/超限色
--l-editor-disabled-bg #f5f5f5 禁用态背景
--l-editor-btn-disabled-bg #e0e0e0 按钮禁用背景
--l-editor-btn-disabled-color #999 按钮禁用文字
--l-editor-btn-active-color #fff 按钮激活文字

覆写示例:

:root {
  --l-editor-primary: #ff6b35;
  --l-editor-link: #1a73e8;
}

类型

interface ParsedModel {
  type: "text" | "ate" | "tag" | "image";
  id?: number | string;
  value: string;
}

interface AtomSelectItem {
  name: string;
  id: number | string;
}

消息编码格式

发送时 message 字段使用不可见分隔符 包裹占位符:

"你好{at_0} 欢迎加入{tag_1}"

反显时用正则 /\{(at|tag|image)(?:_(\d+))?\}/g 解析还原。

APP 端注意事项

  • manifest.json 需配置 softinputMode: "adjustResize"
  • 面板选择项需同时绑定 @touchend.prevent@click.stop

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

不收集用户数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无广告

许可协议

MIT协议

暂无用户评论。