一般写文章都是用一些md编辑器,例如typora,notion等等 有时候记不住快捷键就得选中需要格式化的内容格式化
索性手写一个文本编辑器demo ,直接上效果, 最后附完整代码
引用图标库
使用方法就是搜索需要的图标然后复制样式就行
html结构
结构非常简单
设置div属性contenteditable="true"
, 成为一个可编辑的富文本区域,可以在其中输入文本、执行编辑命令等
<div class="container">
<div class="options">
<button id="bold" class="option-button format">
<i class="fa-solid fa-bold"></i>
</button>
<select id="fontSize" class="adv-option-button"></select>
<div class="input-wrapper">
<input type="color" id="foreColor" class="adv-option-button" />
<label for="foreColor">字体颜色</label>
</div>
<!-- 其他options -->
</div>
<div id="text-input" contenteditable="true"></div>
</div>
主要css样式
样式也很简单
width: 90vmin;
viewport minimum
元素的宽度将占据视口宽度和高度中较小的那个的90%position: absolute;
定义left top transform 实现绝对定位居中flex-wrap: wrap;
flex容器可换行input[type='color']::-webkit-color-swatch
定义颜色选择器的style,为了兼容还可再定义::-moz-color-swatch
.container {
background-color: #fff;
width: 90vmin;
padding: 50px 30px;
position: absolute;
transform: translate(-50%, -50%);
left: 50%;
top: 50%;
border-radius: 10px;
box-shadow: 0 25px 50px rgba(7, 20, 35, 0.2);
}
.options {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 15px;
}
input[type='color']::-webkit-color-swatch {
border-radius: 15px;
box-shadow: 0 0 0 2px #fff, 0 0 0 3px #020929;
}
js部分
标记图标高亮 highlighter
className
是包含按钮类名的数组,needsRemoval
表示是否需要删除高亮;按钮被点击时添加或移除相应的类名,从而实现按钮的高亮效果- 如果
needsRemoval
为true
,则在添加新的高亮类名之前调用highlighterRemover
移除其他按钮上的高亮类名,确保每次只有一个按钮被高亮 如果按钮没有active
样式,就添加它;如果有,就移除它 - 如果
needsRemoval
为false
,则按钮的高亮状态将会切换
const highlighter = (className, needsRemoval) => {
className.forEach(button => {
button.addEventListener('click', () => {
if (needsRemoval) {
highlighterRemover(className)
button.classList.toggle('active', !button.classList.contains('active'))
} else {
button.classList.toggle('active')
}
})
})
}
const highlighterRemover = className => {
className.forEach(button => {
button.classList.remove('active')
})
}
intializer
- 相同类名的
button
调用highlighter
- 向
fontList
,fontSizeRef
添加option
let alignButtons = document.querySelectorAll(".align");
let spacingButtons = document.querySelectorAll(".spacing");
let formatButtons = document.querySelectorAll(".format");
let scriptButtons = document.querySelectorAll(".script");
let fontName = document.getElementById("fontName");
let fontSizeRef = document.getElementById("fontSize");
const fontList = [ "Arial", "Verdana", "Times New Roman", "Garamond", "Georgia", "Courier New", "Cursive"];
const intializer = () => {
highlighter(formatButtons, false);
highlighter(alignButtons, true);
highlighter(spacingButtons, true);
highlighter(scriptButtons, true);
fontList.map((value) => {
let fontStyleOption = document.createElement("option");
fontStyleOption.value = value;
fontStyleOption.innerHTML = value;
fontName.appendChild(fontStyleOption);
});
for (let i = 1; i <= 7; i++) {
let fontSizeOption = document.createElement("option");
fontSizeOption.value = i;
fontSizeOption.innerHTML = i;
fontSizeRef.appendChild(fontSizeOption);
}
fontSizeRef.value = 3; // 默认值为3
};
监听button事件
document.execCommand
有三个参数 :commandId 表示要执行的编辑命令的id标识符,defaultUi 是一个布尔值,表示是否显示用户界面,value 是可选的参数,表示执行命令时可能需要的值- 分别给 optionsButtons advancedOptionButton linkButton 监听click或change事件
/^https?:\/\//i.test(link)
匹配link是否以http://
或者https://
const modifyText = (commandId, defaultUi, value) => {
document.execCommand(commandId, defaultUi, value)
}
optionsButtons.forEach(button => {
button.addEventListener('click', () => {
modifyText(button.id, false, null)
})
})
advancedOptionButton.forEach(button => {
button.addEventListener('change', () => {
modifyText(button.id, false, button.value)
})
})
linkButton.addEventListener('click', () => {
let link = prompt('输入链接')
if (link) {
if (!/^https?:\/\//i.test(link)) {
link = 'http://' + link
}
console.log(link)
modifyText(linkButton.id, false, link)
}
})