函数式组件中实现Antd打开Modal后其Input框自动聚焦(focus)到文字的最后

您所在的位置:网站首页 输入框聚焦事件怎么设置 函数式组件中实现Antd打开Modal后其Input框自动聚焦(focus)到文字的最后

函数式组件中实现Antd打开Modal后其Input框自动聚焦(focus)到文字的最后

2024-05-06 05:04| 来源: 网络整理| 查看: 265

目前React使用函数式组件已经成为趋势, 如何把React函数式组件用好, 提高性能, 从而实现业务需求也成为了一种能力的体现......咳咳咳, 进入正题:

现实场景需求

我想实现这一个需求, 父组件收到文字消息后将其传送给子组件, 子组件是一个Antd组件中的Modal, 里面只有一个input输入框, 子组件收到父组件传过来的文字消息后打开Modal对话框, 其input输入框中的默认值为父组件传递过来的文字消息, 并且自动focus到文字消息的最后, 从而方便用户输入, 当输入完之后, 点击确定按钮调用函数再把消息发送回去.

遇到的问题

怎么说呢, 我本来是打算使用一个给input输入框一个ref(inputRef), 然后当modal框打开时, 使用useEffect副作用钩子, 然后通过使用inputRef的foucs函数来实现自动聚焦, 然而想象是美好的, 现实是残酷的, 如果这么容易能解决我就不会写博客了, 先上错误代码:

import React, { useRef, useEffect } from 'react' import { Input, Modal } from 'antd' // 引入useSelector用于读取redux store中保存的数据, 引入useDispath用于分发数据 import { useSelector, useDispatch } from "react-redux" // 引入action import { change_input_modal_visible } from "../../redux/actions/visible" const { TextArea } = Input // props 传递过来的是发送消息的函数和文本编辑框已有的内容textContent export default function InputModal(props) { const inputRef = useRef() // store dispatch const dispatch = useDispatch() // store里保存的数据, 来控制modal是否显示, 父组件收到文本框编辑消息后会改为true, 从而显示modal对话框 const inputModalVisible = useSelector(state => state.visible.inputModalVisible) // 如果inputModalVisible为true, 聚焦input框 useEffect(() => { if(inputModalVisible) { inputRef.current.focus({ cursor: 'end' }) } }, [inputModalVisible, inputRef]) const handleOk = () => { let textValue = inputRef.current.resizableTextArea.props.value console.log(textValue) // 去除前后多余的空格 let res = textValue.trim() // 如果内容不为空才发送给UE4程序, 具体发送逻辑省略 // 将modal对话框关闭 dispatch(change_input_modal_visible(false)); }; // 取消发送消息 const handleCancel = () => { // 将modal对话框关闭 dispatch(change_input_modal_visible(false)); }; return ( ) }

但是bug随之就来了: image 原因是在Modal框的visible为false时, 网页上根本不会加载Modal节点, 当然就获取不到inputRef, inputRef.current的结果就为null, 下图第一张图为Modal框的visible为false时的DOM树, 第二张图为Modal框的visible为true时的DOM树: image Modal框的visible为false时的DOM树 image Modal框的visible为true时的DOM树 既然问题找到了, 那就提一下我目前的解决办法吧!

解决办法

我的解决办法是利用ref的原理, 当input输入框挂载时, 使用ref进行聚焦, 关键代码片段如下:

{ if (input != null) { input.focus({ cursor: 'end' }); } }} >

但是随之还有一个问题, 我现在ref用来进行聚焦了, 我如何拿到input输入框内的值呢? 我还要输入框消息发送回去呢! 还好Input输入框还有一个onChange函数, 我可以用这个来维护一个state来保存在state中, 既然思路有了, 就上一下源代码:

import React, { useState, useEffect } from 'react' import { Input, Modal } from 'antd' // 引入useSelector用于读取redux store中保存的数据, 引入useDispath用于分发数据 import { useSelector, useDispatch } from "react-redux" // 引入action import { change_input_modal_visible } from "../../redux/actions/visible" const { TextArea } = Input // props 传递过来的是发送消息的函数和UE4中文本编辑框已有的内容textContent export default function InputModal(props) { // 在state中保存目前输入框内的内容, 初始化为空字符串 const [textValue, setTextValue] = useState('') // store dispatch const dispatch = useDispatch() // store里保存的数据, 来控制modal是否显示, 父组件收到文本框编辑消息后会改为true, 从而显示modal对话框 const inputModalVisible = useSelector(state => state.visible.inputModalVisible) // 当props中textContent发生变化时, 即收到文本编辑框内容消息更新之后 // 同步更新保存在textValue中 useEffect(() => { setTextValue(props.textContent) }, [props.textContent]) const handleOk = () => { // 发送消息 console.log(textValue) // 去除前后多余的空格 let res = textValue.trim() // 如果内容不为空才发送给UE4程序, 具体发送逻辑不再展示 // 将modal对话框关闭 dispatch(change_input_modal_visible(false)); }; // 取消发送消息 const handleCancel = () => { // 将modal对话框关闭 dispatch(change_input_modal_visible(false)); }; const handleChange = e => { // 当输入框内容发生变化时, 同步给textValue setTextValue(e.target.value) } return ( { if (input != null) { input.focus({ cursor: 'end' }); } }} onChange={handleChange} /> ) } 结语

至此, 本篇结束, 如果大家有更好的方法, 希望大家提出来, 或者有不懂的也可以留言, 感谢!

新解决办法(2022/3/11)

此解决办法来自于此帖子, 就是给所有modal弹框或者需要展示初始化数据的子组件增加一个展示判断,显示时重新初始化就行了. 通俗的说, 就是给Modal框套一个三元表达式, 如果visible为true才加载Modal框,这样的话我们不需要维护onChange和一个state, 大大提高了性能, 代码如下:

import React, { useRef, useEffect } from 'react' import { Input, Modal } from 'antd' // 引入useSelector用于读取redux store中保存的数据, 引入useDispath用于分发数据 import { useSelector, useDispatch } from "react-redux" // 引入action import { change_input_modal_visible } from "../../redux/actions/visible" const { TextArea } = Input // props 传递过来的是发送消息的函数和UE4中文本编辑框已有的内容textContent export default function InputModal(props) { const inputRef = useRef() // store dispatch const dispatch = useDispatch() // store里保存的数据, 来控制modal是否显示, 父组件收到文本框编辑消息后会改为true, 从而显示modal对话框 const inputModalVisible = useSelector(state => state.visible.inputModalVisible) useEffect(() => { if(inputModalVisible) { inputRef.current.focus({ cursor: 'end' }) } }, [inputModalVisible, inputRef]) const handleOk = () => { // 发送消息 let textValue = inputRef.current.resizableTextArea.props.value console.log(textValue) // 去除前后多余的空格 let res = textValue.trim() // 如果内容不为空才发送消息, 具体逻辑代码省略 // 将modal对话框关闭 dispatch(change_input_modal_visible(false)); }; // 取消发送消息 const handleCancel = () => { // 将modal对话框关闭 dispatch(change_input_modal_visible(false)); }; return ( {inputModalVisible? : null} ) }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3