如何在javascript中稳健地检测复选框值更改

时间:2014-07-01 06:50:10

标签: javascript dom browser checkbox

我想知道如何检测html复选框输入的更改,即使它以编程方式更改,如下所示:

checkboxDomNode.checked = true

浏览器显然知道它已更改,因为它获得了可视化的标记,并且任何:checked css伪类都被触发。我实际上是试图在javascript中模拟:checked css伪类,这就是为什么我要找到一种强有力的方法来实现这一点。

我已经测试了“更改”事件,并且不会像上面那样在程序化更改中触发。它看起来像MutationObserver不支持对该属性所做的更改。

3 个答案:

答案 0 :(得分:1)

Alan Darmasaputra答案的一个小扩展:您可以为每个更改执行两个任务,而不是为您的复选框使用简单的对象包装器,并为您的属性使用getter和setter:

var checkboxObject = {
    node: document.querySelector('input[type=checkbox]'), // or whatever query you wish to perform
    get checked() {
        return this.node.checked;
    },
    set checked(value) {
        var oldValue = this.node.checked;
        this.node.checked = !!value;
        if(oldValue !== !!value) {
            this.node.dispatchEvent(new Event("change"));
        }
    }
};

checkboxObject.node.addEventListener('change',function(event){
    //do something
});

// calls checkboxObject[get checked]
var state = checkboxObject.checked;

// calls checkboxObject[set checked] with argument 'false'
checkboxObject.checked = false;

正如您所看到的,这需要一些初始配置,但是您可以以编程方式更改已检查状态,并在一个分配中分派事件。

更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set

工作小提琴:



var checkboxObject = {
  node: document.querySelector('input[type=checkbox]'), // or whatever query you wish to perform
  get checked() {
    return this.node.checked;
  },
  set checked(value) {
    var oldValue = this.node.checked;
    this.node.checked = !!value;
    if(oldValue !== !!value) {
      this.node.dispatchEvent(new Event("change"));
    }
  }
};

document.getElementById('check').addEventListener('click', function() {
  checkboxObject.checked = true;
});

document.getElementById('uncheck').addEventListener('click', function() {
  checkboxObject.checked = false;
});

checkboxObject.node.addEventListener('change',function(event){
  document.getElementById('log').innerText += 'checkbox value changed! New value: ' + event.target.checked + '\n';
});


// Why implementing this directly on the checkbox element is not a good idea:
console.log( Object.getOwnPropertyDescriptor( Object.getPrototypeOf(checkboxObject.node), 'checked' ));

<button id="check">check</button>
<button id="uncheck">uncheck</button>

<input type="checkbox">

<div id="log" style="white-space: pre-line"></div>
&#13;
&#13;
&#13;

**编辑:**

直接在checkbox元素上实现此行为不是一个好主意。使用Object.getOwnPropertyDescriptor,我们可以检查属性的类型(accessor descriptordata descriptor)。如果我们对checkboxObject.node的原型的checked属性执行此操作,如下所示:

console.log( Object.getOwnPropertyDescriptor( Object.getPrototypeOf(checkboxObject.node), 'checked' ));

输出将是:

{
  "get": function () { [native code] },
  "set": function () { [native code] },
  "enumerable": true,
  "configurable": true
}

这意味着该元素已经在其原型中为属性checked定义了一个getter和setter。你可以在Object.getPrototypeOf()你的复选框中实现逻辑,并明确地调用它上面的setter来调用本机行为,但这会让事情很难真正理解,特别是因为你必须将上下文绑定为该调用的checkbox元素。我会让你做出决定。

还要记住,现有的(原型)描述符可能是不可写的(在这种情况下它不是,否则它将在上面的输出中),这意味着覆盖这个的正常属性赋值将失败。在这种情况下,您必须直接在复选框元素上Object.defineProperty(),以确保您实际上并未尝试覆盖不可变的原型设置者/获取者。

答案 1 :(得分:0)

为什么不使用 AngularJS KnockoutJS 等任何java脚本框架尝试双向绑定。您也可以使用纯javaScript来完成它。

看看这篇文章,

http://www.lucaongaro.eu/blog/2012/12/02/easy-two-way-data-binding-in-javascript/

使用 AngularJS

的简单示例

HTML:

<div ng-controller="checkCtrl">
    Check It : <input type="checkbox" id="chkbox" ng-model="checked" />
    <p ng-model="checked">{{checked}}</p>
</div>

AngularJS:

var testApp = angular.module("testApp", []);

testApp.controller("checkCtrl", function($scope){
    $scope.checked = true;
});

jsFiddle

答案 2 :(得分:0)

以编程方式修改的属性不会触发事件。您可以尝试添加onchange侦听器

checkboxDomNode.addEventListener('change',function(event){
 //do something
})

然后在修改您的属性后,触发事件

checkboxDomNode.dispatchEvent(new Event("change"))

在Chrome 53上测试