React Native Web/Expo中如何为Pressable模拟focus-visible效果
问题1解决方案:点击后自动清除focused状态
直接在onPress回调中主动让当前聚焦的DOM元素失焦即可,需要加端判断避免Native端运行报错:
import { Platform } from 'react-native'; <Pressable onPress={() => { if (Platform.OS === 'web') { document.activeElement.blur(); } // 此处可追加原有业务逻辑 }} style={({pressed, hovered, focused}) => [ { backgroundColor: pressed ? "orange" : hovered ? "green" : focused ? "red" : "lightgray", padding: 20 } ]}> { ({pressed, hovered, focused}) => ( <Text> {pressed ? "Pressed" : hovered ? "Hovered" : focused ? "Focused" : "Default"} </Text> ) } </Pressable>
点击后元素会立即失焦,focused状态自动变为false,样式回到默认的浅灰色。
问题2解决方案:手动实现focus-visible效果
如果不想破坏默认聚焦行为,只需要区分「键盘触发的聚焦」和「鼠标点击触发的聚焦」,可以通过监听全局输入事件维护输入类型状态,结合Pressable的focused状态判断应用哪套样式:
import { useState, useEffect } from 'react'; import { Platform, Pressable, Text } from 'react-native'; const FocusVisiblePressable = () => { // 标记当前聚焦是否来自键盘操作 const [isKeyboardTrigger, setIsKeyboardTrigger] = useState(false); useEffect(() => { // 仅web端需要监听事件 if (Platform.OS !== 'web') return; // 按下Tab键时标记为键盘操作 const handleKeyDown = (e) => e.key === 'Tab' && setIsKeyboardTrigger(true); // 鼠标/触摸操作时标记为非键盘操作 const handlePointerDown = () => setIsKeyboardTrigger(false); window.addEventListener('keydown', handleKeyDown); window.addEventListener('pointerdown', handlePointerDown); return () => { window.removeEventListener('keydown', handleKeyDown); window.removeEventListener('pointerdown', handlePointerDown); }; }, []); return ( <Pressable style={({pressed, hovered, focused}) => [ { padding: 20, // 仅键盘触发的聚焦才显示聚焦样式 backgroundColor: pressed ? "orange" : hovered ? "green" : (focused && isKeyboardTrigger) ? "red" : "lightgray", } ]} > { ({pressed, hovered, focused}) => ( <Text> {pressed ? "Pressed" : hovered ? "Hovered" : (focused && isKeyboardTrigger) ? "Focused" : "Default"} </Text> ) } </Pressable> ) }
如果需要多组件复用,可以把事件监听的逻辑抽成自定义Hook,全局共享输入类型状态即可。
内容的提问来源于stack exchange,提问作者wongx
相关产品推荐
相关产品推荐

