【前端】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>

效果

【前端】JavaScript动态的改变input的value属性时,如何自动触发oninput、onchange事件?

再给个例子,根据数据类型的变化,自动修改类名,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>

效果:

【前端】JavaScript动态的改变input的value属性时,如何自动触发oninput、onchange事件?

【Stack Overflow】Event when input value is changed by JavaScript?

监听 js 动态 修改 input value 事件

方案1

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

回到顶部