You've already forked SmartisanNote.Remake
优化 头部便签管理点击区域;
补充注释;
This commit is contained in:
@@ -50,42 +50,43 @@ onMounted(() => {
|
||||
}
|
||||
})
|
||||
|
||||
// 工具配置
|
||||
// 工具栏配置
|
||||
// 定义富文本编辑器的所有工具按钮及其功能
|
||||
const tools = ref([
|
||||
{
|
||||
name: 'bold',
|
||||
name: 'bold', // 加粗工具
|
||||
icon: '/assets/icons/drawable-xxhdpi/rtf_bold_normal.9.png',
|
||||
action: () => formatText('bold'),
|
||||
active: false,
|
||||
action: () => formatText('bold'), // 执行加粗格式化
|
||||
active: false, // 工具是否处于激活状态
|
||||
},
|
||||
{
|
||||
name: 'center',
|
||||
name: 'center', // 居中对齐工具
|
||||
icon: '/assets/icons/drawable-xxhdpi/rtf_center_normal.9.png',
|
||||
action: () => formatText('justifyCenter'),
|
||||
action: () => formatText('justifyCenter'), // 执行居中对齐格式化
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
name: 'todo',
|
||||
name: 'todo', // 待办事项工具
|
||||
icon: '/assets/icons/drawable-xxhdpi/rtf_gtasks_normal.9.png',
|
||||
action: () => formatText('insertTodoList'),
|
||||
action: () => formatText('insertTodoList'), // 插入待办事项列表
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
name: 'list',
|
||||
name: 'list', // 无序列表工具
|
||||
icon: '/assets/icons/drawable-xxhdpi/rtf_list_normal.9.png',
|
||||
action: () => formatText('insertUnorderedList'),
|
||||
action: () => formatText('insertUnorderedList'), // 插入无序列表
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
name: 'header',
|
||||
name: 'header', // 标题工具
|
||||
icon: '/assets/icons/drawable-xxhdpi/rtf_header_normal.9.png',
|
||||
action: () => formatText('formatBlock', 'h2'),
|
||||
action: () => formatText('formatBlock', 'h2'), // 格式化为二级标题
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
name: 'quote',
|
||||
name: 'quote', // 引用工具
|
||||
icon: '/assets/icons/drawable-xxhdpi/rtf_quot_normal.9.png',
|
||||
action: () => insertQuote(),
|
||||
action: () => insertQuote(), // 插入引用格式
|
||||
active: false,
|
||||
},
|
||||
])
|
||||
@@ -112,6 +113,7 @@ const handleInput = () => {
|
||||
}
|
||||
|
||||
// 检查当前选区是否已经在某种格式中
|
||||
// 用于防止重复应用相同的格式,例如重复加粗
|
||||
const isAlreadyInFormat = formatType => {
|
||||
const selection = window.getSelection()
|
||||
if (selection.rangeCount > 0) {
|
||||
@@ -121,10 +123,15 @@ const isAlreadyInFormat = formatType => {
|
||||
// 向上查找父元素,检查是否已经在指定格式中
|
||||
let current = container.nodeType === Node.TEXT_NODE ? container.parentElement : container
|
||||
while (current && current !== editorRef.value) {
|
||||
// 检查加粗格式
|
||||
if (formatType === 'bold' && current.tagName === 'B') return true
|
||||
// 检查居中对齐格式
|
||||
if (formatType === 'center' && current.style.textAlign === 'center') return true
|
||||
// 检查标题格式
|
||||
if (formatType === 'header' && current.tagName === 'H2') return true
|
||||
// 检查引用格式
|
||||
if (formatType === 'quote' && (current.tagName === 'BLOCKQUOTE' || current.classList.contains('quote-content'))) return true
|
||||
// 检查列表格式
|
||||
if (formatType === 'list' && (current.tagName === 'UL' || current.tagName === 'OL' || current.tagName === 'LI')) return true
|
||||
current = current.parentElement
|
||||
}
|
||||
@@ -133,6 +140,7 @@ const isAlreadyInFormat = formatType => {
|
||||
}
|
||||
|
||||
// 检查是否在列表、引用或待办事项中(用于嵌套限制)
|
||||
// 防止在已有的列表、引用或待办事项中再次插入相同类型的元素
|
||||
const isInListOrQuote = () => {
|
||||
const selection = window.getSelection()
|
||||
if (selection.rangeCount > 0) {
|
||||
@@ -142,7 +150,10 @@ const isInListOrQuote = () => {
|
||||
// 向上查找父元素,检查是否在列表、引用或待办事项中
|
||||
let current = container.nodeType === Node.TEXT_NODE ? container.parentElement : container
|
||||
while (current && current !== editorRef.value) {
|
||||
if (current.tagName === 'UL' || current.tagName === 'OL' || current.tagName === 'LI' || current.tagName === 'BLOCKQUOTE' || current.classList.contains('quote-content') || current.classList.contains('todo-container')) {
|
||||
// 检查是否在列表、引用或待办事项中
|
||||
if (current.tagName === 'UL' || current.tagName === 'OL' || current.tagName === 'LI' ||
|
||||
current.tagName === 'BLOCKQUOTE' || current.classList.contains('quote-content') ||
|
||||
current.classList.contains('todo-container')) {
|
||||
return true
|
||||
}
|
||||
current = current.parentElement
|
||||
@@ -152,8 +163,10 @@ const isInListOrQuote = () => {
|
||||
}
|
||||
|
||||
// 格式化文本
|
||||
// 根据指定的命令和值对选中文本应用格式
|
||||
const formatText = (command, value = null) => {
|
||||
// 检查是否已经应用了相同的格式,如果已应用则取消格式
|
||||
// 例如,如果文本已经是加粗的,再次点击加粗按钮会取消加粗
|
||||
if (command === 'bold' && isAlreadyInFormat('bold')) {
|
||||
document.execCommand('bold', false, null)
|
||||
updateToolbarState()
|
||||
@@ -161,6 +174,7 @@ const formatText = (command, value = null) => {
|
||||
return
|
||||
}
|
||||
|
||||
// 处理居中对齐切换:如果已居中则取消居中
|
||||
if (command === 'justifyCenter' && isAlreadyInFormat('center')) {
|
||||
document.execCommand('justifyLeft', false, null)
|
||||
updateToolbarState()
|
||||
@@ -168,6 +182,7 @@ const formatText = (command, value = null) => {
|
||||
return
|
||||
}
|
||||
|
||||
// 处理标题格式切换:如果已是标题则转为普通段落
|
||||
if (command === 'formatBlock' && value === 'h2' && isAlreadyInFormat('header')) {
|
||||
document.execCommand('formatBlock', false, '<p>')
|
||||
updateToolbarState()
|
||||
@@ -175,6 +190,7 @@ const formatText = (command, value = null) => {
|
||||
return
|
||||
}
|
||||
|
||||
// 处理列表格式切换:如果已是列表则取消列表
|
||||
if (command === 'insertUnorderedList' && isAlreadyInFormat('list')) {
|
||||
document.execCommand('insertUnorderedList', false, null)
|
||||
updateToolbarState()
|
||||
@@ -189,13 +205,16 @@ const formatText = (command, value = null) => {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查嵌套限制
|
||||
// 检查嵌套限制,防止在列表、引用中再次插入列表或引用
|
||||
if ((command === 'insertUnorderedList' || (command === 'formatBlock' && value === 'blockquote')) && isInListOrQuote()) {
|
||||
return
|
||||
}
|
||||
|
||||
// 执行格式化命令
|
||||
document.execCommand(command, false, value)
|
||||
// 更新工具栏状态以反映当前格式
|
||||
updateToolbarState()
|
||||
// 触发输入事件以更新内容
|
||||
handleInput()
|
||||
}
|
||||
|
||||
@@ -283,39 +302,40 @@ const insertQuote = () => {
|
||||
}
|
||||
|
||||
// 插入待办事项列表
|
||||
// 创建一个可交互的待办事项元素,包含复选框图标和可编辑内容区域
|
||||
const insertTodoList = () => {
|
||||
const selection = window.getSelection()
|
||||
if (selection.rangeCount > 0) {
|
||||
const range = selection.getRangeAt(0)
|
||||
|
||||
// 检查嵌套限制
|
||||
// 检查嵌套限制,防止在列表或引用中插入待办事项
|
||||
if (isInListOrQuote()) return
|
||||
|
||||
// 创建待办事项容器
|
||||
const todoContainer = document.createElement('div')
|
||||
todoContainer.contentEditable = false
|
||||
todoContainer.contentEditable = false // 容器本身不可编辑
|
||||
todoContainer.className = 'todo-container'
|
||||
|
||||
// 创建图标元素
|
||||
// 创建图标元素(复选框)
|
||||
const icon = document.createElement('img')
|
||||
icon.className = 'todo-icon'
|
||||
icon.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png'
|
||||
icon.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png' // 未完成状态图标
|
||||
icon.alt = '待办事项'
|
||||
|
||||
// 创建内容容器
|
||||
// 创建内容容器(可编辑区域)
|
||||
const contentSpan = document.createElement('div')
|
||||
contentSpan.contentEditable = true
|
||||
contentSpan.contentEditable = true // 内容区域可编辑
|
||||
contentSpan.className = 'todo-content'
|
||||
contentSpan.textContent = '待办事项'
|
||||
contentSpan.textContent = '待办事项' // 默认文本
|
||||
|
||||
// 组装元素
|
||||
// 组装元素:将图标和内容区域添加到容器中
|
||||
todoContainer.appendChild(icon)
|
||||
todoContainer.appendChild(contentSpan)
|
||||
|
||||
// 插入到当前光标位置
|
||||
range.insertNode(todoContainer)
|
||||
|
||||
// 添加换行
|
||||
// 添加换行,确保待办事项下方有空白行
|
||||
const br = document.createElement('br')
|
||||
todoContainer.parentNode.insertBefore(br, todoContainer.nextSibling)
|
||||
|
||||
@@ -338,19 +358,21 @@ const insertTodoList = () => {
|
||||
}
|
||||
}, 0)
|
||||
|
||||
// 添加事件监听器到图标
|
||||
// 添加事件监听器到图标,实现待办事项完成状态切换
|
||||
icon.addEventListener('click', function () {
|
||||
// 根据当前状态切换图标
|
||||
// 根据当前状态切换图标和样式
|
||||
if (this.src.includes('rtf_icon_gtasks.png')) {
|
||||
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks_light.png'
|
||||
contentSpan.style.color = 'var(--text-tertiary)'
|
||||
contentSpan.style.textDecoration = 'line-through'
|
||||
// 切换到完成状态
|
||||
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks_light.png' // 完成状态图标
|
||||
contentSpan.style.color = 'var(--text-tertiary)' // 灰色文字
|
||||
contentSpan.style.textDecoration = 'line-through' // 添加删除线
|
||||
} else {
|
||||
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png'
|
||||
contentSpan.style.color = 'var(--note-content)'
|
||||
contentSpan.style.textDecoration = 'none'
|
||||
// 切换到未完成状态
|
||||
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png' // 未完成状态图标
|
||||
contentSpan.style.color = 'var(--note-content)' // 正常文字颜色
|
||||
contentSpan.style.textDecoration = 'none' // 移除删除线
|
||||
}
|
||||
handleInput()
|
||||
handleInput() // 触发内容更新
|
||||
})
|
||||
|
||||
// 添加事件监听器到内容区域,监听内容变化和按键事件
|
||||
@@ -365,8 +387,8 @@ const insertTodoList = () => {
|
||||
}, 0)
|
||||
}
|
||||
|
||||
contentSpan.addEventListener('input', checkContent)
|
||||
contentSpan.addEventListener('blur', checkContent)
|
||||
contentSpan.addEventListener('input', checkContent) // 内容输入时检查
|
||||
contentSpan.addEventListener('blur', checkContent) // 失去焦点时检查
|
||||
|
||||
// 添加焦点事件监听器,确保工具栏在待办事项获得焦点时保持可见
|
||||
contentSpan.addEventListener('focus', () => {
|
||||
|
||||
Reference in New Issue
Block a user