From 4a1218e2bfa526dbd2514bcfe8f7a057cef0465e Mon Sep 17 00:00:00 2001 From: "DESKTOP-RQ919RC\\Pc" <1300399510@qq.com> Date: Tue, 14 Oct 2025 20:19:41 +0800 Subject: [PATCH] no message --- contenteditable-accessory.html | 234 +++++++++++++++++++++++++++++ css/index.css | 9 ++ css/index.less | 10 ++ fixed-keyboard-accessory.html | 265 +++++++++++++++++++++++++++++++++ index.html | 14 +- ios-keyboard-accessory.html | 247 ++++++++++++++++++++++++++++++ js/index.js | 133 +++++++++-------- keyboard-accessory.html | 227 ++++++++++++++++++++++++++++ 8 files changed, 1075 insertions(+), 64 deletions(-) create mode 100644 contenteditable-accessory.html create mode 100644 fixed-keyboard-accessory.html create mode 100644 ios-keyboard-accessory.html create mode 100644 keyboard-accessory.html diff --git a/contenteditable-accessory.html b/contenteditable-accessory.html new file mode 100644 index 0000000..bb8c7bf --- /dev/null +++ b/contenteditable-accessory.html @@ -0,0 +1,234 @@ + + + + + + Contenteditable 键盘辅助栏 + + + +
+

Contenteditable 键盘辅助栏

+ +
+
+
+ +
+
+
+
+ + +
+ + + +
+ + + + diff --git a/css/index.css b/css/index.css index 341f1f0..7695f8e 100644 --- a/css/index.css +++ b/css/index.css @@ -330,3 +330,12 @@ editor { width: 100%; height: 2.2667rem; } +.btn-f { + position: fixed; + top: 50px; + left: 0; + width: 100vw; + height: 50px; + background-color: #ff0000; + z-index: 999; +} diff --git a/css/index.less b/css/index.less index 0ddb4b9..04b7a42 100644 --- a/css/index.less +++ b/css/index.less @@ -389,3 +389,13 @@ editor { } } } + +.btn-f { + position: fixed; + top: 50px; + left: 0; + width: 100vw; + height: 50px; + background-color: #ff0000; + z-index: 999; +} diff --git a/fixed-keyboard-accessory.html b/fixed-keyboard-accessory.html new file mode 100644 index 0000000..a49b3b1 --- /dev/null +++ b/fixed-keyboard-accessory.html @@ -0,0 +1,265 @@ + + + + + + 固定定位的键盘辅助栏 + + + +
+

固定定位的键盘辅助栏

+
+ +
+ + +
+

滚动页面测试辅助栏是否固定...

+

中间位置...

+

底部位置...

+
+
+ + +
+ + + +
+ + + + + \ No newline at end of file diff --git a/index.html b/index.html index 20ff421..13963ce 100644 --- a/index.html +++ b/index.html @@ -8,9 +8,11 @@ - + + +
@@ -18,8 +20,8 @@
-
-
+
+
{{ keyboardHeight }}
#推荐标签{{ index }}
@@ -71,10 +73,10 @@
diff --git a/ios-keyboard-accessory.html b/ios-keyboard-accessory.html new file mode 100644 index 0000000..4a4b784 --- /dev/null +++ b/ios-keyboard-accessory.html @@ -0,0 +1,247 @@ + + + + + + iOS 适配键盘辅助栏 + + + +
+

iOS 键盘辅助栏(贴合键盘)

+
+ +
+
+ + +
+ + + +
+ + + + diff --git a/js/index.js b/js/index.js index bf97312..66ddcff 100644 --- a/js/index.js +++ b/js/index.js @@ -30,12 +30,18 @@ createApp({ const editorRef = ref(null); + let isIOS = false; // 是否是 ISO 设备 onMounted(() => { document.addEventListener("selectionchange", getFocusedNodeName); - // 添加键盘事件监听 document.addEventListener("keydown", handleDeleteKey); - judgeIsEmpty(); + + isIOS = /iPhone|iPad|iPod/.test(navigator.userAgent); // 检测iOS设备 + console.log("isIOS", isIOS); + + // 1. 监听视觉视口变化(iOS主要依赖这个) + if (window.visualViewport) window.visualViewport.addEventListener("resize", getKeyboardHeight.bind(this)); + else window.addEventListener("resize", getKeyboardHeight.bind(this)); }); onUnmounted(() => { @@ -206,9 +212,7 @@ createApp({ let focusedNode = selection.focusNode; // 如果是文本节点,取其父元素 - if (focusedNode.nodeType === Node.TEXT_NODE) { - focusedNode = focusedNode.parentNode; - } + if (focusedNode.nodeType === Node.TEXT_NODE) focusedNode = focusedNode.parentNode; // 检查节点是否在.editor容器内 const isInEditor = editorRef.value.contains(focusedNode); @@ -225,45 +229,16 @@ createApp({ let lastSelection = null; onMounted(() => { - setTimeout(() => { - focusLastNode(); - }, 1000); + setTimeout(() => focusLastNode(), 1000); }); const focusLastNode = () => { - const editor = document.getElementById("editor"); - const selection = window.getSelection(); - - // 清除现有选择范围 - selection.removeAllRanges(); - - // 创建新的范围对象 - const range = document.createRange(); - - // 找到最后一个有效子节点(跳过空白文本节点) - let lastNode = editor.lastChild; - while (lastNode) { - // 检查是否为有效节点(非空白文本节点) - if (!(lastNode.nodeType === 3 && lastNode.textContent.trim() === "")) { - break; - } - lastNode = lastNode.previousSibling; - } - - if (lastNode) { - // 设置范围到最后一个节点的末尾 - range.setStartAfter(lastNode); - range.setEndAfter(lastNode); - } else { - // 如果编辑器为空,选择整个编辑器 - range.selectNodeContents(editor); - range.collapse(false); - } - - // 将范围添加到选择对象,不设置焦点 - selection.addRange(range); - - editorRef.value.blur(); + const newRange = document.createRange(); + const textNode = document.createTextNode(""); + editorRef.value.appendChild(textNode); + newRange.setStartAfter(textNode, 0); + newRange.setEndAfter(textNode, 0); + lastSelection = newRange; }; let isEmpty = ref(true); @@ -285,9 +260,9 @@ createApp({ let isBottomState = ref(false); // 底部按钮 显示 const onEditorFocus = () => { isBottomState.value = true; - setTimeout(() => getKeyboardHeight(), 500); }; + let fixedState = ref(false); const onEditorBlur = () => { isBottomState.value = false; }; @@ -369,6 +344,7 @@ createApp({ // formData.append("type", "image"); // console.log("formData", formData); + const reader = new FileReader(); reader.onload = (e) => { const imgSrc = e.target.result; console.log("imgSrc", imgSrc); @@ -393,9 +369,20 @@ createApp({ span.innerHTML = `#${label} `; lastSelection.insertNode(span); - // 移动光标到emoji后面 - lastSelection.setStartAfter(span); - lastSelection.setEndAfter(span); + // 移动光标到元素后面并确保光标位置被正确设置和获取 + const newRange = document.createRange(); + newRange.setStartAfter(span); + newRange.setEndAfter(span); + + // 更新选择范围 + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(newRange); + lastSelection = newRange; + + // 手动触发selectionchange事件,确保其他组件知道光标位置变化 + const selectionChangeEvent = new Event("selectionchange", { bubbles: true }); + document.dispatchEvent(selectionChangeEvent); judgeIsEmpty(); }; @@ -412,9 +399,20 @@ createApp({ const textNode = document.createTextNode(emoji); lastSelection.insertNode(textNode); - // 移动光标到emoji后面 - lastSelection.setStartAfter(textNode); - lastSelection.setEndAfter(textNode); + // 移动光标到emoji后面并确保光标位置被正确设置和获取 + const newRange = document.createRange(); + newRange.setStartAfter(textNode); + newRange.setEndAfter(textNode); + + // 更新选择范围 + const selection = window.getSelection(); + selection.removeAllRanges(); + // selection.addRange(newRange); + lastSelection = newRange; + + // 手动触发selectionchange事件,确保其他组件知道光标位置变化 + const selectionChangeEvent = new Event("selectionchange", { bubbles: true }); + document.dispatchEvent(selectionChangeEvent); judgeIsEmpty(); getCursorPosition("emoji"); @@ -437,9 +435,9 @@ createApp({ // 计算目标位置:中间偏上(视口高度的30%位置) // 公式:元素顶部相对于视口的位置 + 滚动距离 - 目标位置(视口高度的30%) // const targetPosition = window.scrollY + rect.top - viewportHeight * 0.3; // 30%位置,比正中间更靠上 - const height = type == "emoji" ? 300 : keyboardHeight; + const height = type == "emoji" ? 300 : keyboardHeight.value; // console.log(height); - const targetPosition = window.scrollY + rect.top - (originalWindowHeight - height) + 40; + const targetPosition = window.scrollY + rect.top - (originalWindowHeight - height) + 110; // 平滑滚动到目标位置 if (Math.abs(targetPosition - window.scrollY) > 10) { @@ -458,22 +456,41 @@ createApp({ const operateRef = ref(null); onMounted(() => { - // 初始化时记录初始窗口高度 - originalWindowHeight = window.visualViewport.height; - keyboardHeight = originalWindowHeight / 2; + // 优先使用 visualViewport 高度(更准确反映视觉区域) + if (window.visualViewport) originalWindowHeight = window.visualViewport.height; + else originalWindowHeight = window.innerHeight; + + keyboardHeight.value = originalWindowHeight / 2; // 默认设置屏幕一般 }); let originalWindowHeight = 0; - let keyboardHeight = 0; + let keyboardHeight = ref(0); // 获取键盘高度 const getKeyboardHeight = () => { - const currentHeight = window.visualViewport.height; + console.log("getKeyboardHeight"); + let currentHeight = ""; + if (isIOS) currentHeight = window.visualViewport?.height || window.innerHeight; + else currentHeight = window.visualViewport ? window.visualViewport.height : window.innerHeight; - // 键盘弹出时,窗口高度会减小 - if (currentHeight < originalWindowHeight) keyboardHeight = originalWindowHeight - currentHeight; + // 计算高度差(键盘高度 = 初始高度 - 当前高度) + const diff = originalWindowHeight - currentHeight; + + // 判断键盘状态(高度差 > 100 认为是键盘弹出,避免误判) + if (diff > 100) { + console.log("键盘弹出"); + keyboardHeight.value = diff; + fixedState.value = true; + } else if (diff <= 100) { + console.log("键盘收取"); + setTimeout(() => (fixedState.value = false), 200); + // 键盘收起时重置初始高度(避免屏幕旋转等场景导致偏差) + originalWindowHeight = currentHeight; + } + + console.log("keyboardHeight:", keyboardHeight.value); }; - return { isBottomState, operateRef, onEditorBlur, onEditorFocus, cutAnonymity, isEmpty, selectEmoji, closeEmoji, openEmoji, optionEmoji, emojiState, insertLabel, editorRef, info, title, titleLength, titleTextarea, adjustTextareaHeight, isPTitle, paragraphTitle, insertImage, onEditorInput }; + return { keyboardHeight, fixedState, isBottomState, operateRef, onEditorBlur, onEditorFocus, cutAnonymity, isEmpty, selectEmoji, closeEmoji, openEmoji, optionEmoji, emojiState, insertLabel, editorRef, info, title, titleLength, titleTextarea, adjustTextareaHeight, isPTitle, paragraphTitle, insertImage, onEditorInput }; }, }).mount("#appIndex"); diff --git a/keyboard-accessory.html b/keyboard-accessory.html new file mode 100644 index 0000000..77191af --- /dev/null +++ b/keyboard-accessory.html @@ -0,0 +1,227 @@ + + + + + + H5 键盘辅助栏 + + + +
+

键盘辅助栏示例

+ +
+ +
+ +
+ +
+
+ + +
+ + + +
+ + + +