极简富文本编辑器Demo
本帖最后由 马黑黑 于 2023-12-6 23:38 编辑 <br /><br /><style>h2 { text-align: center; }
#ed_outer {
width: 740px;
height: 500px;
border-radius: 6px;
box-shadow: 3px 6px 12px darkgray;
margin: 20px auto;
position: relative;
display: flex;
flex-direction: column;
}
#ed_top, #ed_foot {
border: 1px solid gray;
border-radius: 6px;
background: #f0f0f0;
padding: 8px;
display: flex;
gap: 0 4px;
align-items: center;
}
#ed_top {
border-radius:6px 6px 0 0;
border-bottom-color: transparent;
}
#ed_edit {
flex-grow: 1;
border: 1px solid gray;
box-sizing: border-box;
position: relative;
}
#ed_foot {
border-radius: 0 0 6px 6px;
border-top-color: transparent;
}
#elm, #rDiv {
width: 100%;
height: 100%;
background: white;
padding: 8px;
border: none;
outline: none;
overflow: hidden auto;
resize: none;
box-sizing: border-box;
word-break: break-word;
tab-size: 4;
position: absolute;
}
#elm {
font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
background: #f8f8dc;
display: none;
}
#rDiv > p {
margin: 8px 0;
padding: 0;
}
#rDiv > p:nth-of-type(1)) { margin: 0 0; }
.btn {
width: 30px;
height: 30px;
border: none;
outline: none;
padding: 0;
cursor: pointer;
}
.btn:hover { border: 1px solid gray; }
#font_color, #bg_color, #edlist {
width: 20px;
height: 20px;
box-sizing: border-box;
display: flex;
align-items: center;
}
.grow1 {
flex-grow: 1;
text-align: right;
}
</style>
<h2>mhEditor</h2>
<div id="ed_outer">
<div id="ed_top">
<button id="code" class="btn" title="代码模式"></></button>
<button id="bold" class="btn" title="加粗(Ctrl+B)"><b>B</b></button>
<button id="italic" class="btn" title="斜体(Ctrl+I)"><i>I</i></button>
<button id="underline" class="btn" title="下划线(Ctrl+U)"><u>U</u></button>
<button id="strikethrough" class="btn" title='删除线'><del>D</del></button>
<button id="removeformat" class="btn" title="清除格式">C</button>
<span class="grow1"><a href="http://mhh.52qingyin.cn/">整站系统</a></span>
</div>
<div id="ed_edit">
<textarea id="elm">Textarea</textarea>
<div id="rDiv" contenteditable="true"><p><br></p></div>
</div>
<div id="ed_foot">
<span class="grow1"></span>
<button id="test" onclick='alert("感谢点击!")'>假装发布</button>
</div>
</div>
<script>
(function() {
let codeState = false;
let btns = document.querySelectorAll('.btn');
let formatCode = (code) => {
let regAr = [
[/(<\/p>|<\/div>)(<)/g, '$1\n$2'],
[/<div>(<br>)?<\/div>|<p><\/p>/g, ''],
[/^[\t]*\n/gm, '']
];
regAr.forEach((item) => {
code = code.replaceAll(item,item);
});
return code;
};
btns.forEach((item) => {
item.onclick = () => {
if(item.id === 'code') {
if(codeState) {
rDiv.innerHTML = elm.value;
elm.style.display = 'none';
rDiv.style.display = 'block';
}else{
elm.value = formatCode(rDiv.innerHTML);
elm.style.display = 'block';
rDiv.style.display = 'none';
}
codeState = !codeState;
}else{
document.execCommand(item.id,false,item.id);
}
elm.value = formatCode(rDiv.innerHTML);
};
});
rDiv.oninput = () => elm.value = rDiv.innerHTML;
})();
</script>
代码
<style>
h2 { text-align: center; }
#ed_outer {
width: 740px;
height: 500px;
border-radius: 6px;
box-shadow: 3px 6px 12px darkgray;
margin: 20px auto;
position: relative;
display: flex;
flex-direction: column;
}
#ed_top, #ed_foot {
border: 1px solid gray;
border-radius: 6px;
background: #f0f0f0;
padding: 8px;
display: flex;
gap: 0 4px;
align-items: center;
}
#ed_top {
border-radius:6px 6px 0 0;
border-bottom-color: transparent;
}
#ed_edit {
flex-grow: 1;
border: 1px solid gray;
box-sizing: border-box;
position: relative;
}
#ed_foot {
border-radius: 0 0 6px 6px;
border-top-color: transparent;
}
#elm, #rDiv {
width: 100%;
height: 100%;
background: white;
padding: 8px;
border: none;
outline: none;
overflow: hidden auto;
resize: none;
box-sizing: border-box;
word-break: break-word;
tab-size: 4;
position: absolute;
}
#elm {
font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
background: #f8f8dc;
display: none;
}
#rDiv > p {
margin: 8px 0;
padding: 0;
}
#rDiv > p:nth-of-type(1)) { margin: 0 0; }
.btn {
width: 30px;
height: 30px;
border: none;
outline: none;
padding: 0;
cursor: pointer;
}
.btn:hover { border: 1px solid gray; }
#font_color, #bg_color, #edlist {
width: 20px;
height: 20px;
box-sizing: border-box;
display: flex;
align-items: center;
}
.grow1 {
flex-grow: 1;
text-align: right;
}
</style>
<h2>mhEditor</h2>
<div id="ed_outer">
<div id="ed_top">
<button id="code" class="btn" title="代码模式"></></button>
<button id="bold" class="btn" title="加粗(Ctrl+B)"><b>B</b></button>
<button id="italic" class="btn" title="斜体(Ctrl+I)"><i>I</i></button>
<button id="underline" class="btn" title="下划线(Ctrl+U)"><u>U</u></button>
<button id="strikethrough" class="btn" title='删除线'><del>D</del></button>
<button id="removeformat" class="btn" title="清除格式">C</button>
<span class="grow1"><a href="http://mhh.52qingyin.cn/">整站系统</a></span>
</div>
<div id="ed_edit">
<textarea id="elm">Textarea</textarea>
<div id="rDiv" contenteditable="true"><p><br></p></div>
</div>
<div id="ed_foot">
<span class="grow1"></span>
<button id="test" onclick='alert("感谢点击!")'>假装发布</button>
</div>
</div>
<script>
(function() {
let codeState = false;
let btns = document.querySelectorAll('.btn');
let formatCode = (code) => {
let regAr = [
[/(<\/p>|<\/div>)(<)/g, '$1\n$2'],
[/<div>(<br>)?<\/div>|<p><\/p>/g, ''],
[/^[\t]*\n/gm, '']
];
regAr.forEach((item) => {
code = code.replaceAll(item,item);
});
return code;
};
btns.forEach((item) => {
item.onclick = () => {
if(item.id === 'code') {
if(codeState) {
rDiv.innerHTML = elm.value;
elm.style.display = 'none';
rDiv.style.display = 'block';
}else{
elm.value = formatCode(rDiv.innerHTML);
elm.style.display = 'block';
rDiv.style.display = 'none';
}
codeState = !codeState;
}else{
document.execCommand(item.id,false,item.id);
}
elm.value = formatCode(rDiv.innerHTML);
};
});
rDiv.oninput = () => elm.value = rDiv.innerHTML;
})();
</script>
Wndows 的记事本,是一个处理纯文本的编辑器,Windows还有一个富文本编辑器,在安装word之类的办公软件之前编辑富文本的极好替代品,用过的朋友应该知道什么叫做富文本。
富文本编辑器支持图文共存。Web富文本编辑器,可以使用div之类的常规元素来模拟编辑界面,仅需一个属性值设置,contenteditable="true"。当 contenteditable 设置为true,div 或 p 之类的元素,就都可以对之编辑,且支持粘贴图片、给选定文本设置样式等。HTML核心代码举例如下:
<div contenteditable="true"></div>
上面这句代码,就可以令 div 处于可编辑状态。当然,我们需要给它设置样式,并用JS处理一些输入交互,正如本帖示例一样。
Demo只是一个简单展示,它提供一个基础,我们可以在此基础上进行扩展。
特别说明:本示例工具栏的几个小功能,均使用 execCommand 实现,该API已经被w3c宣布即将下架,但各大浏览器仍然完好支持。 contenteditable 属性是所有现代浏览器都支持的。contenteditable的值有三个:
true : 元素进入可编辑其内内容
false : 元素不可以编辑内容
plaintext-only : 元素仅可编辑纯文本,就像textArea控件一样,遗憾的是目前只有Chromium类的浏览器支持
除了 contenteditable 属性,还可以通过 CSS 的 user-modify 属性设置元素实现,仅 Chromium 类浏览器支持。 本帖最后由 马黑黑 于 2023-12-7 08:23 编辑
作为demo,示例是不完善的,也自然会存在逻辑上的以及其他方面的缺陷。也许,我这里只是提供一种思路,虽然主要是想展现HTML之强大。
如果要做一个可以部署到自己的项目的编辑器,demo远远不够,需要进一步构思与完善。此外要指出的是,特别重要的:
要有 form,上述代码全部或部分隶属于form。当 button 置于form中,要给出 type 属性,type="button",否则每一个按钮都是提交。真正的提交按钮 type="submit“。form和提交按钮都应有 name 属性,然后结合项目,form的提交行为即 action 属性指向根据需要给出明确值。 富文本,介个名字好听{:6_228:} 虽然不懂,看懂 mhEditor 的含义了,就是马黑编辑器{:6_228:} 输入一些文字,果然可以做加粗斜体等操作。还是头一次知道这个,感谢黑黑的介绍{:4_199:} 图片也可以放进去呢,只是不知道怎么去调。也不错,点代码模式,就直接看到图片地址了{:4_173:} 太深奥,看不懂。按红影说的试了试,挺灵的。我就跟在大侠后面学习套用!{:4_203:} 亦是金 发表于 2023-12-7 09:40
太深奥,看不懂。按红影说的试了试,挺灵的。我就跟在大侠后面学习套用!
这只是一个demo编辑器代码,演示一下 幸运草 发表于 2023-12-7 09:05
富文本,介个名字好听
{:4_172:} 幸运草 发表于 2023-12-7 09:06
虽然不懂,看懂 mhEditor 的含义了,就是马黑编辑器
{:4_181:} 红影 发表于 2023-12-7 09:31
图片也可以放进去呢,只是不知道怎么去调。也不错,点代码模式,就直接看到图片地址了
富文本,就是不止是文本 红影 发表于 2023-12-7 09:31
图片也可以放进去呢,只是不知道怎么去调。也不错,点代码模式,就直接看到图片地址了
这个不是全功能编辑器,可以在代码模式中调整 红影 发表于 2023-12-7 09:13
输入一些文字,果然可以做加粗斜体等操作。还是头一次知道这个,感谢黑黑的介绍
论坛发帖都有这类编辑器的。富文本编辑器的开发门槛高、坑多且深,据说很多人都钻进去后出不来。
如果仅仅基于 contenteditable+execCommand,做个轻奢型的富文本编辑器其实不难,问题是,execCommand已经判了死刑,我们得基于 contenteditable + (range + section)去开发,或者用数据模型+映射方式来实现,这将是一个庞大复杂的工程。 马黑黑 发表于 2023-12-7 12:47
富文本,就是不止是文本
原来是这个意思啊。 马黑黑 发表于 2023-12-7 12:48
这个不是全功能编辑器,可以在代码模式中调整
哦哦,我试试。。。 红影 发表于 2023-12-7 13:06
哦哦,我试试。。。
{:4_190:} 红影 发表于 2023-12-7 13:06
原来是这个意思啊。
只是文本,是穷文本,记事本就是这个。