| 123456789101112131415161718192021222324252627282930313233343536373839 |
- /** Three/Cesium 视口的输入焦点边界;只接管视口内部的浏览器菜单。 */
- export function attachSceneFocus(element) {
- if (!element || typeof element.addEventListener !== 'function') return () => {}
- const tabIndex = element.getAttribute?.('tabindex') ?? null
- if (tabIndex === null) element.setAttribute?.('tabindex', '0')
- const editable = (target) => target?.closest?.('input, textarea, select, [contenteditable]')
- const focus = () => element.focus?.({ preventScroll: true })
- const onDown = (event) => {
- if (event.button !== 0 && event.button !== 2) return
- if (editable(event.target) || event.target?.closest?.('button, a, [role="button"]')) return
- focus()
- }
- const onMenu = (event) => {
- if (editable(event.target)) return
- event.preventDefault()
- event.stopPropagation()
- focus()
- }
- const onFocus = () => element.setAttribute?.('data-scene-focused', 'true')
- const onBlur = (event) => {
- if (!element.contains?.(event.relatedTarget)) element.removeAttribute?.('data-scene-focused')
- }
- // 捕获阶段覆盖 canvas、三维标签和覆盖层,即使后代停止冒泡也不会漏掉右键。
- const capture = { capture: true }
- element.addEventListener('pointerdown', onDown, capture)
- element.addEventListener('contextmenu', onMenu, capture)
- element.addEventListener('focusin', onFocus)
- element.addEventListener('focusout', onBlur)
- return () => {
- element.removeEventListener('pointerdown', onDown, capture)
- element.removeEventListener('contextmenu', onMenu, capture)
- element.removeEventListener('focusin', onFocus)
- element.removeEventListener('focusout', onBlur)
- element.removeAttribute?.('data-scene-focused')
- if (tabIndex === null) element.removeAttribute?.('tabindex')
- }
- }
|