马黑黑 发表于 2023-1-6 12:02

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>

马黑黑 发表于 2023-1-6 12:12

textarea自动折行之下的行号演示

实现方法:两个textarea并排,一个显示行号,一个显示正文。为了计算自动折行的文本高度,用一个不可见的 div 框(opacity: 0)动态测量每行文本占据的实际高度,这个div测量器提供的数据是行号形成的计算依据之一。

一楼效果,支持文本框双击选中整行(段),还支持单击行号选中编辑框整行(段)。

代码放在楼下。

马黑黑 发表于 2023-1-6 12:13

<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>

马黑黑 发表于 2023-1-6 12:18

100行左右的代码,其中JS部分去除空行和注释还不到50行,效率还不错

红影 发表于 2023-1-6 15:07

“支持文本框双击选中整行(段),还支持单击行号选中编辑框整行(段)。”
试了一下,果真如此呢,真神奇{:4_187:}

红影 发表于 2023-1-6 15:09

实现自动加行号的功能,竟要考虑这么多细节,真不容易{:4_204:}

马黑黑 发表于 2023-1-6 18:12

红影 发表于 2023-1-6 15:09
实现自动加行号的功能,竟要考虑这么多细节,真不容易

是的。做之前要做好计划,最好有个草图、纲要什么的,纲要包含要写什么函数、用什么变量,函数和变量名最好事先定好。

马黑黑 发表于 2023-1-6 18:12

红影 发表于 2023-1-6 15:07
“支持文本框双击选中整行(段),还支持单击行号选中编辑框整行(段)。”
试了一下,果真如此呢,真神奇 ...

选中行(段)之前就介绍过的

红影 发表于 2023-1-6 20:50

马黑黑 发表于 2023-1-6 18:12
是的。做之前要做好计划,最好有个草图、纲要什么的,纲要包含要写什么函数、用什么变量,函数和变量名最 ...

这个太专业了点,我不太可能学会写代码{:4_173:}

红影 发表于 2023-1-6 20:50

马黑黑 发表于 2023-1-6 18:12
选中行(段)之前就介绍过的

根本就没记住{:4_173:}

马黑黑 发表于 2023-1-6 21:08

红影 发表于 2023-1-6 20:50
根本就没记住

因为对做帖子没啥用

马黑黑 发表于 2023-1-6 21:09

红影 发表于 2023-1-6 20:50
这个太专业了点,我不太可能学会写代码

我是说,做什么,都基本是这个流程

红影 发表于 2023-1-7 10:36

马黑黑 发表于 2023-1-6 21:08
因为对做帖子没啥用

可能是这个原因吧。

红影 发表于 2023-1-7 10:37

马黑黑 发表于 2023-1-6 21:09
我是说,做什么,都基本是这个流程

饿呢,这个流程是必须的{:4_187:}

马黑黑 发表于 2023-1-7 11:15

红影 发表于 2023-1-7 10:37
饿呢,这个流程是必须的

对的,各行各异的流程,如果不看业务内容,都差不多

马黑黑 发表于 2023-1-7 11:15

红影 发表于 2023-1-7 10:36
可能是这个原因吧。

是的。人们对知识的求知欲望,通常总是与实用联系在一起的。

红影 发表于 2023-1-7 16:34

马黑黑 发表于 2023-1-7 11:15
对的,各行各异的流程,如果不看业务内容,都差不多

有了框架,才能补充内容。

红影 发表于 2023-1-7 16:36

马黑黑 发表于 2023-1-7 11:15
是的。人们对知识的求知欲望,通常总是与实用联系在一起的。

急功近利了点{:4_173:}

马黑黑 发表于 2023-1-7 17:58

红影 发表于 2023-1-7 16:36
急功近利了点

这也是正常的心态

马黑黑 发表于 2023-1-7 17:58

红影 发表于 2023-1-7 16:34
有了框架,才能补充内容。

所谓纲举目张
页: [1] 2
查看完整版本: textarea加行号(二)