【前端】JavaScript动态的改变input的value属性时,如何自动触发oninput、onchange事件?
如页面上有如下input:
<input type="text" id="demo"/>
给input加上事件:
var input = document.getElementById('demo');input.addEventListener('oninput', function(){
console.log('oninput event ');
}, false);
input.addEventListener('onchange', function(){
console.log('onchange event');
}, false);
现在我用JavaScript动态的设置input的值:
document.getElementById('demo').value = 'value change';
会发现oninput和onchange事件都没有自动触发,但输入框的值却已经变化了。如果想要触发事件,则必须手动触发才行。
要想设置value值得时候,自动触发一些事件有没有对应的解决办法呢?
回答
lerte 说的对,数据双向绑定,不过不用框架也行,只要知道原理;楼主的问题实际上是:
改变了一个对象的属性,怎么去自动触发一个程序,或者访问一个属性,怎么去自动触发一个程序
实际上,可以新建另一个访问器属性 _value ,把原来 js 对 value 的操作改为对 _value 属性的操作,这样访问 _value 时,会自动调用 get 函数获取 value 的值,设置 _value 属性时,会自动调用 set 函数设置 value 属性的值,你可以将你的程序绑定在 get/set 函数中,这样就可以监听 js 修改 value 数据的变化;
如果直接设置 value 属性为 访问器属性,结果会造成,用户在页面修改了 value,不会调用 set 函数,所以 想了上面的中介 _value,此处感谢@叫我小蓝就行了 的提醒。
题主的案例:
js:
window.onload = function() { let input = document.getElementById('demo');
function oninputCallback() {
console.log('oninput event ');
}
function onchangeCallback() {
console.log('onchange event');
}
input.addEventListener('oninput', oninputCallback, false);
input.addEventListener('onchange', onchangeCallback, false);
Object.defineProperty(input, '_value', {
configurable: true,
set: function(value) {
this.value = value;
oninputCallback();
onchangeCallback();
},
get: function() {
return this.value;
}
});
};
html:
<body> <input type="text" id="demo"/>
</body>
效果
再给个例子,根据数据类型的变化,自动修改类名,demo
js:
window.onload = function() {let bonusDiv = document.getElementById('bonusDiv');
Object.defineProperty(bonusDiv, 'data-type', {
configurable: true,
set: function(value) {
switch (value) {
case 'x1':
this.className = 'red';
break;
case 'x2':
this.className = 'blue';
break;
case 'x3':
this.className = 'purple';
break;
}
}
});
};
html:
<div id="bonusDiv" ></div>
效果:
【Stack Overflow】Event when input value is changed by JavaScript?
监听 js 动态 修改 input value 事件
function customInputSetter(){ var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
var originalSet = descriptor.set;
// define our own setter
descriptor.set = function(val) {
console.log("Value set", this, val);
originalSet.apply(this,arguments);
}
Object.defineProperty(HTMLInputElement.prototype, "value", descriptor);
}
customInputSetter();
方案2
Here is a solution to hook the value property changed for all inputs:
var valueDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");HTMLInputElement.prototype.addInputChangedByJsListener = function(cb) {
if(!this.hasOwnProperty("_inputChangedByJSListeners")) {
this._inputChangedByJSListeners = [];
}
this._inputChangedByJSListeners.push(cb);
}
Object.defineProperty(HTMLInputElement.prototype, "value", {
get: function() {
return valueDescriptor.get.apply(this, arguments);
},
set: function() {
var self = this;
valueDescriptor.set.apply(self, arguments);
if(this.hasOwnProperty("_inputChangedByJSListeners")){
this._inputChangedByJSListeners.forEach(function(cb) {
cb.apply(self);
})
}
}
});
//Usage example:
document.getElementById("myInput").addInputChangedByJsListener(function() {
console.log("Input changed to \"" + this.value + "\"");
});
方案3
/** * [changeValueListener 监听 js 修改 input 和 textarea 的 value。]
* @param {[HTMLElement]} element [具有 value 属性的 html 元素,如 input 和 textarea。]
* @param {Function} callback [回调,this 为 element,参数为当前值。]
* @return {[HTMLElement]} [element]
*/
function changeValueListener(element, callback) {
if (!Array.isArray(element.callbacks)) {
element.callbacks = [];
var valueDes = Object.getOwnPropertyDescriptor(element.constructor.prototype, "value");
Object.defineProperty(element, 'value', {
set: function(v) {
// console.log('set', v, this, arguments);
element.callbacks.forEach(function(callback) {
callback.call(this, v);
});
valueDes.set.apply(this, arguments);
},
get: function() {
// console.log('get', this, arguments);
return valueDes.get.apply(this, arguments);
}
});
}
element.callbacks.push(callback);
return element;
}
// 调用
var input = document.getElementById('foo');
changeValueListener(input, function(v) {
console.log('a callback', this, v);
});
// 支持绑定多个回调
changeValueListener(input, function(v) {
console.log('b callback', this, v);
});
我觉得数据双向绑定蛮好的,不过还有别的解决办法,可以用js的事件构造器,让js触发你想要的事件
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<input type="text" id="demo" />
<!-- Simulate click -->
<input type="button" onclick="changeValue();" value="点击我改变input值" />
<!-- Add a click handler that calls preventDefault -->
<input type="button" onclick="addHandler();" value="js触发input和change默认事件" />
<!-- Remove the click handler that calls preventDefault -->
<input type="button" onclick="removeHandler();" value="js取消触发input和change默认事件" />
<script>
var input = document.getElementById('demo');
input.addEventListener('input', function() {
console.log('oninput event ');
}, true);
input.addEventListener('change', function() {
console.log('onchange event');
}, false);
// 参考网站
// https://stackoverflow.com/questions/2490825/how-to-trigger-event-in-javascript
// https://developer.mozilla.org/zh-CN/docs/Web/Guide/Events/Creating_and_triggering_events
function changeValue() { //改变input的值函数
input.value = Math.random() * 10;
simulateEvent("demo", "change");
simulateEvent("demo", "input");
}
function simulateEvent(id, event) { //js触发事件--事件构造器
var evt = document.createEvent("Event");
evt.initEvent(event, true, true);
var cb = document.getElementById(id);
var canceled = !cb.dispatchEvent(evt);
if (canceled) {
// A handler called preventDefault
// console.log("canceled");
} else {
// None of the handlers called preventDefault
// console.log("not canceled");
}
}
function preventDef(event) {
event.preventDefault();
}
function addHandler() {
document.getElementById("demo").addEventListener("change", preventDef, false);
document.getElementById("demo").addEventListener("input", preventDef, false);
}
function removeHandler() {
document.getElementById("demo").removeEventListener("change", preventDef, false);
document.getElementById("demo").removeEventListener("input", preventDef, false);
}
</script>
</body>
</html>
js动态改变时,手动触发input事件
其实,仔细一想,要是JavaScript可以通过设置值来触发input事件,本身好像就不太合理。
因为当我打开一个页面的时候,页面中某一段js可以通过某种方法来触发需要用户手动触发的事件,也就是相当于在用户不知情的情况下,替用户做了某些操作(填写表单、填写密码),感觉不太安全。
onchange 只会在你离开(blur) input 的时候触发。你可以将回调函数抽取出来,在 JS 改变 input 时同时调用回调。或者用 oninput ,搭配 onpropertychange 可兼容 IE8 。
oninput 事件在value 改变时触发,是实时的,然而通过 js 改变 value 时,却不会触发。onpropertychange用js改变是可以触发的,单限于ie。可以封装一下
var input = document.getElementById('demo'); valuechange(input,function(){
input.value = 'value change';
return true;
},function(){
console.log('this input change');
});
function valuechange(obj,myevent,fn){
var ie = !!window.ActiveXObject;
if(ie){
if(myevent()){
obj.onpropertychange = fn;
}
}else{
if(myevent()){
fn();
}
}
}
你可以做一个定时器,设置一些标识变量,在定时器里面根据这些变量达到你的效果
var onchange = function(){
console.log('onchange event');
};
input.addEventListener('onchange', function(){
onchange();
}, false);
document.getElementById('demo').value = 'value change';
onchange();//你都用程序改值了,当然是用程序调用change啊
程序无法获取页面操作才有了事件监听,比如用户点击按钮如果没有监听点击事件,程序不知道用户是否点击按钮,于是用addEventListener监听。
如果程序知道操作干嘛要用事件监听多此一举??
用Vue或者其他框架,做数据双向绑定
$("#demo").trigger("oninput").trigger("onchange");
遇到同样的问题。楼主怎么解决的
你既然都是用js去操作input了,这些事件触发的处理(调用),你写到js后续操作中就完了,为什么还要想着触发事件?
可以将监听函数内部的操作作为一个函数,当改变input的值时,调用这个函数。
貌似被采纳的答案不支持在ie中运行 我在Stack Overflow上问过相同的问题。
以上是 【前端】JavaScript动态的改变input的value属性时,如何自动触发oninput、onchange事件? 的全部内容, 来源链接: utcz.com/a/79805.html