JS文字操作库(亲测可用)
2023-12-13 04:53:13
使用
<template>
<div id="examination" :style="{ '--themeColor': themeColors[0].color }">
<div class="themeLi">
<span class="main_right-btn">切换风格</span>
<ul>
<li
@click="onThemeColorChange(item.color)"
v-for="(item, index) in themeColors"
:key="index"
:style="{ 'background-color': item.color }"
>
{{ item.name }}
</li>
</ul>
</div>
<li class="main_right-btn" @click="selectionColor('yellow')">题干标识</li>
<li class="main_right-btn" @click="selectionColor('transparent')">取消标识</li>
<li class="main_right-btn" @click="backText">撤销</li>
<li class="main_right-btn" @click="goText">恢复</li>
<li class="main_right-btn" @click="copyText">复制</li>
<li class="main_right-btn" @click="cutstrText">剪切</li>
<li class="main_right-btn" @click="pasteText">粘贴</li>
<textarea id="examText" v-model="answerText" @input="onChangeAnswerText"></textarea>
</div>
</template>
<script>
import Mark from '@/utils/TextMark'
export default {
components: {
},
data() {
return {
// 当前的内容
answerText: '',
// 复制的文字
copyVal: '',
// 主题颜色
themeColors: [
{ color: 'rgb(222, 235, 245)', name: '主题一' },
{ color: 'rgb(204, 225, 225)', name: '主题二' },
{ color: 'rgb(245, 232, 219)', name: '主题三' },
{ color: 'rgb(245, 219, 227)', name: '主题四' },
{ color: 'rgb(224, 223, 246)', name: '主题五' },
],
}
},
mounted() {
},
computed: {
},
methods: {
// 文本发生变化
onChangeAnswerText(e) {
Mark.stackedPrveTextStack(this.answerText)
},
// 撤销方法
backText() {
let text = Mark.revoke( this.answerText)
if (typeof text == 'undefined') return
this.answerText = text
},
//恢复方法
goText() {
let text = Mark.restore(this.answerText)
if (typeof text == 'undefined') return
this.answerText = text
},
// 剪切文字方法
cutstrText() {
this.copyVal = Mark.cutstr('examText').selectedText
console.log('this.copyVal ', this.copyVal)
},
// 粘贴文字方法
pasteText() {
Mark.parsestr('examText', this.copyVal)
},
// 复制当前文字方法
copyText() {
this.copyVal = Mark.getSelectedText()?.trim()
},
// 标识文字方法
selectionColor(color) {
Mark.ColorizeSelection(color)
},
}
}
</script>
<style scoped lang="less">
.themeLi {
display: flex;
ul {
display: none;
li {
font-size: 12px;
line-height: 12px;
margin-left: 6px;
cursor: pointer;
height: 12px;
padding: 4px;
margin-top: 4px;
user-select: none;
}
}
&:hover {
ul {
display: flex;
}
}
}
</style>
库内容
const Mark = {
// 标记方法 S
GetNextLeaf: function (node) {
while (!node.nextSibling) {
node = node.parentNode
if (!node) {
return node
}
}
var leaf = node.nextSibling
while (leaf.firstChild) {
leaf = leaf.firstChild
}
return leaf
},
GetPreviousLeaf: function (node) {
while (!node.previousSibling) {
node = node.parentNode
if (!node) {
return node
}
}
var leaf = node.previousSibling
while (leaf.lastChild) {
leaf = leaf.lastChild
}
return leaf
},
// If the text content of an element contains white-spaces only, then does not need to colorize
IsTextVisible: function (text) {
for (var i = 0; i < text.length; i++) {
if (text[i] != ' ' && text[i] != '\t' && text[i] != '\r' && text[i] != '\n') return true
}
return false
},
ColorizeLeaf: function (node, color) {
if (!Mark.IsTextVisible(node.textContent)) return
var parentNode = node.parentNode
if (!parentNode) return
// if the node does not have siblings and the parent is a span element, then modify its color
if (!node.previousSibling && !node.nextSibling) {
if (parentNode.tagName.toLowerCase() == 'span') {
parentNode.style.backgroundColor = color
return
}
}
// Create a span element around the node
var span = document.createElement('span')
span.style.backgroundColor = color
var nextSibling = node.nextSibling
parentNode.removeChild(node)
span.appendChild(node)
parentNode.insertBefore(span, nextSibling)
},
ColorizeLeafFromTo: function (node, color, from, to) {
var text = node.textContent
if (!Mark.IsTextVisible(text)) return
if (from < 0) from = 0
if (to < 0) to = text.length
if (from == 0 && to >= text.length) {
// to avoid unnecessary span elements
Mark.ColorizeLeaf(node, color)
return
}
var part1 = text.substring(0, from)
var part2 = text.substring(from, to)
var part3 = text.substring(to, text.length)
var parentNode = node.parentNode
var nextSibling = node.nextSibling
parentNode.removeChild(node)
if (part1.length > 0) {
var textNode = document.createTextNode(part1)
parentNode.insertBefore(textNode, nextSibling)
}
if (part2.length > 0) {
var span = document.createElement('span')
span.style.backgroundColor = color
var textNode = document.createTextNode(part2)
span.appendChild(textNode)
parentNode.insertBefore(span, nextSibling)
}
if (part3.length > 0) {
var textNode = document.createTextNode(part3)
parentNode.insertBefore(textNode, nextSibling)
}
},
ColorizeNode: function (node, color) {
var childNode = node.firstChild
if (!childNode) {
Mark.ColorizeLeaf(node, color)
return
}
while (childNode) {
// store the next sibling of the childNode, because colorizing modifies the DOM structure
var nextSibling = childNode.nextSibling
Mark.ColorizeNode(childNode, color)
childNode = nextSibling
}
},
ColorizeNodeFromTo: function (node, color, from, to) {
var childNode = node.firstChild
if (!childNode) {
Mark.ColorizeLeafFromTo(node, color, from, to)
return
}
for (var i = from; i < to; i++) {
Mark.ColorizeNode(node.childNodes[i], color)
}
},
ColorizeSelection: function (color) {
if (!!window.ActiveXObject || 'ActiveXObject' in window) {
document.execCommand('BackColor', false, color)
return
}
// all browsers, except IE before version 9
if (window.getSelection) {
var selectionRange = window.getSelection()
if (selectionRange.isCollapsed) {
return
}
var range = selectionRange.getRangeAt(0)
// store the start and end points of the current selection, because the selection will be removed
var startContainer = range.startContainer
var startOffset = range.startOffset
var endContainer = range.endContainer
var endOffset = range.endOffset
// because of Opera, we need to remove the selection before modifying the DOM hierarchy
selectionRange.removeAllRanges()
if (startContainer == endContainer) {
//同一个节点时,直接标记颜色
Mark.ColorizeNodeFromTo(startContainer, color, startOffset, endOffset)
} else {
if (startContainer.firstChild) {
var startLeaf = startContainer.childNodes[startOffset]
} else {
//标记第一段节点
var startLeaf = Mark.GetNextLeaf(startContainer)
Mark.ColorizeLeafFromTo(startContainer, color, startOffset, -1)
}
if (endContainer.firstChild) {
if (endOffset > 0) {
var endLeaf = endContainer.childNodes[endOffset - 1]
} else {
var endLeaf = Mark.GetPreviousLeaf(endContainer)
}
} else {
var endLeaf = Mark.GetPreviousLeaf(endContainer)
Mark.ColorizeLeafFromTo(endContainer, color, 0, endOffset)
}
while (startLeaf) {
var nextLeaf = Mark.GetNextLeaf(startLeaf)
Mark.ColorizeLeaf(startLeaf, color)
if (startLeaf == endLeaf) {
break
}
startLeaf = nextLeaf
}
}
} else {
// Internet Explorer before version 9
document.execCommand('BackColor', false, color)
}
},
// 标记方法 E
// 粘贴方法
parsestr(dom, myValue) {
if (!myValue) return
let myField = document.getElementById(dom)
//IE support
if (document.selection) {
myField.focus()
sel = document.selection.createRange()
sel.text = myValue
sel.select()
}
//MOZILLA/NETSCAPE support
else if (myField.selectionStart || myField.selectionStart == '0') {
var startPos = myField.selectionStart
var endPos = myField.selectionEnd
var restoreTop = myField.scrollTop
myField.value =
myField.value.substring(0, startPos) + myValue + myField.value.substring(endPos, myField.value.length)
if (restoreTop > 0) {
myField.scrollTop = restoreTop
}
myField.focus()
myField.selectionStart = startPos + myValue.length
myField.selectionEnd = startPos + myValue.length
} else {
myField.value += myValue
myField.focus()
}
return myField.value
},
// 复制方法
getSelectedText() {
return window.getSelection().toString()
},
// 剪切方法
cutstr(id) {
// 获取Textarea元素
var textarea = document.getElementById(id)
// 获取选中文本的起始和结束位置
var selectionStart = textarea.selectionStart
var selectionEnd = textarea.selectionEnd
// 提取选中的文本
var selectedText = textarea.value.substring(selectionStart, selectionEnd)
// 删除选中的文本
textarea.value = textarea.value.substring(0, selectionStart) + textarea.value.substring(selectionEnd)
// 将选中的文本剪切到剪贴板
document.addEventListener('cut', function (e) {
// 将光标移到Textarea内部
textarea.focus()
e.clipboardData.setData('text/plain', selectedText)
e.preventDefault()
})
// 执行剪切操作
document.execCommand('cut')
return {
// 没删除的文本
notValue:textarea.value,
// 选中删除的文本
selectedText:selectedText
}
},
// 存储栈区
textStack: [],
// 栈区下标
textStackIndex: 0,
// 是否点击了恢复方法
textStackRestore: false,
// 撤销方法
revoke: function (text) {
if (typeof text == 'undefined') return
if (Mark.textStackIndex <= 0) return
Mark.textStackIndex--
return Mark.textStack[Mark.textStackIndex]
},
//恢复方法
restore: function (text) {
if (typeof text == 'undefined') return
if (Mark.textStackIndex >= Mark.textStack.length - 1) return
Mark.textStackIndex++
Mark.textStackRestore = true
return Mark.textStack[Mark.textStackIndex]
},
// 清空栈方法(在切换保存区域的时候需要清空)
clearStack() {
Mark.textStack = []
Mark.textStackIndex = 0
Mark.textStackRestore = false
},
// 入栈方法
stackedPrveTextStack(text) {
if (typeof text == 'undefined') return
Mark.textStack.push(text)
if (Mark.textStackRestore) {
Mark.textStack.splice(Mark.textStackIndex + 2)
}
Mark.textStackIndex = Mark.textStack.length - 1
},
}
export default Mark
这块写的有问题,暂时没有解决方案
// 上一个栈
prveTextStack: [],
// 下一个栈
nextTextStack: [],
// 撤销方法
revoke: function (text) {
let content = Mark.prveTextStack.pop()
if (text && content == text) {
content = Mark.prveTextStack.pop()
}
if (typeof content != 'undefined') {
Mark.nextTextStack.push(content)
}
return content
},
//恢复方法
restore: function (text) {
let content = Mark.nextTextStack.pop()
if (text && content == text) {
content = Mark.nextTextStack.pop()
}
if (typeof content != 'undefined') {
Mark.prveTextStack.push(content)
}
return content
},
// 清空双栈方法(在切换保存区域的时候需要清空)
clearStack() {
Mark.nextTextStack = []
Mark.prveTextStack = []
},
// 入栈方法
stackedPrveTextStack(text) {
if(typeof text == 'undefined')return;
Mark.prveTextStack.push(text)
},
文章来源:https://blog.csdn.net/qq_37547964/article/details/134583364
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!