{{ markContent }}
{{ i.tag_name }}
取 消
重 选
const TAG_WIDTH = 280 //自定义最大范围,以保证不超过内容的最大宽度
const tagInfo = ref({
visible: false,
top: 0,
left: 0,
})
const el = document.getElementById('text-container')
//鼠标抬起
el?.addEventListener('mouseup', (e) => {
const text = window?.getSelection()?.toString() || ''
if (text.length > 0) {
const left = e.offsetX < TAG_WIDTH ? 0 : e.offsetX - 300
tagInfo.value = {
visible: true,
top: e.offsetY + 40,
left: left,
}
getSelectedTextData()
} else {
tagInfo.value.visible = false
}
//清空重选/取消数据
resetEditTag()
const selectedText = reactive({
start: 0,
end: 0,
content: '',
})
//获取选取的文字数据
const getSelectedTextData = () => {
const select = window?.getSelection() as any
console.log('selectselectselectselect', select)
const nodeValue = select.focusNode?.nodeValue
const anchorOffset = select.anchorOffset
const focusOffset = select.focusOffset
const nodeValueSatrtIndex = markContent.value?.indexOf(nodeValue)
selectedText.content = select.toString()
if (anchorOffset < focusOffset) {
//从左到右标注
selectedText.start = nodeValueSatrtIndex + anchorOffset
selectedText.end = nodeValueSatrtIndex + focusOffset
} else {
//从右到左
selectedText.start = nodeValueSatrtIndex + focusOffset
selectedText.end = nodeValueSatrtIndex + anchorOffset
}
}
import Mark from 'mark.js'
import {ref} from 'vue
import { nanoid } from 'nanoid'
const selectedTextList = ref([])
const handleSelectLabel = (t) => {
const marker = new Mark(document.getElementById('text-container'))
const { tag_color, tag_name, tag_id } = t
const markId = nanoid(10)
marker.markRanges(
[
{
start: selectedText.start, //必填
length: selectedText.content.length, //必填
},
],
{
className: 'text-selected',
element: 'span',
each: (element: any) => {
//为元素添加样式和属性
element.setAttribute('id', markId)
element.style.borderBottom = `2px solid ${t.tag_color}` //添加下划线
element.style.color = t.tag_color
//绑定事件
element.onclick = function (e: any) {
//
}
},
}
)
selectedTextList.value.push({
tag_color,
tag_name,
tag_id,
start: selectedText.start,
end: selectedText.end,
mark_content:selectedText.content,
mark_id: markId,
})
}
点击已进行标记的文字————>重选/取消弹窗显示————>点击取消
如何判断点击的文字是否已标记,通过在创建的标记元素中绑定点击事件,触发则表示已标记。
import { nanoid } from 'nanoid'
//选择标签后
const markId = nanoid(10)
marker.markRanges(
[
{
start: isReset ? editTag.value.start : selectedText.start,
length: isReset ? editTag.value.content.length : selectedText.content.length,
},
],
{
className: 'text-selected',
element: 'span',
each: (element: any) => {
element.setAttribute('id', markId)
//绑定事件
element.onclick = function (e: any) {
e.preventDefault()
if (!e.target.id) return
const left = e.offsetX < TAG_WIDTH ? 0 : e.offsetX - 300
const item = selectedTextList.value?.find?.((t) => t.mark_id == e.target.id) as any
const { mark_content, tag_id, start, end } = item || {}
editTag.value = {
visible: true,
top: e.offsetY + 40,
left: e.offsetX,
mark_id: e.target.id,
content: mark_content || '',
tag_id: tag_id || '',
start: start,
end: end,
}
tagInfo.value = {
visible: false,
top: e.offsetY + 40,
left: left,
}
}
},
}
)
const handleCancel = () => {
if (!editTag.value.mark_id) return
const markEl = new Mark(document.getElementById(editTag.value.mark_id))
markEl.unmark()
selectedTextList.value.splice(
selectedTextList.value?.findIndex((t) => t.mark_id == editTag.value.mark_id),
1
)
tagInfo.value = {
visible: false,
top: 0,
left: 0,
}
resetEditTag()
}
const resetEditTag = () => {
editTag.value = {
visible: false,
top: 0,
left: 0,
mark_id: '',
content: '',
tag_id: '',
start: 0,
end: 0,
}
}
和取消的步骤一样,只不过在点击重选后,先弹出标签弹窗,选择标签后,需要先删除选中的元素,然后再新增一个标记元素。由于在标签选择,在标签选择中判断一下是否是重选,是重选的话就需删除后再创建元素,不是的话就代表是新增,直接新增标记元素(综上所述)。
const handleSelectLabel = (t: TTag) => {
tagInfo.value.visible = false
const { tag_color, tag_name, tag_id } = t
const marker = new Mark(document.getElementById('text-container'))
const markId = nanoid(10)
const isReset = selectedTextList.value?.map((j) => j.mark_id).includes(editTag.value.mark_id)
? 1
: 0 // 1:重选 0:新增
if (isReset) {
//如若重选,则删除后再新增标签
const markEl = new Mark(document.getElementById(editTag.value.mark_id))
markEl.unmark()
selectedTextList.value.splice(
selectedTextList.value?.findIndex((t) => t.mark_id == editTag.value.mark_id),
1
)
}
marker.markRanges(
[
{
start: isReset ? editTag.value.start : selectedText.start,
length: isReset ? editTag.value.content.length : selectedText.content.length,
},
],
{
className: 'text-selected',
element: 'span',
each: (element: any) => {
element.setAttribute('id', markId)
element.style.borderBottom = `2px solid ${t.tag_color}`
element.style.color = t.tag_color
element.style.userSelect = 'none'
element.style.paddingBottom = '6px'
element.onclick = function (e: any) {
e.preventDefault()
if (!e.target.id) return
const left = e.offsetX < TAG_WIDTH ? 0 : e.offsetX - 300
const item = selectedTextList.value?.find?.((t) => t.mark_id == e.target.id) as any
const { mark_content, tag_id, start, end } = item || {}
editTag.value = {
visible: true,
top: e.offsetY + 40,
left: e.offsetX,
mark_id: e.target.id,
content: mark_content || '',
tag_id: tag_id || '',
start: start,
end: end,
}
tagInfo.value = {
visible: false,
top: e.offsetY + 40,
left: left,
}
}
},
}
)
selectedTextList.value.push({
tag_color,
tag_name,
tag_id,
start: isReset ? editTag.value.start : selectedText.start,
end: isReset ? editTag.value.end : selectedText.end,
mark_content: isReset ? editTag.value.content : selectedText.content,
mark_id: markId,
})
}
const handleAllDelete = () => {
selectedTextList.value = []
const marker = new Mark(document.getElementById('text-container'))
marker.unmark()
}
清空标记
保存
{{ markContent }}
{{ i.tag_name }}
√
取 消
重 选
目前功能实现比较简单,还有很多发挥的空间,先小小的记录一下