操作&效果
原有效果: 不管光标在哪里, 使用 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);
}
});
})()
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于