创建批注:
继续批注:
右侧批注列表:
1、功能与应用:
- 文本注释:recogito-js可以将注释功能添加到网页上,或者作为构建完全自定义注释应用程序的工具箱。
- 图像注释:除了文本注释外,它还支持为网页中的图像添加绘图、注释和标签功能。
- PDF注释:通过@recogito/recogito-react-pdf插件,它还能够支持在React中注释PDF文档。
2、官网及示例
官网:https://github.com/recogito/recogito-js/wiki/API-Reference
示例:https://recogito.github.io/recogito-js/
3、需求:
前面的文章提到过很多的tinyMCE、Vditor、cherryMarkdown、wangEditor等等markdown和富文本编辑器,在这些编辑器生成的文本内容的预览基础上要加上批注功能,用户选中文本后就要弹出批注弹窗,确认批注后右侧会相应展示出批注内容,同时在右侧进行批注的编辑、删除
4、安装与使用:
npm i @recogito/recogito-js@1.8.2
以下示例为文本注释功能:
import { Recogito } from "@recogito/recogito-js";
import "@recogito/recogito-js/dist/recogito.min.css";// 初始化批注
const initRecogito = () => {getAnnoList();r = new Recogito({content: document.querySelector(".artDetail"), // 批注区域readOnly: false, // 是否只读locale: "auto", // 可选择语言 auto会根据浏览器设置选择语言});r.setServerTime(Date.now()); // 设置批注日期r.setAuthInfo({ // 这里设置每个批注携带的默认信息id: useUserStore().userId,displayName: useUserStore().nickName,});// 创建批注事件r.on("createAnnotation", async function (annotation, overrideId) {// 定义一个getInitAnnotate方法拿到创建的这个批注信息let newAnno = getInitAnnotate("create", annotation);// 因为批注插件不管有没有输入内容都会创建,这里要求了没有批注内容时不允许新建批注if (!newAnno.annotationContent?.trim()?.length) {getAnnoList(); // 刷新批注列表避免页面出现空批注内容return proxy.$modal.msgWarning("请先输入批注内容");}// 将批注信息存入后端submitAnnotation(newAnno).then(({ data }) => {recogitoList.value.push(data); // 在页面右侧回展示批注信息proxy.$modal.msgSuccess("新增成功!");}).catch((err) => {getAnnoList();// 刷新批注列表避免页面出现空批注内容});});// 在已有批注基础上补充批注r.on("updateAnnotation", function (annotation, previous) {let newAnno = getInitAnnotate("update", annotation);if (!newAnno.annotationContent?.trim()?.length) {getAnnoList();return proxy.$modal.msgWarning("请先输入批注内容");}submitAnnotation(newAnno).then(({ data }) => {// 补充批注时let index = recogitoList.value.findIndex((item) => item.id === data.id);recogitoList.value[index] = data;proxy.$modal.msgSuccess("新增成功!");}).catch((err) => {getAnnoList();});});
};// 更改批注参数
const getInitAnnotate = (title, newAnno, pkId) => {let data = {};// 创建批注时if (title === "create") {data.annotationContent = newAnno.body[0]?.value;data.textContent = newAnno.target.selector.find((item) => item.type === "TextQuoteSelector")?.exact;// 修改批注时} else if (title === "update") {data.annotationContent = newAnno.body[newAnno.body?.length - 1]?.value;} else {// 通过外部input框编辑批注let annoBody = newAnno.body.find((item) => item.pkId === pkId);data.annotationContent = annoBody?.iptValue;data.pkId = pkId;}let annoPosition = newAnno.target.selector.find((item) => item.type === "TextPositionSelector");// 按照后端入参要求组装批注内容的结构data.annotationId = newAnno.id;data.createdBy = useUserStore().name;data.endCoordinate = annoPosition.end;data.startCoordinate = annoPosition.start;data.knwlgId = artDetails.value.pkId;data.knwlgNo = artDetails.value.knwlgNo;return data;
};// 获取批注列表并回显
const getAnnoList = () => {getAnnotationList({ knwlgId: artDetails.value.pkId }).then((res) => {recogitoList.value = res.data; // 批注列表setTimeout(() => {r.clearAnnotations(); //清除所有批注r.setAnnotations(recogitoList.value); // 设置已有批注内容}, 500);}).catch(() => {});
};// 根据批注id在点击右侧批注列表激活文本域内批注弹窗
const selectAnnotation = (id) => {let domList = document.querySelectorAll(".r6o-annotation");let activeTop =Array.from(domList).find((item) => item.dataset.id === id && item.innerText?.length)?.offsetTop - 5;document.querySelector(".article-container").scrollTop = activeTop;r.selectAnnotation(id);
};