本教程适用于所有符合情况的第三方UI框架;
如果你想在Angular中使用Layui框架,想必已经发现Layui已经用div+css重写了select、radio、CheckBox等表单元素的样式,原元素被display="none"隐藏掉了。
那么问题来了,用户操作的是layui重写的元素视图上面,Angular的[(ngModel)]在原元素上,不能直接操作layui视图;
三者关系就出来了,理清三者中“值”的传递关系很重要:
Ng Model -> Ng View -> Layui View:当NG组件的数据被改变 -> 刷新NG视图(原元素) -> 渲染刷新layui视图
Layui View -> Ng view-> Ng Model:当Layui视图元素被改变值 -> NG视图被改变 -> 改变NG数据
从NM-NV-LV中,layui官网已经给出动态加载的数据需要用layui.form.render();来重新渲染layui视图;
在LV-NV-NM中,LV-NV这步没什么问题,问题在于LV之后的NV-NM这步!
问题:
LV把原视图更新了,但是NM数据却没有更新,但是如果你找到原视图的select进行操作(到浏览器控制台把display="none"注释掉就出来了),你发现LV到NV没问题,NV到NM没问题,但是LV->NV->NM不通!很显然,select触发change事件,通知Angular更新数据,但是LV到NV这个并没有触发change,所以到NV这里就断开了。
所以需要手动接通事件来传递:
Angular1.X解决方案:
利用jQuery的trigger模拟change事件
$('select').trigger('change');
Angular2.X解决方案:
用1.X的方式处理,好像并不能解决问题,依然无法触发2.X的change事件,这时候需要用到CustomEvent自定义事件来处理这个问题就比较简单了。
triggerChange(elem: any): void {
elem.dispatchEvent(
new CustomEvent('change', {
detail: {}, // 参数
bubbles: true // 是否冒泡
})
);
}
需要触发change事件的地方,调用一下这个triggerChange方法就可以了。
对于操作的监听放在组件生命周期ngAfterViewInit这个钩子中比较合理:
ngAfterViewInit() {
// 初始化layui视图
layui.form.render();
// 当数据改变->刷新ng视图->刷新layui视图,
$('select').on('change', (e: any) => {
layui.form.render(); // 监听select change事件(原来的change事件[原dom被layui隐藏] + 自定义的change事件)=> 刷新layui视图
});
// 当layui视图改变->ng视图被改变->改变数据
layui.form.on('select', (data) => {
this.triggerChange(data.elem); // 创建自定义change事件 => 触发NG数据更新
});
}
需要注意的是select是用change事件传递,但是Radio和CheckBox的事件是click事件来传递,其他的自己分析分析就知道是什么事件传递了,千万不要迷糊了!
其他问题
NM->NV->LV这个过程由于NM值地改变,NV需要时间渲染,所以需要用setTimeout来调整NV优先LV稍后的渲染顺序,最终才看得到Layui的效果。
setTimeout( () => {layui.form.render();},0);