当用户在浏览器中保存了一个用于表单名称的受控组件时(通常与用户名/密码字段一起使用),浏览器有时会使用这些字段中的值来呈现页面,而不会触发onChange事件。 如果用户提交表单,则组件状态不会反映向用户显示的内容。
在对此进行试验时,似乎数据已加载(通过记录this.refs.myinput.getDOMNode()。value进行测试)
这似乎要讨论更多: http :
atm我正在使用这个https://github.com/tbosch/autofill-event
抄送我
( @visionscaper提示:按右列中的“订阅”。)
有任何更新或建议的最佳做法吗? 自动填充事件polyfill似乎是大锤解决方案。
Safari(8)确实在自动填充上调度了更改事件,但它们不会冒泡,因此无法到达react处理程序。
已结束对https://github.com/angular/angular.js/issues/1460的相关讨论,并提出了一些建议,其中一项建议是利用https://github.com/tbosch/autofill-event触发手动更改自动填充事件。
我认为,我们也可以在这里关闭。
最好将autofill-event作为React的一部分,可以作为一个插件。 几乎每个使用React进行表单验证的人都将需要此功能。 autofill-event脚本还为jQuery添加了一个依赖项,这在许多情况下可能是不可取的。
这是一个浏览器错误,对所有浏览器的影响略有不同。 我认为,仅仅因为在尝试解决或修复问题时遇到了麻烦,并不意味着应该做出反应。 这是很平常的事情,但我知道这是否是“ Wontfix”。
我对各种浏览器的错误跟踪器不是很精通,但是如果有人可以为此找到或打开问题,那就太好了。 我认为反应团队的权重比大多数用户在解决问题时要强。 我们可以在这里为有兴趣的反应开发人员准备门票。
我赶上了角线。 Firefox的密码字段存在问题(https://bugzilla.mozilla.org/show_bug.cgi?id=950510仍处于打开状态),Safari浏览器的bug号无字,chrome已修复。
问题已经在某些地方被跟踪-https : //github.com/angular/angular.js/issues/1460#issuecomment -53947546
Chrome问题现已关闭,但显然不能在带有React 0.14.8的Chrome 50中使用。
还没有解决?
我觉得这工作了一段时间,最近又坏了吗?
这个问题有任何更新吗?
这是我针对此问题的解决方案的摘录:
export default class Input extends Component {
static propTypes = {
value: PropTypes.string,
onFieldChange: PropTypes.func,
};
static defaultProps = {
value: '',
}
componentDidMount() {
this._listener = setInterval(() => {
if (!this.input || this._previousValue === this.input.value) {
return;
}
this._previousValue = this.input.value;
const evt = document.createEvent('HTMLEvents');
evt.initEvent('input', true, true);
this.input.dispatchEvent(evt);
}, 20);
}
componentWillUnmount() {
clearInterval(this._listener);
}
refInput = (input) => this.input = input;
render() {
const { label,
value,
onFieldChange,
} = this.props;
this.input = this.input || { value };
return (
<input
value={this.input.value}
onChange={onFieldChange}
ref={this.refInput}
/>
);
}
}
注意: value
来自该州, onFieldChange
用新值更新该州
setInterval代码来自https://github.com/Pephers/react-autofill
谁能确认此问题已在iOS 10.2中修复? 我现在无法重现...
我在iOS 10.2的Chrome版本55.0.2883.79上仍然遇到问题...与上述内容相反,对我来说,自动填充的内容会在表单中短暂闪烁,然后再次删除。
因此,它现在与状态中存储的内容一致,但是,自动填充仍然无法正常工作...
我正在重现@irisSchaffer遇到的相同问题。 我有一个同构的应用程序,在这里我用react和express渲染一个静态页面,然后在客户端上导出道具并使用相同的页面组件。
即使不通过react处理密码输入值,客户端chrome组件也会从输入中删除保存的密码,即使chrome短暂显示该密码也是如此。 当我从浏览器禁用javascript时,保存的密码将保留在该位置。
此问题仅在使用最新版本58的Chrome上可见。
与反应无关,保存的密码无法通过element.value访问,直到在dom上触发了一个事件(如焦点,任何键事件等)为止。尝试通过javascript模拟事件触发,值的填充没有运气属性。
+1。 任何修复或黑客攻击?
我仍在iOS 10.3.3 Chrome 60.0.3112.89上遇到此问题。
自动填充有效,可以填充字段,但不会更改状态。
装饰器解决方法: https :
通用组件的解决方法:
/**
Trigger onChange event after browser auto-fill.
<strong i="8">@see</strong> https://github.com/facebook/react/issues/1159
<strong i="9">@example</strong> <AutoFillWatch component={ref =>
<input required type="password" ref={ref} />
}/>
*/
class AutoFillWatch extends Component {
static propTypes = {
// Auto-fill component like: <input type="password"
component: PropTypes.func.isRequired,
// component pass-through reference
ref: PropTypes.func,
}
componentDidMount() {
this._listener = setInterval(() => {
if (!this.input || this._previousValue === this.input.value) {
return;
}
this._previousValue = this.input.value;
const evt = document.createEvent('HTMLEvents');
evt.initEvent('input', true, true);
this.input.dispatchEvent(evt);
}, 100);
}
componentWillUnmount() {
clearInterval(this._listener);
}
componentDidMount() {
const {ref} = this.props
if(ref) {
console.log('ref', this.input);
ref(this.input)
}
}
refInput = (input) => this.input = input;
render() {
const {component} = this.props
return component(this.refInput)
}
}
Chrome for iOS(请确保您使用Chrome的自动填充功能进行测试,而不是iOS键盘上的建议进行测试),在自动填充值时只会发出change
。 另一方面,移动Safari会发出focus
, keydown
, input
, keyup
, change
和blur
,在Mac上执行Chrome和Safari。
React不会为常规<input />
使用change
事件,这似乎是此问题的根本原因: https :
React onChange
也可以在DOM change
事件上触发吗? 会有什么危害吗?
Chrome iOS的相关问题: https :
我已经在下面的小页面上测试了自动填充和事件:
<html>
<head>
<script type="text/javascript">
window.onload = function () {
let elements = document.querySelectorAll('input');
let actions = document.getElementById('actions')
let events = 'focus blur keydown keyup change input'.split(' ');
elements.forEach(element => {
events.forEach(event => {
element.addEventListener(event, e => {
console.log(e);
let eTypeNode = document.createTextNode(element.name + ' > ' + e.type + ":" + e.code + ":" + e.keyIdentifier);
actions.appendChild(eTypeNode);
actions.appendChild(document.createElement('br'));
})
})
})
};
</script>
</head>
<body>
<form>
<input type="text" name="name" id="a" autocomplete="name" />
<input type="email" name="email" id="b" autocomplete="email" />
<input type="tel" name="tel" id="c" autocomplete="tel" />
</form>
<div id="actions"></div>
</body>
</html>
当您用<form />
元素包装输入时,Chrome v62中会发出Change事件。
有一个onInput事件处理程序,如果发生更改,它将捕获输入字段的值。
在iOS上使用自动填充功能仍会看到一些异常行为。 上面的react-autofill装饰器似乎可以通过简单的autofill很好地工作,但是不能通过键盘提供的autofill快捷方式。
现在应在iOS专用的Chrome浏览器中修复此问题: https :
为什么一定要用 onChange?
Why do we HAVE to use 'onChange' but not the 'change event'
class Input extends Component {
componentDidMount(){
this.input.addEventListener('change', (e)=>{
this.props.onChange(this.props.field, e.target.value)
})
}
render(){
const { className, name, label, autofill, field, onBlur, onChange, value, error, visited, required, type, maxLength } = this.props
return (
<div className={ [styles.inputWrap, className || ''].join(' ') } onBlur={e => onBlur(field)}>
<input ref={n => this.input = n} id={field} name={name || field} type={ type || 'text' } defaultValue={ value }
autoComplete={ autofill } maxLength={maxLength} />
<div className={ [styles.placeholder, value? styles.active:''].join(' ') }>
<FormattedMessage id={label} />
<i className={styles.required}>{required? '*':''}</i>
<span className={ styles.error }>{ visited? error:'' }</span>
</div>
</div>
)
}
}
当您用
<form />
元素包装输入时,Chrome v62中会发出Change事件。
我确认该解决方案适用于Chrome,可通过autoComplete="tel"
自动填充电话号码
https://github.com/catamphetamine/react-phone-number-input/issues/101
不幸的是,以上使用this._previousValue !== this.input.value
的解决方案仅适用于iOS Safari。 自动填充后,iOS Chrome的.value
仍然为空。
我不知道人们在使用受控组件时如何处理表单的自动填充。 考虑以下登录方案:
.value
为空除非有一种方法让Chrome报告值,否则我不会想到一种解决方案,除了使用不受控制的组件,html5输入验证以及像过去一样在提交时获取表单值。
您可以在此处跟踪(并标记问题): https :
我无法通过以上解决方案来使用@DominicTobias。 存在多层问题。 首先是this.input.value
总是返回空白。 但是,我发现,如果您在每个循环中使用document.getElementById
,那么document.getElementById(id).value
-您将获得一个返回值。
这不能解决dispatchEvent
问题,但是至少您可以获得自动填充的值并可以对其进行填充(例如,仅调用受控输入的onChange
处理程序)。
@wlingke很高兴知道(而且很奇怪)! 如果他们没有及时解决我发布的错误,我也必须走这条路
@wlingke在为Chrome家伙设置演示时,我意识到了一些事情-这与Chrome无关,我应该更仔细地阅读以上注释(尤其是@ oscar-b注释)。 onChange
是React中的综合事件,实际上并没有使用change
事件,这对我来说似乎很奇怪。
您甚至可以在下面的演示中看到它的行为不同,更像是在监听input
事件。 当您使用实际的change
事件时,它在iOS Chrome中可以正常运行。
因此,我建议您获取一个ref元素,然后收听真正的change事件以及onChange
事件,如果您需要将状态更新为input
事件,则该事件似乎是
演示: https :
@DominicTobias我以前分别在该装饰器中分别尝试了change
和input
事件,并且一次都尝试了两次,但无法在我的应用程序中使用它。
另外我不确定这是否会改变..但是自动填充ONE字段与自动填充MULTIPLE字段有区别。 自动填充一个字段时, input
事件工作正常。 但是,在移动Chrome浏览器中,实际上您可以一次从键盘自动填充一组字段(例如,姓,名,一键发送所有电子邮件)。
在第二种情况下,装饰器允许第一个字段正确自动填充(第一个字段表示当前处于焦点状态的字段)。 但是,装饰器(附加到所有3个字段)似乎在其他字段上不起作用。
@wlingke有趣的是,我添加了更多字段,但是当在iOS Chrome中一次自动填充这三个字段时,我正确地接收了本地更改事件(但以下React版本为0):
(屏幕截图来自桌面浏览器,但我在手机上得到的结果相同)
@DominicTobias我认为,如果您使用input
事件-这是我以前使用的事件,它将在Desktop中完全起作用。 并为Mobile中的第一个输入工作。
input
事件最接近react的onChange
。 change
事件仅在某个元素失去我所了解的焦点之后提交(https://stackoverflow.com/questions/17047497/what-is-the-difference-between-change-and-input-event-输入元素)
是的,由于某种原因,react绑定了onChange到input
事件: https :
因此,为了简单起见,我只在Input
组件中将其称为实际更改事件(以及正常输入事件)。 现在可以在iOS Chrome浏览器中使用了。 试试看,让我知道!
componentDidMount() {
this.inputRef.addEventListener('change', this.onChange);
}
onChange = (event) => {
// React actually uses the input even for onChange, this causes autofill to
// break in iOS Chrome as it only fires a change event.
if (this.props.onChange) {
this.props.onChange(event);
}
}
componentWillUnount() {
this.inputRef.removeEventListener('change', this.onChange);
}
编辑:Chrome应该已经在v65中修复,但人们报告它仍然无法正常工作:/
谢谢您对多米尼克的解释。 我们确实在12月修正了该行为。 现在,我们触发键盘按下,更改,输入和键盘按下事件。
https://chromium-review.googlesource.com/c/chromium/src/+/771674我们还修复了React。
https://chromium-review.googlesource.com/c/chromium/src/+/844324尽管这确实解决了自动填充行为,但仍不调用onChange处理程序。
我对此也提出了一个问题,开发人员确信它将在65中得到修复... https://bugs.chromium.org/p/chromium/issues/detail?id=813175
我还在听@DominicTobias这样的本地change
事件,它在iOS Chrome浏览器中对我有效。 我正在挂载在附加的本机事件侦听器中触发redux-form的onChange
。
我还使用input:-webkit-autofill
选择器进行样式设置。
在https://labrewlangerie.com底部(联系表)亲自查看结果。
似乎此修复程序终于可以在Chrome iOS中使用! 不过不确定是什么版本,因为这似乎已在12月1日合并。
https://bugs.chromium.org/p/chromium/issues/detail?id=705275#c11
https://chromium-review.googlesource.com/c/chromium/src/+/771674
在Chrome 65,React 15.6中也是如此。
令人遗憾的是,Mahmadi表示将于3月13日在v65上进行:(
评论15作者[email protected] ,3月9日
该修复程序不在Chrome 64中。 Chrome 65将具备(将于3月13日开始推出)。 我刚刚测试了您的本地事件演示网站,并且该网站可以在Chrome 65上运行。非常感谢您关注此事。
https://bugs.chromium.org/p/chromium/issues/detail?id=813175
尝试在手机上转到此处并检查: https :
真正奇怪的是,它在v65中本机运行,但是即使它得到输入,即使它没有在React中被接收! 需要进一步研究,我不确定是附加处理程序的反应如何(或者是否在文档元素上进行处理,例如单击处理程序)。
在本地,我可以看到输入事件现在正在发生(https://kind-stallman-f3c045.netlify.com/native.html):
但是不知何故,React没有收到任何这些事件(https://kind-stallman-f3c045.netlify.com):
在输入上添加onBlur = {this.handleChange}
KlarnaUI小组有一个有趣的技巧,可以利用onAnimationStart
事件和:-webkit-autofill
伪类来解决此问题,如本文所述-https : //medium.com/@brunn/detecting -autofilled- javascript-aed598d25da7中的字段
我们已经在我们的应用程序中使用了该技巧,它可以正常工作(只能在Chrome上进行测试)。 我将尝试使用这种技术来创建垫片,以使其具有通用性。
关于这个问题有任何更新吗?
起来,目前最好的技巧是什么?
@ericflo @sophiebits
这个问题似乎仍然存在,是否有任何更新?
@Pixelatex @Aarbel进一步了解我的答案-https : //github.com/facebook/react/issues/1159#issuecomment -371604044
基本上,React侦听input
事件,而不是onChange的change
事件,因此答案只侦听这两个事件。
@DominicTobias我尝试了此操作,但需要在页面中的某个位置进行实际单击才能使此工作
现在,在这个问题上总共已经苦苦挣扎了大约一天。 我绝对可以列出在桌面版Chrome 67和React 15.6.0中不起作用的内容:
onAnimationStart
和input:-webkit-autofill
https://medium.com/@brunn/detecting -autofilled-fields-in-javascript-aed598d25da7-过早触发(表单尚未填写)this.inputRef.addEventListener("transitionend", this.doSomething, false)
与input:-webkit-autofill
css转换结合使用-按时触发,但您无法唤醒页面,如@Pixelatex所述this.inputRef.addEventListener("change", this.doSomething)
-甚至在您单击页面后才会触发onBlur={this.doSomething}
-不触发事件同样,不幸的是,这些解决方案不会起作用。 除非您戳页面,否则HTML不包含自动填充的值。 最接近的是2,因为您可以在控制台中键入document
,它将唤醒页面,到目前为止,以编程方式,此操作无效。
@DominicTobias您的解决方案可在桌面Chrome上运行吗?
实际上,我有一个肮脏的技巧。 如果您使用上一条注释中的解决方案2,则可以依靠[这里是肮脏的东西]“保存的表单数据是有效数据”。 然后,您可以在自动填充完成事件之后捕获过渡,并启用一个Submit按钮。 这是如何做:
CSS:
input:-webkit-autofill {
transition: background-color 0.1s ease-in-out 0s;
}
在构造函数中:
this.autofillCompleted = this.autofillCompleted.bind(this)
在您的React Component类中:
componentDidMount(){
if(this.myInputRef)
this.myInputRef.addEventListener("transitionend", this.autofillCompleted, false)
}
autofillCompleted(){
this.setState({ submitActive: true });
}
componentWillUnmount(){
if(this.myInputRef)
this.myInputRef.removeEventListener("transitionend", this.autofillCompleted, false)
}
JSX内部:
<FormControl
inputRef={(node) => this.myInputRef= node}
/>
PS适用于基本组件(例如input
),请使用ref
prop代替inputRef
在最新的Chrome桌面和iOS 12 Safari中,在<form>
中包装元素确实会导致自动完成功能发出onChange事件。
@rxb包装在<p> </p>
?
@basarat对不起,忘记了我的代码标记,标签消失了... <form>
标签
关于此问题有任何更新吗?
关于此问题有任何更新吗?
如果有更新,那么他们将在这个问题上。
如果您没有任何要添加的内容,请不要发布-您正在向订阅此问题的所有人发送垃圾邮件。 谢谢。
我对此也提出了一个问题,开发人员确信它将在65中得到修复... https://bugs.chromium.org/p/chromium/issues/detail?id=813175
不幸的是,此修复未与React团队协调。 我们不知道iOS上的Chrome现在设置了一个属性,该属性在过去的版本中偶然触发了更改处理程序。 我们并非故意支持这一点-我们已经进行了更改以消除该行为(我们不知道Chrome开始依赖它了)。
如果您正在使用浏览器并添加一个特定于React的黑客,请确保与React团队中的某人进行交流。
任何人都可以将其归结为当前的错误。 React处理输入的change
和input
事件。 如果自动填充功能触发了这两种情况,那么它应该起作用。 因此,尚不清楚此处的原始问题是否仍然有意义。 或者这里有些事情可能是不同的问题
我在这里有什么想念的吗?有人知道哪些浏览器可以正常工作吗?
顺便说一句,我们希望将其视为#9657的一部分-理想情况下,我们所做的任何事情都应在帮助解决此问题的服务中得到部分体现。
好的,我也做了一些研究:
我认为这里有两个问题:
这是您可以用来测试的网站: https :
据我所知,所有其他平台和浏览器都能很好地选择自动填充的值
请注意,上面是gatsby页面,因此_also_演示了SSR问题
@nhunzaker您对IOS镀铬保护壳有聪明的主意吗? 看起来也像Vue一样https://github.com/vuejs/vue/issues/7058
React不会渲染自动完成功能
我已经针对iOS上的Chrome提交了一个新的Chrome Bug: https :
您是否尝试为输入定义'name'属性? 这个对我有用。 onChange在用户自动填充时触发
@eatsjobs我们使用attr名称,但存在相同的问题。
我测试了
$$(':-webkit-autofill')
适用于chrome 70,返回自动填充的输入。
@QuantumInformation对我一样:(
handleOnChange = e => {
this.setState({ email: e.target.value }, () => {
alert(this.state.email)
})
}
<form>
<input
name="email"
type="email"
placeholder="Enter Your Email"
autocomplete="email"
value={this.state.email}
onChange={e => this.handleOnChange(e)}
/>
</form>
我这样尝试,看起来一切正常。
自动填充会正确设置我的状态。 (iOS 12)
对于最近遇到此问题的用户,这是由浏览器有意造成的,以避免安全风险。
如果我们能够在页面加载后访问自动填充的值,那么编写恶意代码以提取旨在用于网络钓鱼的表单中的信息的恶意代码将变得非常容易。 给用户没有机会做出反应。 autocomplete="off"
被浏览器忽略的部分原因。
为了克服这个问题,我们需要:
为了解决此问题,请回想一下表单最初是如何设计和打算使用的。 当用户单击<button type="submit" />
内的<form>
,基本上是说“嘿,此操作是用户想要的,现在让我们评估表单值”。
考虑一下用React编写的一个非常简单的SignInForm的示例:
import React from 'react';
class SignInForm extends React.Component {
constructor() {
this.state = {
email: '',
password: '',
};
this.handleEmail = this.handleEmail.bind(this);
this.handlePassword = this.handlePassword.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleEmail(event) {
this.setState({ email: event.target.value });
}
handlePassword(event) {
this.setState({ password: event.target.value });
}
handleSubmit() {
console.log(this.state.email); // The email value
console.log(this.state.password); // The password value
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
name="email"
type="text"
value={this.state.email}
onChange={this.handleEmail}
placeholder="Email"
/>
<input
name="password"
type="text"
value={this.state.password}
onChange={this.handlePassword}
placeholder="Password"
/>
<button type="submit" onClick={this.handleSubmit}>Sign In</button>
</form>
);
}
}
export default SignInForm;
提交后,表单将相应地更新和评估输入字段。
这表示:
我认为,这是最实用的方法,可以节省很多麻烦。 我希望这会在将来对其他人有所帮助。
编辑:对于那些不熟悉React的人,您可以看一下此链接,以获取表单的基本实现以及一些其他有用的信息: https :
对于最近遇到此问题的用户,这是由浏览器有意造成的,以避免安全风险。
如果我们能够在页面加载后访问自动填充的值,那么编写恶意代码以提取旨在用于网络钓鱼的表单中的信息的恶意代码将变得非常容易。 给用户没有机会做出反应。
autocomplete="off"
被浏览器忽略的部分原因。为了克服这个问题,我们需要:
- 接受以下事实:当DOM节点挂载时,我们将(永远不会)访问自动填充的值
- 拥抱浏览器带来的安全问题
为了解决此问题,请回想一下表单最初是如何设计和打算使用的。 当用户单击
<button type="submit" />
内的<form>
,基本上是说“嘿,此操作是用户想要的,现在让我们评估表单值”。考虑一下用React编写的一个非常简单的SignInForm的示例:
import React from 'react'; class SignInForm extends React.Component { constructor() { this.state = { email: '', password: '', }; this.handleEmail = this.handleEmail.bind(this); this.handlePassword = this.handlePassword.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleEmail(event) { this.setState({ email: event.target.value }); } handlePassword(event) { this.setState({ password: event.target.value }); } handleSubmit() { console.log(this.state.email); // The email value console.log(this.state.password); // The password value } render() { return ( <form onSubmit={this.handleSubmit}> <input name="email" type="text" value={this.state.email} onChange={this.handleEmail} placeholder="Email" /> <input name="password" type="text" value={this.state.password} onChange={this.handlePassword} placeholder="Password" /> <button type="submit" onClick={this.handleSubmit}>Sign In</button> </form> ); } } export default SignInForm;
提交后,表单将相应地更新和评估输入字段。
这表示:
- 我们根本无法禁用提交按钮
- 用户单击此按钮后,必须进行所有验证
我认为,这是最实用的方法,可以节省很多麻烦。 我希望这会在将来对其他人有所帮助。
编辑:对于那些不熟悉React的人,您可以看一下此链接,以获取表单的基本实现以及一些其他有用的信息: https :
感谢您的总结,但是我感到非常困惑。 您说我们提交表单时,它将“相应地更新”。 这是否意味着它将在触发提交事件之前为其自动填充的每个字段触发其他更改事件? 还是这意味着在触发Submit事件时,现在可以通过引用读取值了? 如果是前者,那么我们可以构建片段中显示的组件。 如果是后者,那么我们将需要采用基于ref的方法来前进表格。
@thomasjulianstoelen是什么意思?
@dwoodwardgb
以我的经验(至少使用chrome),它一直在更新用户第一次与页面进行交互时的字段(单击,表单提交等),并且一直在提交具有更改的事件,从而允许模型变量进行更新。 我还没有测试其他浏览器。
您可以设置autocomplete =“ off”属性(HTML5),或将输入值记录在url哈希中。
进一步研究该问题:Chromium进行了更改,以根据以下错误报告发送“更改”和“输入”本机事件: https : onChange
事件。 这可能与React的重复数据删除逻辑(https://github.com/facebook/react/issues/10135)或Chrome在iOS上以编程方式发出的事件带有isTrusted=false
标志有关。
React团队中的某人能否深入研究React onChange
事件处理程序,以弄清楚为什么未触发该事件? @gaearon或@zpao (随机猜测)?
同时,我正在使用onInput
事件,该事件直接侦听本地的“ input”事件。
我认为这是Chrome中的提交破坏了行为:
它从change事件中删除simulated
标志,这可能导致重复数据删除逻辑忽略这些事件。
@nfiacco的提交是从2018年开始的,此问题于2014年打开,所以从表面
我从2022年回来
最有用的评论
您是否尝试为输入定义'name'属性? 这个对我有用。 onChange在用户自动填充时触发