HTML编辑器(1)
前言
现在网上有很多这样的HTML编辑器,这种编辑器无疑给人带来了很多方便,所以自己也想尝试制作一款这样的HTML编辑器,既然要制作,那就肯定是先把UI搭起来,再慢慢完善功能
设计思路
我的思路就是将div标签设置一个属性(contenteditable="true"
),使div成为可编辑的div
并且我发现可编辑div有个特征:在内部换行会将上一个标签复制下来,所以为了防止这种问题,我决定在内部加入<p><br></p>
这样,每次换行就会自动复制<p><br></p>
标签
把这些东西弄好后,我就开始写UI,俗话说:交互也是一门技术
UI用的Icon使用了图标字体
后面使用html写好了交互的菜单以及用css做了交互效果
UI效果
交互效果
鼠标移到Icon
鼠标移到有下拉框的Icon
开启功能
完整代码
引用的css文件
/Icon字体/
Css
@font-face { font-family: 'poppin'; src: url('../../Content/Font/poppin.ttf') format('truetype'); } @font-face { font-family: 'SEGUIEMJ'; src: url('../Font/SEGUIEMJ.TTF') format('truetype'); } *::-webkit-scrollbar { width: 3px; height:1px; } *::-webkit-scrollbar-thumb { border-radius: 10px; -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2); background: #0094ff; } *::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2); border-radius: 10px; background: #ccc; } body { font-family: 'poppin'; margin: 0; padding: 0px; } #YolxRichText { min-width: 1000px; max-width: 1600px; height: 620px; margin: 0 auto; position: relative; box-sizing: border-box; padding: 0px 40px; margin-top: 10px; font-family: 'poppin'; } #YolxRichText_Input { width: calc(100% - 40px); font-size: 16px; color: rgba(0,0,0,.8); letter-spacing: 2px; margin: 0; padding: 10px 20px 245px; outline: none; } .YolxRichText_Input_token { white-space: pre-wrap; } #YolxRichText_Ouput { position: absolute; top: 0px; right: 0px; width: 100%; height: 500px; font-size: 12px; color: #fff; letter-spacing: 2px; } #YolxRichText_Ouput_Preview { padding: 10px 20px 245px; color: #000; } #YolxRichText_Ouput h1 { text-align: center; border-bottom: 2px dotted #ff6a00; color: #ff6a00; } #YolxRichText_Input_section * { display: inline; } .editor { width: calc(100% - 15px); height: 100%; overflow: auto; float: left; } .color_SkyBlue { color: skyblue !important; } .YolxRichText_editor, .YolxRichText_Preview, .YolxRichText_Help { width: 50%; height: 500px; overflow: auto; position: relative; float: left; border: 1px solid #ccc; box-sizing: border-box; } .YolxRichText_Help { width: 20%; font-size: 14px; padding: 0px 10px; display:none; } .YolxRichText_Help p { display:block; } .YolxRichText_Help p span { display: block; } br { line-height: 26px; } .EditorMenu { width: 100%; height: 36px; position: relative; float: left; box-sizing: border-box; background: #f1f1f1; border: 1px solid #ccc; border-bottom: none; } .EditorMenu ul { margin: 0; padding: 0px; height: 100%; display: flex; text-align: center; margin: 0px 5px; } .EditorMenu ul li { display: block; width: 36px; line-height: 2.3em; position: relative; } .EditorMenu ul li:hover { cursor: pointer; } .EditorMenu ul li:hover i { color: #000; } .EditorMenu ul li:hover div { z-index: 2; display: block; animation: EditorMenuAnima ease 0.5s forwards; } @keyframes EditorMenuAnima { 0% { top:-100px; } 30% { top: 35px; } 60% { top: 20px; } 100% { top: 35px; } } .EditorMenu ul li svg { width: 26px; height: 34px; } .EditorMenu ul li div { width: 100px; z-index: 1; position: absolute; top: 35px; left: 0px; background-color: #fff; border: 1px solid #f1f1f1; border-right-color: #ccc; border-bottom-color: #ccc; border-top:1px solid #ccc; margin: 0; display: none; transition: all ease 0.5s; box-sizing: border-box; overflow: hidden; } .EditorMenu ul .editor_menu_face { } .EditorMenu ul .editor_menu_face div ul { display: flex; } .EditorMenu ul .editor_menu_face .face { display: block; position: initial; width: 100%; padding: 10px; border: none; max-height: 138px; overflow-y: auto; } .EditorMenu ul .editor_menu_face .face span { font-size: 24px; padding: 0px 4px; } .EditorMenu ul .editor_menu_face .face span:hover { background:#ccc; border-radius:3px; } .EditorMenu ul li div p { } .EditorMenu_ul_li_div_p { text-align: center; color: #999; line-height: 2; border-bottom: 1px solid #f1f1f1; font-size: 13px; } .EditorMenu ul li ul { display: block; margin: 0px; } .EditorMenu ul li div ul li { color: #333; padding: 5px 0; width: 100%; float: left; } .EditorMenu ul li div ul li:hover { background: #ccc; } .noPaddingAndMargin { margin: 0; padding: 0; } .EditorMenu ul li i { color: #999; } .LinesOfCode { height: 100%; float: left; background: #eee; padding: 10px 5px 0px 5px; } .LinesOfCode ul { text-align:left; font-size:12px; } .LinesOfCode ul li { margin: 20px 0px; }
Html
<div id="YolxRichText"> <div class="EditorMenu"> <ul> <li title="撤销"><i class="fa fa-undo"></i></li> <li title="重做"><i class="fa fa-repeat"></i></li> <li title="标题"> <i class="fa fa-header"></i> <div style="transform: translateX(-35%);"> <p class="EditorMenu_ul_li_div_p noPaddingAndMargin">设置标题</p> <ul> <li><h1 class="noPaddingAndMargin">H1</h1></li> <li><h2 class="noPaddingAndMargin">H2</h2></li> <li><h3 class="noPaddingAndMargin">H3</h3></li> <li><h4 class="noPaddingAndMargin">H4</h4></li> <li><h5 class="noPaddingAndMargin">H5</h5></li> <li><p class="noPaddingAndMargin">正文</p></li> </ul> </div> </li> <li title="字体"> <i class="fa fa-font"></i> <div style="transform: translateX(-35%);"> <p class="EditorMenu_ul_li_div_p noPaddingAndMargin">设置字体</p> <ul> <li>poppin</li> <li>微软雅黑</li> <li>宋体</li> <li>A字体</li> <li>B字体</li> <li>C字体</li> </ul> </div> </li> <li title="字号"> <i class="fa fa-text-height"></i> <div style="transform: translateX(-35%);"> <p class="EditorMenu_ul_li_div_p noPaddingAndMargin">设置字号</p> <ul> <li>x-small</li> <li>small</li> <li>normal</li> <li>large</li> <li>x-large</li> <li>xx-large</li> </ul> </div> </li> <li title="颜色"> <i class="fa fa-pencil"></i> <div style="width: 300px;transform: translateX(-45%);"> <p class="EditorMenu_ul_li_div_p noPaddingAndMargin">字体颜色</p> <ul> <li style="width:99px"><i class="fa fa-pencil" style="color: #000000;"></i></li> <li style="width:100px"><i class="fa fa-pencil" style="color: #1c487f;"></i></li> <li style="width:99px"><i class="fa fa-pencil" style="color: #4d80bf;"></i></li> <li style="width:99px"><i class="fa fa-pencil" style="color: #c24f4a;"></i></li> <li style="width:100px"><i class="fa fa-pencil" style="color: #8baa4a;"></i></li> <li style="width:99px"><i class="fa fa-pencil" style="color: #7b5ba1;"></i></li> <li style="width:99px"><i class="fa fa-pencil" style="color: #46acc8;"></i></li> <li style="width:100px"><i class="fa fa-pencil" style="color: #f9963b;"></i></li> <li style="width:99px"><i class="fa fa-pencil" style="color: #eeece0;"></i></li> <li style="width:99px"><i class="fa fa-pencil" style="color: #ffffff;"></i></li> <li style="width:99px"><i class="fa fa-magic" style="color: coral;"></i></li> </ul> </div> </li> <li title="背景色"> <i class="fa fa-paint-brush"></i> <div style="width: 300px;transform: translateX(-45%);"> <p class="EditorMenu_ul_li_div_p noPaddingAndMargin">字体颜色</p> <ul> <li style="width:99px"><i class="fa fa-paint-brush" style="color: #000000;"></i></li> <li style="width:100px"><i class="fa fa-paint-brush" style="color: #1c487f;"></i></li> <li style="width:99px"><i class="fa fa-paint-brush" style="color: #4d80bf;"></i></li> <li style="width:99px"><i class="fa fa-paint-brush" style="color: #c24f4a;"></i></li> <li style="width:100px"><i class="fa fa-paint-brush" style="color: #8baa4a;"></i></li> <li style="width:99px"><i class="fa fa-paint-brush" style="color: #7b5ba1;"></i></li> <li style="width:99px"><i class="fa fa-paint-brush" style="color: #46acc8;"></i></li> <li style="width:100px"><i class="fa fa-paint-brush" style="color: #f9963b;"></i></li> <li style="width:99px"><i class="fa fa-paint-brush" style="color: #eeece0;"></i></li> <li style="width:99px"><i class="fa fa-paint-brush" style="color: #ffffff;"></i></li> <li style="width:99px"><i class="fa fa-magic" style="color: coral;"></i></li> </ul> </div> </li> <li title="加粗"><i class="fa fa-bold"></i></li> <li title="斜体"><i class="fa fa-italic"></i></li> <li title="下划线"><i class="fa fa-underline"></i></li> <li title="删除线"><i class="fa fa-strikethrough"></i></li> <li title="对齐方式"> <i class="fa fa-paragraph"></i> <div style="transform: translateX(-35%);"> <p class="EditorMenu_ul_li_div_p noPaddingAndMargin">对齐方式</p> <ul> <li title="靠左"><i class="fa fa-list-ol"></i></li> <li title="居中"><i class="fa fa-list-ul"></i></li> <li title="靠右"><i class="fa fa-list-ul"></i></li> </ul> </div> </li> <li class="editor_menu_face" title="插入表情"> <i class="fa fa-meh-o"></i> <div style="width:300px;transform: translateX(-45%);"> <p class="EditorMenu_ul_li_div_p noPaddingAndMargin">插入表情</p> <ul> <li><span>Emoji</span></li> <li style="width:1px;background:#ccc;"></li> <li><span>更多表情</span></li> </ul> <div class="face"> <span>?</span> <span>?</span> <span>?</span> <span>?</span> <span>?</span> <span>?</span> <span>?</span> <span>?</span> <span>?</span> <span>?</span> <span>?</span> <span>?</span> <span>?</span> <span>?</span> </div> </div> </li> <li title="设置列表"> <i class="fa fa-list-ul"></i> <div style="transform: translateX(-35%);"> <p class="EditorMenu_ul_li_div_p noPaddingAndMargin">设置列表</p> <ul> <li><i class="fa fa-list-ol" title="有序列表"></i></li> <li><i class="fa fa-list-ul" title="无序列表"></i></li> </ul> </div> </li> <li title="媒体"> <i class="fa fa-tv"></i> <div style="transform: translateX(-35%);"> <p class="EditorMenu_ul_li_div_p noPaddingAndMargin">插入媒体</p> <ul> <li><i class="fa fa-youtube-play" title="视频"></i></li> <li><i class="fa fa-music" title="音乐"></i></li> </ul> </div> </li> <li title="超链接"><i class="fa fa-chain"></i></li> <li title="代码块"><i class="fa fa-terminal"></i></li> <li title="引用"><i class="fa fa-quote-left"></i></li> <li title="表格"><i class="fa fa-table"></i></li> <li title="图片"><i class="fa fa-image"></i></li> <li title="导入"><i class="fa fa-importfile"><svg t="1552977381714" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2344" xmlns:xlink="http://www.w3.org/1999/xlink" width="26" height="26" class="icon"><path d="M708.266667 460.8h-140.8V307.2H384v25.6a34.133333 34.133333 0 1 1-68.266667 0V290.133333c0-28.2752 22.9248-51.2 51.2-51.2h298.666667l110.933333 128v366.933334c0 28.2752-22.9248 51.2-51.2 51.2H366.933333c-28.2752 0-51.2-22.9248-51.2-51.2v-42.666667a34.133333 34.133333 0 1 1 68.266667 0v25.6h324.266667v-256z m0-68.266667v-0.132266l-72.533334-83.694934V392.533333h72.533334z m-352.674134 149.905067H277.282133c-16.469333 0-29.815467-14.574933-29.815466-32.554667 0-17.975467 13.3504-32.5504 29.815466-32.5504h78.3104l-27.997866-25.706666a25.924267 25.924267 0 0 1 0-38.190934 30.754133 30.754133 0 0 1 41.6 0l83.2 76.386134a25.8688 25.8688 0 0 1 8.375466 20.0704 25.8432 25.8432 0 0 1-8.375466 20.053333l-83.2 76.3904a30.754133 30.754133 0 0 1-41.6 0 25.924267 25.924267 0 0 1 0-38.190933l27.997866-25.706667z" fill="#999999" p-id="2345"></path></svg></i></li> <li title="导出"><i class="fa fa-derivefile"><svg t="1552977587969" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2453" xmlns:xlink="http://www.w3.org/1999/xlink" width="26" height="26" class="icon"><path d="M674.133333 682.666667v51.2c0 28.2752-22.9248 51.2-51.2 51.2H264.533333c-28.2752 0-51.2-22.9248-51.2-51.2V290.133333c0-28.2752 22.9248-51.2 51.2-51.2h358.4c28.2752 0 51.2 22.9248 51.2 51.2v51.2a34.133333 34.133333 0 1 1-68.266666 0v-34.133333H281.6v409.6h324.266667v-34.133333a34.133333 34.133333 0 1 1 68.266666 0z m31.325867-140.228267h-78.3104c-16.469333 0-29.815467-14.574933-29.815467-32.554667 0-17.975467 13.3504-32.5504 29.815467-32.5504h78.3104l-27.997867-25.706666a25.924267 25.924267 0 0 1 0-38.190934 30.754133 30.754133 0 0 1 41.6 0l83.2 76.386134a25.8688 25.8688 0 0 1 8.375467 20.0704 25.8432 25.8432 0 0 1-8.375467 20.053333l-83.2 76.3904a30.754133 30.754133 0 0 1-41.6 0 25.924267 25.924267 0 0 1 0-38.190933l27.997867-25.706667zM443.733333 588.782933a31.338667 31.338667 0 0 1-22.976-8.802133L375.466667 535.9104v24.0512c0 15.927467-13.371733 28.8384-29.866667 28.8384s-29.866667-12.910933-29.866667-28.842667v-95.914666c0-15.931733 13.371733-28.842667 29.866667-28.842667l0.541867 0.004267a31.317333 31.317333 0 0 1 22.434133 8.814933L443.733333 517.149867l75.157334-73.130667a31.317333 31.317333 0 0 1 22.434133-8.814933L541.866667 435.2c16.494933 0 29.866667 12.910933 29.866666 28.842667v95.914666c0 15.931733-13.371733 28.842667-29.866666 28.842667s-29.866667-12.910933-29.866667-28.842667v-24.046933l-45.290667 44.0704a31.338667 31.338667 0 0 1-22.976 8.802133z" fill="#999999" p-id="2454"></path></svg></i></li> <li title="新建"><i class="fa fa-newfile"><svg t="1552977627227" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2562" xmlns:xlink="http://www.w3.org/1999/xlink" width="26" height="26" class="icon"><path d="M511.278933 426.756267c-17.109333 22.741333 72.738133 14.208 68.458667 18.474666-47.061333 31.266133-88.4224 54.0032-149.751467 78.161067-41.361067 15.6288-86.997333 110.843733-104.1152 149.213867-18.538667 38.370133-21.393067 58.261333-27.093333 76.736-1.429333 5.687467-9.984 24.157867-27.101867 17.053866-17.1136-5.6832-17.1136-25.578667-14.263466-34.103466 48.494933-170.530133 126.933333-305.536 215.36-405.009067 19.968-22.741333 48.490667-39.790933 71.313066-46.8992 98.4064-28.420267 161.160533-24.157867 223.914667-24.157867-12.834133 18.474667-25.672533 35.528533-39.936 52.5824-2.850133 2.8416-115.52 17.0496-132.637867 39.790934-17.109333 22.737067 91.281067 7.104 88.426667 9.9456a723.473067 723.473067 0 0 1-49.92 45.474133c-2.850133 1.4208-105.536-1.4208-122.653867 22.741333zM605.866667 605.866667v-59.733334a34.133333 34.133333 0 1 1 68.266666 0v59.733334h59.733334a34.133333 34.133333 0 1 1 0 68.266666h-59.733334v59.733334a34.133333 34.133333 0 1 1-68.266666 0v-59.733334h-59.733334a34.133333 34.133333 0 1 1 0-68.266666h59.733334z" fill="#999999" p-id="2563"></path></svg></i></li> <li title="保存"><i class="fa fa-save"></i></li> <li title="预览"><i class="fa fa-eye color_SkyBlue"></i></li> <li title="帮助"><i class="fa fa-question-circle-o"></i></li> <li title="切换编辑器"><i class="fa fa-wrench color_SkyBlue"></i></li> </ul> </div> <div class="YolxRichText_editor"> <div class="LinesOfCode"> <ul class="noPaddingAndMargin"> <li>1</li> </ul> </div> <div class="editor"> <div id="YolxRichText_Input" tabindex="0" contenteditable="true"><p><br></p></div> </div> </div> <div class="YolxRichText_Preview"> <div id="YolxRichText_Ouput"> <h1>预览</h1> <div id="YolxRichText_Ouput_Preview"> </div> </div> </div> <div class="YolxRichText_Help"> <h1>帮助文档</h1> <hr /> <h3>快捷键</h3> <p> <span>撤销:Ctrl / Command + Z</span> <span>重做:Ctrl / Command + Shift + Z || Ctrl / Command + Y</span> <span>加粗:Ctrl / Command + B</span> <span>斜体:Ctrl / Command + I</span> <span>斜体:Ctrl / Command + I</span> <span>标题:Ctrl / Command + Shift + H</span> <span>无序列表:Ctrl / Command + Shift + U</span> <span>有序列表:Ctrl / Command + Shift + O</span> <span>检查列表:Ctrl / Command + Shift + C</span> <span>插入代码:Ctrl / Command + Shift + K</span> <span>插入链接:Ctrl / Command + Shift + L</span> <span>插入图片:Ctrl / Command + Shift + G</span> </p> <hr /> <h3>标题 Title</h3> <p> <span>$[Title|1] 1级标题 <span style="color:#46acc8">示例:$[Title|1]HelloWorld</span></span> <span>$[Title|2] 2级标题 <span style="color:#46acc8">示例:$[Title|2]HelloWorld</span></span> <span>$[Title|3] 3级标题 <span style="color:#46acc8">示例:$[Title|3]HelloWorld</span></span> <span>$[Title|4] 4级标题 <span style="color:#46acc8">示例:$[Title|4]HelloWorld</span></span> <span>$[Title|5] 5级标题 <span style="color:#46acc8">示例:$[Title|5]HelloWorld</span></span> <span>$[Title|p] 正文 <span style="color:#46acc8">示例:$[Title|p]HelloWorld</span></span> </p> <hr /> <h3>文本 Text</h3> <p> <span>$[Text|b]Value^ 加粗文本 <span style="color:#46acc8">示例:$[Text|b]HelloWorld^</span></span> <span>$[Text|i]Value^ 斜体文本 <span style="color:#46acc8">示例:$[Text|i]HelloWorld^</span></span> <span>$[Text|d]Value^ 删除文本 <span style="color:#46acc8">示例:$[Text|d]HelloWorld^</span></span> <span>$[Text|u]Value^ 重点文本 <span style="color:#46acc8">示例:$[Text|u]HelloWorld^</span></span> </p> <hr /> <h3>代码 Code</h3> <p> <span>$[Code|*]^ 自识别代码 <span style="color:#46acc8">$[Code|*]HelloWorld^</span></span> </p> <hr /> <h3>列表 List</h3> <p> <span>$[List|u]^ 无序列表 <span style="color:#46acc8">$[List|u]HelloWorld^</span></span> <span>$[List|o]^ 有序列表 <span style="color:#46acc8">$[List|o]HelloWorld^</span></span> </p> <hr /> <h3>表格 Table</h3> <p> <span>$[Table|*]^ 表格 <span style="color:#46acc8">$[Table|*]HelloWorld^</span></span> </p> <hr /> <h3>注释 Annotation</h3> <p> <span>$[Annotation|*]^ 注释 <span style="color:#46acc8">$[Annotation|*]HelloWorld^</span></span> </p> </div> </div>
现在就做到这里,下一篇我们继续完善
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南