赞
踩
实现效果:通过 鼠标松开事件highlight监听选中文本,文本选中后可以通过window.getSelection()拿到选中的文本数据;同时可以通过鼠标松开时的位置,调用this.setBoxPosition(e.pageX, e.pageY)事件计算想要弹出的标签弹窗的位置。标签弹窗中给每一个标签添加点击事件labelmenuchose(id, item)(标签弹窗的html代码没有贴出,可以根据自身需要自行定义),点击选择标签后触发事件labelmenuchose(id, item),[id是我在点击标签时传入的时间戳,准备用来给标注span标签和i标签的id选择器命名用的,保证他们id的一致性,为了后面的删除]。点击事件触发后,在点击事件内部,对选中文本右边添加标注,整个标注内容用span标签包裹,选中文本背景色变成标签背景色的百分之二十五,单击标签,可以对标签进行修改,点击删除按钮实现删除功能
html部分 后端传入文本,前端拿到文本通过v-html进行渲染
- <template>
- <div
- id="annotateContent"
- style="text-align: left; font-size: 16px; padding: 20px"
- type="textarea"
- v-html="textMgs.content"
- @mouseup.stop="highlight($event)"
- v-if="textrender"
- ></div>
- </template>
js部分
- <script>
- import $ from "jquery";
-
- export default {
- data() {
- return {
- textMgs: {
- content: "",
- detailId: null,
- },
- textrender: true,
- sel: null,
- range: null,
- labeldialog: false,
- editbutton: false,//已标注在文本的标签单击后会把editbutton变成true,然后再次弹出标签选择弹框,可以重新选择标签把旧的标签替换掉,这个代码忘写了,算了,但那不重要,没有标签修改功能的直接走else就可以了
- }
- },
- methods:{
- // 选中标注文本
- highlight(e) {
- if (!window.getSelection().toString() || this.labels.length == 0) {
- this.labeldialog = false; //选中文本后出现标注列表弹框
- return;
- }
-
- this.sel = window.getSelection();
- this.range = this.sel.getRangeAt(0);
- // 判断选中文本中是否包含子元素 如果需要阻止重叠标注可使用
- // let span = document.querySelectorAll(".highlight ");
- // for (let i = 0; i < span.length; i++) {
- // if (this.sel.containsNode(span[i])) {
- // this.labeldialog = false;
- // return;
- // }
- // }
-
- //计算选中文本在屏幕中的位置,然后弹出标签列表弹窗
- this.setBoxPosition(e.pageX, e.pageY);
- },
-
- // 计算标注标签栏弹出的位置
- setBoxPosition(X, Y) {
- var labellist = document.querySelector(".labelbutton2");
- const maxHeight = document.body.clientHeight;
- let height = Y + 10;
- if (maxHeight < height + 248) {
- height = height - 268;
- }
- labellist.style.cssText = `height:248px;overflow:auto;width:200px;position:fixed;left:${X + 10}px;top:${height}px;background:#fff;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);border-radius: 4px`;
- //弹出标签列表
- this.labeldialog = true;
- },
-
- // 选择标注标签
- labelmenuchose(id, item) {
- // 修改标签
- if (this.editbutton) { //这个是标注后单击标签,实现修改标签,不需要可以直接走else
- let changeid = this.editbutton_spanid;
- let annotateContent =
- document.getElementById(changeid).parentNode.parentNode.parentNode;
- let span = document.getElementById(changeid).parentNode.parentNode;
- span.removeChild(document.getElementById(changeid).parentNode);
- const newspan = document.createElement("span");
- newspan.className = "highlight";
- let delicon = document.createElement("i");
- delicon.setAttribute("id", item.tagId + "-" + new Date().getTime());
- // // 删除标签
- delicon.addEventListener("click", (a) => {
- this.deleteById(a.currentTarget.id);
- this.delMarking.visible = false; });
- delicon.setAttribute("class", "el-icon-close");
- delicon.setAttribute("style", this.deliconStyle());
- let color = item.tagColor + "40";
- newspan.innerHTML = `<em style="background:${color};font-style: normal;">${span.innerText.trim()}</em><button style="border:1px solid #ccc;position:relative;vertical-align: super;background:${
- item.tagColor
- };color:#fff">${item.tagName}</button>`;
- newspan.lastChild.appendChild(delicon);
- annotateContent.insertBefore(newspan, span);
- annotateContent.removeChild(span);
- this.labeldialog = false;
- this.editbutton = false;
- this.editbutton_spanid = null;
- } else {
- // 添加标签
- if (!this.textchose) { //如果选中文本为空,直接返回
- return;
- }
- this.addMarking(id, item, this.sel, this.range);//标注时间
- var labellist = document.querySelector(".labelbutton2");
-
- labellist.style.cssText = `position:fixed;left:-999px;top:-999px;background:#fff`;
- this.labeldialog = false;
- this.highLightTableMsg(
- $("#annotateContent").html(),
- );
- }
- },
-
- // 在文本中生成标注
- addMarking(id, item, sel, range) {
- // 限制标注内嵌套标注
- let startContainer = range.startContainer;
-
- const span = document.createElement("span");
- span.className = "highlight";
- let delicon = document.createElement("i");
-
- delicon.setAttribute("id", id);
- // 删除标签
- delicon.addEventListener("click", (a) => {
- // deleteById(id);
- this.labeldialog = false;
- this.deleteById(id);
- this.delMarking.visible = false;
- a.stopPropagation();
- });
-
- delicon.setAttribute("class", "el-icon-close");
- delicon.setAttribute("style", this.deliconStyle());
- try{
- range.surroundContents(span); //把指定节点插入选区的起始位置,然后把指定节点的内容替换为选区的内容。
- }catch(e){
- window.getSelection().removeAllRanges();
- this.sel = null;
- this.range = null;
- this.textchose = null;
- this.labeldialog = false;
- return;
- }
- let color = item.tagColor + "40";
- span.innerHTML = `<em style="background:${color};font-style: normal;">${span.innerHTML}</em><button style="border:1px solid #fff;background:#fff;padding: 0 2px;border-radius: 2px;position:relative;vertical-align: super;background:${item.tagColor}!important;color:#fff">${item.tagName}</button>`;
- span.lastChild.appendChild(delicon);
- window.getSelection().removeAllRanges();
- this.sel = null;
- this.range = null;
- this.textchose = null;
- },
-
- }
- }
- </script>
如果还需要删除标记功能,需要在上面的methods插入下面的方法
- // 删除标记
- deleteById(id) {
-
- let annotateContent =
- document.getElementById(id).parentNode.parentNode.parentNode;
-
- let span = document.getElementById(id).parentNode.parentNode;
- let button = document.getElementById(id).parentNode;
-
- let emtext = "";
-
- if (span.firstChild.getElementsByTagName("span").length > 0) { //判断标注内是否还嵌套有标注,有走if,没有走else(其实这里只需要if就可以了,写的时候可以把代码简化一下)
-
- let kk = span.firstChild.innerHTML
- let newSpan = document.createElement('span');
- newSpan.className = "tagReplace";
- span.removeChild(button);
- annotateContent.insertBefore(newSpan, span);
- annotateContent.removeChild(span);
- annotateContent.innerHTML = annotateContent.innerHTML.replace('<span class="tagReplace"></span>', kk);
- } else {
- emtext = span.firstChild.innerText.trim();
- span.removeChild(button);
- let textNode = document.createTextNode(emtext);
- annotateContent.insertBefore(textNode, span);
- annotateContent.removeChild(span);
- }
-
- window.getSelection().removeAllRanges();
- this.labeldialog = false;
- },
因为我这边保存是直接把整个文本返回给后端,再次获取已标注的结果的话,也是后端直接把一整个文本返回给我的,所以为了保证渲染完已标注过的文本还能正常实现删除功能、标签修改功能,需要在文本获取成功后再次添加上删除的点击事件
- // 给已标注文件添加点击事件
- addLabelDel() {
- let del = document.querySelectorAll("#annotateContent span button i");
- // let button = document.querySelectorAll("#annotateContent span button")
- $("#annotateContent").on("click", "span button", (e) => {
- //通过事件委托完成,有效
- if (this.labels.length > 0) {
- this.editbutton = true;
- this.setBoxPosition(e.pageX, e.pageY);
- this.editbutton_spanid = e.currentTarget.lastElementChild.id;
- //操作this
- // ...
- }
- });
- for (var i = 0; i < del.length; i++) {
- del[i].addEventListener("click", (a) => {
- this.labeldialog = false;
- this.deleteById(a.currentTarget.id);
- a.stopPropagation();
- });
- }
- },
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。