扩展 HTML 原生标签(下)

扩展 HTML 原生标签(下)

上一节请到如何通过Object.defineProperty为标签定义新的属性和重写现有的属性,这一节我们聊一下如何为标签添加方法和事件。

标签的方法

文章开头已经提到过使用原型属性来为标签增加一个方法。下面事件为 A 标签增加了一个jump方法。

HTMLAnchorElement.prototype.jump = function() {
    window.location.href = this.href;
}

定义完成后可以 在 Javascript 可以直接调用jump方法。

<a id="QrossLink" href="http://www.qross.cn">星源数软</a>
<script type="text/javascript">
document.querySelector('#QrossLink').jump();
</script>

如果想为每一个标签增加同一个方法,可以在HTMLElement上定义。

HTMLElement.prototype.getNodeName = function() {
    return this.nodeName;
}

虽然也可以在 Object 对象上定义,但是非常非常不建议这么做。

Object.prototype.getNodeName = function() {
    return this.nodeName;
}

这会让所有的数据类型都有了getNodeName这个方法。

标签的事件

我们已经知道了如何定义扩展属性和扩展方法,最后我们来看一下事件如何定义。事件则是属性和事件的结合体,从本质上讲,事件是一种属性,但其数据类型是函数,跟方法相同。但其执行由特定的交互行为触发,而不是主动执行。我们以onclick事件为例,解释一下事件的定义和执行过程。

首先我们为一个 DIV 标签定义一个onclick事件。

<!--方法一-->
<div id="Test" onclick="alert('Hello World!')"></div>
<script type="text/javascript">
//方法二
document.querySelector('#Test').onclick = functino(ev) {
    alert('Hello World!');
}
//方法三
document.querySelector('#Test').addEventListener('click', function(ev) {
    alert('Hello World!');
});
</script>

定义事件可以有以上三种方法:方法一在元素属性上定义,我们甚至可以通过setAttribute('onclick', "alert('Hello World!')")定义。方法二支持通过给onclick赋值来定义,不值类型必须是函数,而不能是字符串。第一种方法和第二种方法都会指定onclick“属性”,所有赋值后会互相覆盖。这么看事件好像真是一个属性。方法三是为元素添加事件监听,可以添加多次,添加的事件与onclick“属性”互相独立,不会冲突。

定义完成后,我们用鼠标点击这个 DIV 所在的区域,则会执行这个事件。也可以调用document.querySelector('#Test').click()方法来执行。这样看,onclick事件即是当执行click方法时要执行的逻辑。

因为事件本身就是自定义的逻辑,而且同一个事件还可以通过事件监听添加多次。所以下面就介绍一下如何定义自己的事件,以复选框为例,我们为事件添加两个方法onchange-checkedonchange-unchecked,即定义当复选框选中时和当复选框取消选中时触发的事件。

第一步,向定义属性或方法一样:

HTMLInputElement.prototype['onchange-checked'] = null;
HTMLInputElement.prototype['onchange-unchecked'] = null;

因为事件名称中间有中横线-也就是减号,所有不能直接用点规则写在原型上.prototype.onchange-checked = null

第二步,编写元素属性上的处理逻辑,也就是上面第一种方法的解析:

this['onchange-checked'] = this.getAttribute('onchange-checked');
this['onchange-unchecked'] = this.getAttribute('onchange-unchecked');

上面介绍的第二种方法不用管,本身完成第一步之后,元素就可以接受属性的直接赋值。比如:

document.querySelector('#CheckBox1')['onchange-checked'] = function(ev) { ... }
document.querySelector('#CheckBox1')['onchange-unchecked'] = function(ev) { ... }

第三步,事件的执行逻辑,就是如何执行已经定义的事件。根据上面两步,事件的值可以是字符串或函数,那么我们就得有执行字符串或函数的处理方法。以下是实现代码:

HTMLInputElement.prototype.execute = function(eventName, ...args) {
    let logic = this[eventName];
    if (logic != null) {
        if (typeof (logic) == 'function') {
            logic.call(this, ...args);
        }
        else if (typeof (logic) == 'string') {
            eval('_ = function() {' + logic + '}').call(this, ...args);
        }
    }
}

第四步,事件的触发逻辑,就是什么时候执行这个自定义事件。这个需要在绑定在原生事件上添加逻辑进行处理。以下是实现代码:

document.querySelector('#CheckBox1').addEventListener('change', function(ev) {
    if (this.checked) {
        this.execute('onchange-checked', ev);
    }
    else {
        this.execute('onchange-unchecked', ev);
    }
});

完整的代码如下:

<!--示便-->
<input id="CheckBox1" type="checkbox" onchange-checked="alert('Hello')" onchange-unchecked="alert('World')" />

<script type="text/javascript">
HTMLInputElement.prototype['onchange-checked'] = null;
HTMLInputElement.prototype['onchange-unchecked'] = null;

HTMLInputElement.prototype.execute = function(eventName, ...args) {
    let logic = this[eventName];
    if (logic != null) {
        if (typeof (logic) == 'function') {
            logic.call(this, ...args);
        }
        else if (typeof (logic) == 'string') {
            eval('_ = function() {' + logic + '}').call(this, ...args);
        }
    }
}

document.querySelectorAll('input[type=checkbox]').forEach(checkbox => {
    checkbox['onchange-checked'] = checkbox.getAttribute('onchange-checked');
    checkbox['onchange-unchecked'] = checkbox.getAttribute('onchange-unchecked');
    checkbox.addEventListener('change', function(ev) {
        if (this.checked) {
            this.execute('onchange-checked', ev);
        }
        else {
            this.execute('onchange-unchecked', ev);
        }
    });
});
</script>

至此,关于如何扩展原生标签的属性、方法和事件已经全部介绍完,下一期会介绍一下如何创建自己的 HTML 标签。

上述的自定义事件其实原生 Javascript 也有相应的接口,请参考 HTML 标签自定义事件

原文链接:http://www.qross.cn/blog/20210807

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值