操作&效果
原有效果: 不管光标在哪里, 使用 ctrl+homne
或 ctrl+end
都是跳转到整个文档的开头和结尾
修改后效果:
- 当光标在代码块中间的时候, 使用
ctrl+homne
或ctrl+end
跳转到代码块的开头和结尾 - 当光标在代码块开头和结尾的时候, 跳转到整个文档的开头和结尾
- 当光标在非代码块的时候, 跳转到整个文档的开头和结尾
js 代码
(()=>{ // 获取光标所在的元素 function getElementAtCursor() { const selection = window.getSelection(); if (selection.rangeCount > 0) { const range = selection.getRangeAt(0); const startContainer = range.startContainer; // 如果是文本节点,获取其父元素 const element = startContainer.nodeType === 3 ? startContainer.parentNode : startContainer; return element; } return null; // 如果没有选中内容或光标位置无效 } // 当前块是否是代码块 function getCodeBlockDfs(ele) { if (ele.classList.contains('protyle-wysiwyg')) { return null } if (ele.classList.contains('hljs')) { return ele } return getCodeBlockDfs(ele.parentElement) } async function handle_goto_home(event, element) { if (!element) { return; } element = getCodeBlockDfs(element) if (element == null) { console.log("[跳转开头] 所在位置不是代码块, 使用默认功能") return; } // 找到代码块的第一个子元素, 用于判断 let firstChild = element.querySelector('[contenteditable="true"]')?.firstChild if (firstChild == null) { console.log("[跳转开头] 子元素寻找失败, 使用默认功能") return; } // 获取当前的 Selection 对象 const selection = window.getSelection(); // 获取选择的范围 const range = selection.getRangeAt(0); // 判断光标是否在第一个子元素的开头 if (range.startContainer !== firstChild || range.startOffset !== 0) { if (range.startContainer !== firstChild) { console.log("[跳转开头] 不在第一个子元素附近, 功能生效") } else if (range.startOffset !== 0) { console.log("[跳转开头] 不在第一个子元素的开头, 功能生效") } event.preventDefault(); // 防止快捷键默认行为 event.stopPropagation(); // 停止事件传播 // 如果不在,移动到最前面 range.selectNodeContents(firstChild); range.collapse(true); selection.removeAllRanges(); selection.addRange(range); } else { console.log("[跳转开头] 已经在最开头了, 使用默认功能") } } async function handle_goto_end(event, element) { if (!element) { return; } element = getCodeBlockDfs(element) if (element == null) { console.log("[跳转末尾] 所在位置不是代码块, 使用默认功能") return; } // 找到代码块的第一个子元素, 用于判断 let lastChild = element.querySelector('[contenteditable="true"]')?.lastChild if (lastChild == null) { console.log("[跳转末尾] 子元素寻找失败, 使用默认功能") return; } // 获取当前的 Selection 对象 const selection = window.getSelection(); // 获取选择的范围 const range = selection.getRangeAt(0); // 判断光标是否在第一个子元素的开头 if (range.startContainer !== lastChild || range.startOffset !== lastChild.textContent.length) { if (range.startContainer !== lastChild) { console.log("[跳转末尾] 不在最后一个子元素附近, 功能生效") } else if (range.startOffset !== lastChild.textContent.length) { console.log("[跳转末尾] 不在最后一个子元素的末尾, 功能生效") } event.preventDefault(); // 防止快捷键默认行为 event.stopPropagation(); // 停止事件传播 // 如果不在,移动到最前面 range.selectNodeContents(lastChild); range.collapse(false); selection.removeAllRanges(); selection.addRange(range); } else { console.log("[跳转末尾] 已经在代码块最末尾了, 使用默认功能") } } // 事件监听 document.addEventListener('keydown', async (event) => { let element = getElementAtCursor(); // event.preventDefault(); // 防止快捷键默认行为 // event.stopPropagation(); // 停止事件传播 if (event.ctrlKey && !event.shiftKey && !event.altKey && event.key.toLowerCase() === 'home') { // 判断是否需要处理 跳转到代码块开头, 并处理 handle_goto_home(event, element); } else if (event.ctrlKey && !event.shiftKey && !event.altKey && event.key.toLowerCase() === 'end') { // 判断是否需要处理 跳转到代码块末尾, 并处理 handle_goto_end(event, element); } }); })()
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于