javascript - textarea中的多个单独区域选择?
问题描述
我对编码很陌生,并且一直在使用 textarea 制作文本编辑器组件:https ://jsfiddle.net/chrismg12/jLk70ar3/5/
我打算创建一个函数来选择找到的单词的所有实例。但是我不知道如何在 textarea 中这样做。注意:这不是关于多个插入符号,而是多个选择,但是在实现多个插入符号时的建议将不胜感激。
HTML
var lNo = "";
function injectStyles(rule) {
var div = $("<div />", {
html: '­<style>' + rule + '</style>'
}).appendTo("body");
}
$.fn.selectRange = function(start, end) {
return this.each(function() {
if (typeof end == "undefined") {
end = start;
}
if (start == -1) {
start = this.value.length;
}
if (end == -1) {
end = this.value.length;
}
if (this.setSelectionRange) {
this.focus();
this.setSelectionRange(start, end + 1);
} else if (this.createTextRange) {
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
});
};
$.fn.selectRangeExcludingLast = function(start, end) {
return this.each(function() {
if (typeof end == "undefined") {
end = start;
}
if (start == -1) {
start = this.value.length;
}
if (end == -1) {
end = this.value.length;
}
if (this.setSelectionRange) {
this.focus();
this.setSelectionRange(start, end + 1);
} else if (this.createTextRange) {
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
});
};
function getPos(str, substr, index) {
var io = str.split(substr, index).join(substr).length;
if (io >= str.length) {
return -1;
} else {
return io;
}
}
function gutterChildControl(gutter, textarea, settings) {
if (gutter.childNodes.length != $(textarea).val().split("\n").length) {
while (gutter.childNodes.length < $(textarea).val().split("\n").length) {
var gutterChild = document.createElement("div");
gutterChild.className = "gutterChild"
gutterChild.style.height = $(textarea).css('line-height');
var gutterChildLineHeight = $(textarea).css('line-height');
$(gutterChild).css('line-height', gutterChildLineHeight)
gutterChild.style.fontSize = $(textarea).css('font-size');
gutterChild.style.width = "100%";
gutterChild.style.color = settings.gFontCol;
gutterChild.style.paddingRight = `${settings.gPadding}px`;
gutterChild.style.paddingLeft = `${settings.gPadding}px`;
gutterChild.style.textAlign = settings.gFontAlign;
gutterChild.onmouseover = function() {
gutterChild.style.opacity = "0.75"
}
gutterChild.onmouseleave = function() {
gutterChild.style.opacity = "1"
}
gutterChild.onclick = function() {
if (parseInt(gutterChild.innerHTML) != 1) {
startPos = getPos($(textarea).val(), "\n", parseInt(gutterChild.innerHTML) - 1)
console.log(`startPos:${startPos}`);
endPos = getPos($(textarea).val(), "\n", parseInt(gutterChild.innerHTML))
if (endPos == -1) {
endPos = $(textarea).val().length - 1
}
console.log(`endPos:${endPos}`)
$(textarea).selectRange(startPos, endPos);
} else {
startPos = 0;
console.log(`startPos:${startPos}`)
endPos = getPos($(textarea).val(), "\n", 1)
if (endPos == -1) {
endPos = $(textarea).val().length - 1
if (endPos == -1) {
endPos = 0;
}
}
console.log(`endPos:${endPos}`)
$(textarea).selectRange(startPos, endPos);
}
}
gutter.appendChild(gutterChild);
gutterChild.innerHTML = `${gutter.childNodes.length}`
}
while (gutter.childNodes.length > $(textarea).val().split("\n").length) {
gutter.removeChild(gutter.lastChild)
}
// while(gutter.childNodes.length > $(textarea).val().split("\n").length){
// gutter.childNodes.pop;
// }
}
}
function Ventify(element, options) {
const settings = {
taCol: "#1d252c",
gCol: "#1d252c",
fSize: "22px",
gFontCol: "rgba(58,74,88,1)",
pad: 1,
gFontAlign: "center",
gPadding: 20,
...options
}
element.style.display = "flex";
element.style.flexDirection = "row";
var gutter = document.createElement("div");
var textarea = document.createElement("textarea");
gutter.className = "gutter";
gutter.classList.add("scrll")
textarea.className = "ventiEditor";
textarea.classList.add("scrll")
gutter.style.width = "100px";
gutter.style.height = "100%";
gutter.style.backgroundColor = settings.gCol;
gutter.style.overflowY = "scroll"
gutter.style.scrollbarWidth = "none";
injectStyles(".gutter::-webkit-scrollbar{width:0px;}")
injectStyles(".ventiEditor{outline:0px !important;-webkit-appearance:none;}")
textarea.style.width = "calc(100% - 100px)";
textarea.style.fontSize = settings.fSize;
textarea.style.color = settings.gFontCol;
textarea.style.overflowY = "scroll";
textarea.style.whiteSpace = "pre";
textarea.style.resize = "none";
textarea.style.height = "100%";
textarea.style.margin = "0px 0px 0px 0px"
textarea.style.border = "0px solid rgb(255,255,255)"
textarea.style.padding = "0"
$(textarea).css('line-height', `calc(${2*settings.pad}px + ${settings.fSize})`)
textarea.style.backgroundColor = settings.taCol;
textarea.spellcheck = false;
$(textarea).css("-moz-tab-size", "4");
$(textarea).css("tab-size", "4")
$('.ventiEditor:focus').css('outline', '0px !important')
$('.ventiEditor:focus').css('-webkit-appearance', 'none')
textarea.oninput = function() {
var gutter = textarea.parentElement.childNodes[0];
gutterChildControl(gutter, textarea, settings)
};
textarea.onscroll = function() {
gutter.scrollTop = textarea.scrollTop
}
$(textarea).keydown(function(e1) {
if (e1.ctrlKey) {
if (e1.keyCode >= 48 && e1.keyCode <= 57) {
lNo += e1.key;
console.log(lNo);
}
}
})
// gutter.onscroll = function(){
// if(gutter.scrollTop != textarea.scrollTop){
// textarea.scrollTop = gutter.scrollTop;
// }
// }
element.appendChild(gutter);
element.appendChild(textarea);
gutterChildControl(gutter, textarea, settings);
}
function gutterFix(textarea) {}
$(document).delegate('.ventiEditor', 'keydown', function(e) {
var keyCode = e.keyCode || e.which;
if (keyCode == 9) {
e.preventDefault();
var start = this.selectionStart;
var end = this.selectionEnd;
// set textarea value to: text before caret + tab + text after caret
$(this).val($(this).val().substring(0, start) +
"\t" +
$(this).val().substring(end));
// put caret at right position again
this.selectionStart =
this.selectionEnd = start + 1;
}
});
injectStyles(".gutterChild{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}")
Ventify(document.getElementsByClassName("container")[0], {
taCol: "#1d252c",
gCol: "#1d252c",
pad: 5,
gFontCol: '#bbb'
})
html,
body {
height: 100%;
margin: 0px 0px 0px 0px;
}
.container {
height: 100%;
}
<link rel="stylesheet" href="bootstrap-4.3.1-dist/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container"></div>
解决方案
您可以设置一个空数组并将所有匹配字符串的位置推送到它。this
(例如,如果您在字符串 ' ' 中寻找' this and this match; so does this
',您的数组将得到 [0,9,29]。)您可能想要/需要使用正则表达式
有了这些信息(并知道子字符串的长度),您可以执行以下操作:
- 在 textarea 上覆盖一个 div(可能使用contenteditable="true"和z-index: 1
)
- 将每个匹配的字符串包含在一个 span 元素中(更多信息关于这里)并且可能给所有这些跨度一个类,
- 使用 querySelectorAll 来获取一个包含所有这些跨度的 NodeList,并且
- 循环遍历列表以更改它们的样式(以便用户可以看到什么是“选定的”)和它们的内容(假设重点是让用户能够进行更改。)
您可以稍后删除环绕跨度,使用更新的文本更新文本区域,并删除覆盖的 div。
请注意,您的索引数组可能不会长时间保持有效,并且根据您对初始列表所做的操作,您可能希望向后循环以保护这些值,直到您不再需要它们为止。
无论如何,这是我的头脑风暴。
推荐阅读
- kotlin - 在 Groovy 中,Kotlin 扩展的等价物是什么?
- haskell - 如何转换 [(Data.Text.Internal.Text,Data.Text.Internal.Text)] -> 文本
- ajax - 单击任何按钮时出现 Ajax I/O 错误,在我的脚本中下拉
- python - 如何在 Python 中将一整列数据(行数不固定)复制到同一个 excel 文件中的新列?
- javascript - 您如何使用 ava 忽略非测试文件?
- python - 将系列转换为数组
- java - 操作方法:配置 Tomcat 9 以通过 Log4j2 登录
- c# - 在.Net核心控制台应用程序中触发后台服务ExecuteAsync方法
- sql - SQL 检索最新记录、标签 = 1 的最新记录和标签 = 1 的最新记录的先前记录
- javascript - 调用具有单个 Promise 参数的本机模块的 JS 语法是什么?