textarea加行号(二)
<style>#papa {
margin: auto;
width: 740px;
height: 520px;
box-shadow: 3px 3px 20px #000;
outline: 4px solid #eee;
border-radius: 1px;
position: relative;
}
#chkHeight {
position: absolute;
left: 60px;
width: calc(100% - 60px);
border:1px solid #ccc;
border-left: none;
padding: 6px;
font: normal 16px/20px monospace;
white-space:pre-wrap;
word-break: break-all;
box-sizing: border-box;
opacity: 0;
}
#papa > textarea {
position: absolute;
padding: 6px;
resize: none;
border-color: #ccc;
outline: none;
box-sizing: border-box;
font: normal 16px/20px monospace;
}
#maintxtbox {
width: calc(100% - 60px);
height: 100%;
left: 60px;
background: #fff;
border-left: none;
word-break: break-all;
}
#linetxtbox {
width: 60px;
height: 100%;
text-align: right;
background: #eee;
color: gray;
overflow: hidden;
cursor: default;
}
</style>
<div id="papa">
<div id="chkHeight"></div>
<textarea id="linetxtbox" readonly>1</textarea>
<textarea id="maintxtbox"></textarea>
</div>
<script>
//函数:显示行号
let showLineIdx = (ele,e) => {
chkHeight.style.cssText += ele.clientHeight < ele.scrollHeight ? 'overflow-y : scroll' : 'overflow-y: auto';
let lines = ele.value.split('\n'), all = lines.length, linestr = '';;
for (j = 0; j < all; j ++) {
linestr += j + 1;
chkHeight.innerText = lines;
let total = (chkHeight.clientHeight - 12) / 20 || 1;
linestr += '\n'.repeat(total);
}
linetxtbox.value = linestr;
linetxtbox.scrollTop = maintxtbox.scrollTop;
};
//编辑框输入事件
maintxtbox.oninput = (e) => {
showLineIdx(maintxtbox,e);
};
//函数:选中行
let selectLine = (ele,num) => {
let mpos, tstr = '';
let ar = ele.value.split('\n');
for (j = 0; j < num; j ++) {
tstr += ar + 2;
}
mpos = tstr.length;
ele.setSelectionRange(mpos, mpos + ar.length);
ele.focus();
};
//编辑框双击事件
maintxtbox.ondblclick = () => {
let pos = maintxtbox.selectionStart;
let tmpar = maintxtbox.value.substring(0, pos).split('\n');
selectLine(maintxtbox, tmpar.length - 1);
};
//编辑框滚动事件
maintxtbox.onscroll = () => linetxtbox.scrollTop = maintxtbox.scrollTop;
//行号单击击事件
linetxtbox.onclick = () => {
let pos = linetxtbox.selectionStart, ar = linetxtbox.value.split('\n'), len = 0,idx = 0;
for(j = 0; j < ar.length; j ++) {
len += ar.length + 1;
if (len > pos) {
idx = ar;
break;
}
}
selectLine(maintxtbox, idx - 1);
};
//编辑框获得焦点事件
//maintxtbox.onfocus = () => papa.style.outlineColor = '#aaa';
//编辑框失去焦点事件
//maintxtbox.onblur = () => papa.style.outlineColor = '#eee';
</script> textarea自动折行之下的行号演示
实现方法:两个textarea并排,一个显示行号,一个显示正文。为了计算自动折行的文本高度,用一个不可见的 div 框(opacity: 0)动态测量每行文本占据的实际高度,这个div测量器提供的数据是行号形成的计算依据之一。
一楼效果,支持文本框双击选中整行(段),还支持单击行号选中编辑框整行(段)。
代码放在楼下。 <style>
#papa {
margin: auto;
width: 740px;
height: 520px;
box-shadow: 3px 3px 20px #000;
outline: 4px solid #eee;
border-radius: 1px;
position: relative;
}
#chkHeight {
position: absolute;
left: 60px;
width: calc(100% - 60px);
border:1px solid #ccc;
border-left: none;
padding: 6px;
font: normal 16px/20px monospace;
white-space:pre-wrap;
word-break: break-all;
box-sizing: border-box;
opacity: 0;
}
#papa > textarea {
position: absolute;
padding: 6px;
resize: none;
border-color: #ccc;
outline: none;
box-sizing: border-box;
font: normal 16px/20px monospace;
}
#maintxtbox {
width: calc(100% - 60px);
height: 100%;
left: 60px;
background: #fff;
border-left: none;
word-break: break-all;
}
#linetxtbox {
width: 60px;
height: 100%;
text-align: right;
background: #eee;
color: gray;
overflow: hidden;
cursor: default;
}
</style>
<div id="papa">
<div id="chkHeight"></div>
<textarea id="linetxtbox" readonly>1</textarea>
<textarea id="maintxtbox"></textarea>
</div>
<script>
//函数:显示行号
let showLineIdx = (ele,e) => {
chkHeight.style.cssText += ele.clientHeight < ele.scrollHeight ? 'overflow-y : scroll' : 'overflow-y: auto';
let lines = ele.value.split('\n'), all = lines.length, linestr = '';;
for (j = 0; j < all; j ++) {
linestr += j + 1;
chkHeight.innerText = lines;
let total = (chkHeight.clientHeight - 12) / 20 || 1;
linestr += '\n'.repeat(total);
}
linetxtbox.value = linestr;
linetxtbox.scrollTop = maintxtbox.scrollTop;
};
//编辑框输入事件
maintxtbox.oninput = (e) => {
showLineIdx(maintxtbox,e);
};
//函数:选中行
let selectLine = (ele,num) => {
let mpos, tstr = '';
let ar = ele.value.split('\n');
for (j = 0; j < num; j ++) {
tstr += ar + 2;
}
mpos = tstr.length;
ele.setSelectionRange(mpos, mpos + ar.length);
ele.focus();
};
//编辑框双击事件
maintxtbox.ondblclick = () => {
let pos = maintxtbox.selectionStart;
let tmpar = maintxtbox.value.substring(0, pos).split('\n');
selectLine(maintxtbox, tmpar.length - 1);
};
//编辑框滚动事件
maintxtbox.onscroll = () => linetxtbox.scrollTop = maintxtbox.scrollTop;
//行号单击击事件
linetxtbox.onclick = () => {
let pos = linetxtbox.selectionStart, ar = linetxtbox.value.split('\n'), len = 0,idx = 0;
for(j = 0; j < ar.length; j ++) {
len += ar.length + 1;
if (len > pos) {
idx = ar;
break;
}
}
selectLine(maintxtbox, idx - 1);
};
//编辑框获得焦点事件
//maintxtbox.onfocus = () => papa.style.outlineColor = '#aaa';
//编辑框失去焦点事件
//maintxtbox.onblur = () => papa.style.outlineColor = '#eee';
</script>
100行左右的代码,其中JS部分去除空行和注释还不到50行,效率还不错 “支持文本框双击选中整行(段),还支持单击行号选中编辑框整行(段)。”
试了一下,果真如此呢,真神奇{:4_187:} 实现自动加行号的功能,竟要考虑这么多细节,真不容易{:4_204:} 红影 发表于 2023-1-6 15:09
实现自动加行号的功能,竟要考虑这么多细节,真不容易
是的。做之前要做好计划,最好有个草图、纲要什么的,纲要包含要写什么函数、用什么变量,函数和变量名最好事先定好。 红影 发表于 2023-1-6 15:07
“支持文本框双击选中整行(段),还支持单击行号选中编辑框整行(段)。”
试了一下,果真如此呢,真神奇 ...
选中行(段)之前就介绍过的 马黑黑 发表于 2023-1-6 18:12
是的。做之前要做好计划,最好有个草图、纲要什么的,纲要包含要写什么函数、用什么变量,函数和变量名最 ...
这个太专业了点,我不太可能学会写代码{:4_173:} 马黑黑 发表于 2023-1-6 18:12
选中行(段)之前就介绍过的
根本就没记住{:4_173:} 红影 发表于 2023-1-6 20:50
根本就没记住
因为对做帖子没啥用 红影 发表于 2023-1-6 20:50
这个太专业了点,我不太可能学会写代码
我是说,做什么,都基本是这个流程 马黑黑 发表于 2023-1-6 21:08
因为对做帖子没啥用
可能是这个原因吧。 马黑黑 发表于 2023-1-6 21:09
我是说,做什么,都基本是这个流程
饿呢,这个流程是必须的{:4_187:} 红影 发表于 2023-1-7 10:37
饿呢,这个流程是必须的
对的,各行各异的流程,如果不看业务内容,都差不多 红影 发表于 2023-1-7 10:36
可能是这个原因吧。
是的。人们对知识的求知欲望,通常总是与实用联系在一起的。 马黑黑 发表于 2023-1-7 11:15
对的,各行各异的流程,如果不看业务内容,都差不多
有了框架,才能补充内容。 马黑黑 发表于 2023-1-7 11:15
是的。人们对知识的求知欲望,通常总是与实用联系在一起的。
急功近利了点{:4_173:} 红影 发表于 2023-1-7 16:36
急功近利了点
这也是正常的心态 红影 发表于 2023-1-7 16:34
有了框架,才能补充内容。
所谓纲举目张
页:
[1]
2