事件处理

本主题已经彻底取消了传统的基于回调参数的事件处理方法,全部改成基于 DOM 原生事件或 DOM 自定义事件的处理方式。

原生事件

Edge主题更进一步,彻底降低了 UI 组件的存在感,也就是开发者在进行交互开发的时候,只需要按照原生的 HTML 控件元素开发即可。

其实现的底层逻辑在于,当 LuLu UI 创建的组件在发生交互的时候,会触发原始 HTML 控件元素的原生事件,最具有代表性的就是 'change' 事件,部分 UI 组件还支持 'input' 事件。

<select> 下拉框元素具体,在实际开发的时候,我们无需关心下拉框组件的初始化以及交互逻辑判断,只需要把对应的 <select> 元素写在页面中就可以了,就像下面这样:

<select is="ui-select">
    <option value="1">选项1</option>
    <option value="2">选项2</option>
</select>

开发者无需再做任何其他事情,就当 LuLu UI 组件不存在正常开发就好了。

比方说用户选择了某个选项,想要进行处理,则使用原生的 'change' 事件就好了,语法也是原生的 DOM 事件处理语法,例如:

select.addEventListener('change', function () {
    // 下拉框选择了
});

无论是 Color 颜色选择组件、Datetime时间选择组件、Range范围选择组件还是Datalist数据列表组件,都是一样的处理。

自定义事件

Edge主题支持若干固定的自定义事件,包括 'show''hide''select''success'等事件,具体参见下表:

组件名 自定义事件 说明
Select下拉框 - -
Range范围选择 - -
Color颜色选择 'show'、'hide' 颜色选择面板显示和隐藏的时候触发。
Datetime日期选择 'show'、'hide' 日期选择面板显示和隐藏的时候触发。
Datalist数据列表 'show'、'hide'、'select' select 事件发生于列表内容选择后。
Dialog弹框 'show'、'hide'、'close'、'remove' show 事件在弹框显示的时候触发,hide 事件在弹框隐藏的时候触发,close 事件在弹框关闭的时候触发,remove 事件在弹框移除的时候触发。

其中,hide 事件和 close 事件的区别在于,当执行 hide() 方法的时候会连同 close 事件一同触发,但是执行 close() 方法的时候只会触发 close 事件。

Tip提示 'show'、'hide' 提示信息显示和隐藏的时候触发。
ErrorTip出错提示 'show'、'hide' 出错提示信息显示和隐藏的时候触发。
LightTip轻提示 - -
Pagination分页 'change' 选择不同分页数量的时候触发 change 事件。
Drop下拉 'show'、'hide'
'select'
'ensure'、'cancel'
select 事件是 Drop 下拉扩展的 list() 列表方法专有;
ensure 和 cancel 事件是 Drop 下拉扩展的 panel() 轻面板方法才会触发,只有当 target 对象是 <dialog> 元素的时候才会执行。
Tab切换 'show'、'hide'、'switch' 无论选项卡按钮激活或失活都会触发 switch 事件。
Validate表单验证 'valid' 表单元素全部验证通过时候触发 valid 事件。
Table列表 'show'、'check' show 事件是列表内容显示的时候触发,check 事件是列表中的复选框(如果有)选中的时候触发。
Form表单 'success'、'error'、'complete' success 事件在表单请求提交成功后触发,error 是失败后触发,complete 事件在请求完成后触发,无论成功还是失败。

同一个元素可能会同时应用多个 UI 组件,这就会带来同一种类型的事件互相冲突的问题,例如一个输入框即是日期选择框,又参与了出错验证,此时,日期选择框出现和出错提示出现都会触发 show 事件,可能会对业务开发带来困扰,此时可以根据 event.detail.type 判断 show 事件是哪个组件触发的。

例如:

点击日期选择框,或者点击“验证”按钮,控制台就会看到对应组件类型的提示,相关测试代码如下所示:

<input type="date" id="date" is="ui-datetime">
<button type="primary" id="valid" is="ui-button">验证</button>
valid.addEventListener('click', function () {
    date.errorTip('测试提示信息');
});
date.addEventListener('show', function (event) {
    console.log(`显示的 UI 组件类型是 ${event.detail.type}`);
});

生命周期事件

几乎所有的 UI 组件都提供了 'connected' 和 'DOMContentLoaded' 这两个生命周期事件,具体的含义见下表。

事件类型 描述
connected connected 事件在 UI 组件和文档上下文发生接触的时候触发
DOMContentLoaded DOMContentLoaded 事件在 UI 组件的 DOM 结构在页面中初始化完毕触发

举个例子,<ui-pagination> 是个自定义元素,当我们使用 JavaScript 创建一个 <ui-pagination> 元素的时候,上面两个生命周期事件均不会触发。

// 不会触发声明周期事件
let p = document.createElement('ui-pagination')

但是如果将对象 p 附加在页面中,此时,就会触发 connected 事件,表示元素和页面发生了连接。

// 触发 connected 事件
document.body.append('p');

那 DOMContentLoaded 事件什么时候触发呢?

<ui-pagination> 分页完整的 DOM 结构创建之后触发。

为什么需要生命周期事件?

因为有时候我们需要一进入页面就对 UI 组件元素进行某些属性修改,如果此时 UI 组件元素还只是普通的 DOM 元素,则进行的这些属性修改可能无法触发对应的变化。

举个例子,页面中直出了一个 <ui-pagination id="p2"> 元素,如果此时 Pagination.js 还未加载完毕就设置 p2.total = 100 是无效的,因为此时 <ui-pagination> 元素还未注册,组件内置的属性和功能尚未挂载。

有了生命周期事件,则就不需要担心加载的时机问题,直接在 connected 事件中设置就可以了,示意:

p2.addEventListener('connected', function (event) {
    // 分页总数就会变化
    this.total = 100;
});

对于内置自定义元素,Safari浏览器是不支持的,需要引入一段 Polyfill 代码,但是这段代码的执行是滞后的,会导致内置自定义元素注册的时机比 Chrome 浏览器靠后,所带来的后果就是 Chrome 浏览器下正常运行的代码在 Safari 浏览器下出现的报错。

原因就在于代码执行的时机出了问题,可以在 connected 事件或 DOMContentLoaded 事件中执行相关的代码,可以让 Safari 浏览器也能正常执行。

另外补充一点,如果生命周期事件在组件已经完成注册后再设置,是不会触发的,就好比浏览器原生的 DOMContentLoaded 事件,如果页面已经完全加载完毕,你再去绑定, DOMContentLoaded 事件并不会触发。

我们可以使用自定义元素上暴露的 isConnectedCallback 属性判断自定义元素是否已经完成注册。

// 如果已经完成注册,直接设置
// 否则,设置生命周期函数,在注册完成后执行设置
if (p2.isConnectedCallback) {
    p2.total = 100;
} else {
    p2.addEventListener('connected', function (event) {
        this.total = 100;
    });
}

其他判定是否完成注册的方法

对于自定义元素,我们可以使用 :defined 伪类判断组件是否完成初始化。

例如:

<ui-drop id="d0">下拉</ui-drop>
console.log(d0.matches(':defined'));
// 如果返回 true 说明完成了注册,
// 如果返回 false,则说明组件没有完成注册

对于内置自定义元素,非 Safari 浏览器也可以使用 :defined 伪类判断。

对于自定义属性元素,:defined 则无效,无法作为判断依据,此时可以根据元素上的 [defined] 属性继续进行判断。

本页贡献者:

zhangxinxu