安装与调用
如果是基本弹框功能,直接引用下面CSS和JS即可:
<link rel="stylesheet" href="https://qidian.gtimg.com/lulu/hope/ui/Dialog/index.css">
<script type="module" src="https://qidian.gtimg.com/lulu/hope/ui/Dialog/index.js"></script>
或者:
<script type="module"> import Dialog from "https://qidian.gtimg.com/lulu/edge/js/common/ui/Dialog.js"; </script>
如果需要用到 Alert 或者 Confirm 弹框,则还需要引入 Button/index.css:
<link rel="stylesheet" href="https://qidian.gtimg.com/lulu/hope/ui/Button/index.css">
如果需要用到 Loading 弹框,则还需要引入 Loading/index.css:
<link rel="stylesheet" href="https://qidian.gtimg.com/lulu/hope/ui/Loading/index.css">
概要
Hope 主题和 Edge 主题中的 Dialog 组件实现原理类似,可以理解为对 HTML5 原生的 <dialog>
元素进行的扩展,有别于 peak、pure 主题中原型组件。
目前 Firefox 97- 浏览器和 Safari 15.4- 浏览器并不支持 <dialog>
元素,本组件进行了简易的 Ployfill,可以满足常规的弹框需求。
本 Dialog 组件的所有功能都是围绕 <dialog>
元素的属性和方法展开的,使用的时候需要给 <dialog>
元素添加 is="ui-dialog"
,否则还是原始样式的 <dialog>
元素。
例如:
<dialog id="dialog" is="ui-dialog"></dialog>
此时,设置该<dialog>
元素的open
属性值为true
,就可以显示弹框。
button.addEventListener('click', function () { dialog.open = true; });
不过实际开发通常不会这么使用,因为在移动端,结构提前预置的弹出式交互多使用 Popup 弹出层实现,Dialog 弹框更多的是模拟原生的 alert
和 confirm
效果,而这两个交互效果的执行普遍出现在 JS 业务逻辑代码中,因此,Dialog 组件更常见的是使用 JS ,也就是 Dialog 类进行构建。
Dialog 类使用指南
Dialog 类本质是对原生 <dialog>
元素的常用功能进行了封装,这样大家不必关心具体的细节,专注于API 本身。
1. 起步
打开控制台,输入并执行下面这行 JS:
new Dialog()
页面就会显示一个空弹框,并且返回当前 <dialog>
元素。
因此下面代码中的 eleDialog
本质上就是 <dialog>
元素,<dialog>
元素所有的属性和方法都可以直接使用。
const eleDialog = new Dialog()
例如 <dialog>
元素扩展的 alert()
方法就可以使用:
const eleDialog = new Dialog(); eleDialog.alert('我是提示内容');
当然,也可以级联使用:
new Dialog().alert('我是提示内容');
下面通过多个案例演示 Dialog 类的不同使用场景。
2. alert 信息提示框
new Dialog().alert('操作成功!', { type: 'success' });
我们可以type
参数指定提示的类型,除了这里使用的 'success'
类型,其他内置类型还有:'remind'
提示,'danger'
警示。
也可以使用自定义的类型,例如:
new Dialog().alert('自定义提示,有标题,无图标。', { title: '系统提醒', type: 'custom' });
3. confirm 确认提示框
const content = `<h6>您确定要停用所选的成员吗?</h6> <p>成员停用后,可以在停用成员列表中重新启用。</p>`; new Dialog().confirm(content, { buttons: [{}, { value: '停用', events: function (event) { // 按钮禁用 button.disabled = true; // event.dialog 是当前实例对象 event.dialog.remove(); } }] });
同时示意了通过使用 buttons
参数指定按钮的文案、类型以及事件。
4. 普通的内容弹框
new Dialog({ title: '普通文本框', content: '我是一段HTML,啦啦啦啦啦', buttons: [{ value: '知道啦!', type: 'remind' }] });
5. 高度拉伸弹框
通过设置参数height
的值为'stretch'
实现。最大支持高度为1000px
,此值通过CSS进行修改。如果浏览器高度小于1000px
,弹框高度会自动上下拉伸适配。
new Dialog({ title: '中间高度自适应的容器', height: 'stretch', content: `<div class="bg-white p20">${Array(60).fill().map((_, index) => { return `<img src="${index}.gif" class="db mt10">`; }).join('')}</div>`, buttons: [{}] });
6. loading 弹框
new Dialog().loading();
有时候,弹框内容是 Ajax 动态请求的,此时在 Ajax 成功之前是需要一个加载状态的。
体验更好的做法是根据最终呈现布局,局部动态 loading,但是有时候我们想要偷懒,不想再写一个 loading 布局,则就可以使用这里的 loading 弹框。例如下面这个示意:
const eleDialog = new Dialog({ width: 288 }).loading(); // ajax请求模拟 fetch(location.href).then(res => res.text()).then(text => { eleDialog.setParams({ title: '请求内容', buttons: [{}], content: text.replace(/[\w\W]+<pre>([\w\W]+?)<\/pre>[\w\W]+/, '$1') }); });
这里使用 setParams 方法传参,让 loading 弹框替换成内容弹框。
7. 弹框打开 DOM 元素
<p id="t0" class="dn">
下拉:<select style="width:150px;padding:.5rem;">
<option>选项1</option>
<option>选项2</option>
</select>
</p>
button.addEventListener('click', function () {
// 如果弹框已创建,就直接显示
if (this.dialog) {
this.dialog.show();
} else {
this.dialog = new Dialog({
title: 'DOM载入测试',
content: t0,
buttons: [{}, {}]
});
}
});
下拉:
本例中,也可以直接使用 ID 选择器作为 content
参数值,例如:
new Dialog({ title: 'DOM载入测试', content: '#t0', buttons: [{}, {}] });
接下来深入介绍下弹框组件的实现原理、语法和参数等。
弹框的显示、隐藏
弹框显示有3种方法,分别是:
- dialog.open = true;
- dialog.setAttribute('open', '');
- dialog.show(); // 推荐,自定义若干细节
弹框隐藏有4种方法,分别是:
- dialog.open = false;
- dialog.removeAttribute('open');
- dialog.close();
- dialog.hide(); // 非原生方法
显示和隐藏测试
弹框的创建
实际开发,弹框元素往往并不是在页面中的,需要 JS 创建,此时按照普通的 DOM 元素创建使用就可以了。
这里列举 3 个不同的弹框创建案例:
1. DOM 创建
let dialog = document.createElement('dialog'); dialog.setAttribute('is', 'ui-dialog'); dialog.addEventListener('DOMContentLoaded', function () { this.alert('Hello, LuLu UI!'); }); document.body.appendChild(dialog);
2. HTML 字符串创建
document.body.insertAdjacentHTML('beforeend', '<dialog id="dia" is="ui-dialog"></dialog>'); dia.addEventListener('DOMContentLoaded', function () { this.alert('Hello, LuLu UI!'); });
3. Dialog 类创建
new Dialog().alert('Hello, LuLu UI!');
Dialog 对象隐藏了创建的细节,是更推荐的元素创建方法,详见“Dialog 类使用指南”。
弹框的删除
弹框删除可以使用下面的方法:
- dialog.remove();
测试:
比方说下面这个例子:
new Dialog({ content: '<button onclick="this.closest(\'dialog\').remove()">删除弹框</button>' });
如果弹框内容以字符串形式设置,则弹框关闭默认执行的就是删除操作,而不是隐藏。
弹框内容设置
如果需要让弹框显示对应的内容,则有下面这些方法:
1. 直接显示
需要显示的内容内容直接放在 <dialog>
元素中,例如:
<dialog id="dialog2" is="ui-dialog" title="我是标题">Hello, LuLu UI!</dialog>
此时弹框直接显示已有内容,例如:
dialog2.show();
其中,<dialog>
元素上的 title
属性值会作为弹框的标题显示。
此 title
属性是一次性的,也就是后期再使用 dialog.title
修改 title
属性是无效的,请使用 dialog.params.title
进行标题的修改。
2. params 参数传递
本弹框组件的参数传递底层使用的是 dialog.params
对象,因此,对于弹框内容,可以通过 dialog.params.content
进行设置。例如:
<dialog id="dialog3" is="ui-dialog"></dialog>
dialog3.params.content = 'Hello, LuLu UI!'; dialog3.show();
如果希望弹框关闭后还能继续显示当前弹框,需要使用节点对象作为弹框内容。例如本例中需要把文字转为文本节点使用:
button3.addEventListener('click', function () { dialog3.params.content = document.createTextNode('Hello, LuLu UI!'); dialog3.show(); });
3. 直接在 <dialog> 元素上设置
<dialog>
元素扩展了一个可读写的 content
属性,可以用来直接改变弹框内容。
<dialog id="dialog3" is="ui-dialog"></dialog>
button4.addEventListener('click', function () { dialog4.show().content = document.createTextNode('Hello, LuLu UI!'); });
这里的dialog4.show()
返回的是弹框元素自身,因此可以级联使用。原生弹框的show()方法返回的是undefined
,不支持dialog4.show().content
这种用法。
4. Dialog 类设置内容
如果使用 Dialog 类创建弹框,则弹框的内容推荐使用 content
参数进行传递,例如:
new Dialog({ content: '#someId' });
会自动把页面上id
为'someId'
的元素作为内容显示在弹框中。
语法和参数
Dialog 类的基础语法
基本的弹框使用方法为:
const eleDialog = new Dialog(options);
其中:
- options
options
是可选参数,支持的参数见下表:
参数名称 | 支持类型 | 默认值 | 释义 |
---|---|---|---|
title | String | '' | 表示弹框的标题。 |
content | String Object Function |
'' | 表示弹框显示的主体内容。可以是 HTML 字符串,或者是 DOM 对象,也可以是返回 HTML 字符串或 DOM 对象的函数。参数类型不同,弹框关闭的方法也不一样,DOM 对象关闭执行 hide() 方法,HTML 内容执行 remove() 方法。 |
buttons | Array | [] | 弹框的按钮元素。默认是空数组,表示没有按钮。每个按钮为一个 {} 对象,含一些可选参数,具体释义参见这里。
|
width | String Number |
'auto' | 标题弹框的主体宽度。可以是纯数值,会按照像素单位处理;也支持其他任意单位,例如 默认值是 |
height | String Number |
'auto' | 标题弹框的主体高度。可以是纯数值,会按照像素单位处理;也支持其他任意单位,例如 支持关键字 |
onShow* | Function | function () {} | 弹框显示时候的回调。this 为当前弹框元素,支持一个参数,为 'show' 事件对象。 |
onHide* | Function | function () {} | 弹框隐藏时候的回调。this 为当前弹框元素,支持一个参数,为 'hide' 事件对象。 |
on |
Function | function () {} | 弹框移除时候的回调。this 为当前弹框元素,支持一个参数,为 'remove' 事件对象。 |
后面跟随 * 的参数,为 Dialog()
方法独有的可选参数。其他扩展方法,无法重置。
buttons
参数
buttons
参数数组项支持参数如下:
{ type: '', value: '', form: '', className: '', events: {} }
其中:
参数名称 | 支持类型 | 默认值 | 释义 |
---|---|---|---|
type | String | 'primary' |
表示按钮的类型。和Button.css中按钮类型关键字对应。默认值与当前对象在buttons 参数数组中的位置有关。第一个按钮对象,默认值是'primary' ,也就是蓝色按钮,也就是如果你的弹框只有一个按钮,默认是蓝色。之后的按钮,默认则是白色按钮,如白色的“取消”按钮。 |
value | String | '确定' |
表示按钮的文字内容。默认值与当前对象在buttons 参数数组中的位置有关。如果在数组的第一个选项中,默认值是'确定' ,如果在后面的选项,则按钮默认值是'取消' 。 |
form | String | '' | 表示按钮所属的表单元素的id ,如果form 属性值有设置,则按钮会自动变成'submit' 类型,点击该按钮会触发对应表单元素的'submit' 行为。 |
disabled | Boolean | false | 表示按钮是否处于禁用态。 |
class |
String | '' | 表示按钮上额外添加的类名。 |
events | Object| |
{} | 表示按钮绑定的事件。可选,如果不设置,会调用弹框关闭事件。
如果只有 click 事件,可以直接使用 Function 类型参数,例如: events: function (event) { event.dialog.remove(); } 如果包含多个事件,则只能使用 Object 类型参数,例如: events: { focus() {}, blur() {} } |
因此:
1. 如果你的弹框默认就是一个文字为“确定”的确认按钮,则 buttons
参数内容就是:
{ buttons: [{}] }
2. 如果你的弹框默认就是一个蓝色确认按钮,但是文字内容是“我知道了”,则 buttons
参数内容就是:
{ buttons: [{ value: '我知道了' }] }
3. 如果你的弹框默认就是一个文字为“确定”的确认按钮,但是是红色的警示按钮,则buttons
参数内容就是:
{ buttons: [{ type: 'danger' }] }
4. 如果你的弹框默认就有一个蓝色“确定”按钮,和一个白色“取消”按钮,则buttons
参数内容就是:
{ buttons: [{}, {}] }
我们只需要空对象占位就好了。你也可以使用null
占位。
按钮中的 form 参数
form
参数使用示意,点击下面的编辑小图标测试效果。
昵称:
昵称:<output>最帅最俊朗</output> <css-icon id="b1"></css-icon>
b1.addEventListener('click', function () { const op = this.previousElementSibling; new Dialog({ title: '修改昵称', content: `<form id="f0"> 姓名:<input value="${op.textContent}" required> </form>`, buttons: [{ value: '修改', form: 'f0' }], onShow: function () { f0.addEventListener('submit', event => { event.preventDefault(); // 输入框内容赋值 op.textContent = f0.querySelector('input').value; // 弹框关闭 this.remove(); }); } }); });
参数的底层设置
Dialog 类中 options
参数在底层是使用 dialog.setParams()
这个方法实现的。
dialog.setParams(options)
dialog.setParams()
这个方法底层是使用 Object.assign()
这个方法实现的。
Object.assign(dialog.params, options || {})
因此,如果想要同时设置多个参数,下面这两种用法是等同的:
<dialog id="dialog5" is="ui-dialog">Hello, LuLu UI!</dialog>
Object.assign(dialog5.show().params, { title: '我是标题', height: 200, buttons: [{ value: '我是按钮' }] });
等同于:
dialog5.show().setParams({ title: '我是标题', height: 200, buttons: [{ value: '我是按钮' }] });
如果需要设置的参数就 1 个或者 2 个,则可以使用更底层的方法,直接改变 <dialog>
元素的 params
属性值。
例如使用 dialog.params.title
设置弹框的标题。
<dialog id="dialog6" is="ui-dialog">Hello, LuLu UI!</dialog>
button6.addEventListener('click', function () {
dialog6.show().params.title = '我是标题-哇咔咔';
});
事件的底层处理
设置 is="ui-dialog"
的 <dialog>
元素除了支持原生的 'close'
事件,还支持 'show'
、'hide'
、'remove'
和 'DOMContentLoaded'
事件。
这些事件的用法很简单,直接对 <dialog>
元素添加对应的监听即可,例如:
dialog.addEventListener('DOMContentLoaded', event => { console.log('弹框自定义属性和方法注册完毕了'); }); dialog.addEventListener('show', event => { console.log('弹框显示了'); }); dialog.addEventListener('hide', event => { console.log('弹框隐藏了'); }); dialog.addEventListener('remove', event => { console.log('弹框移除了'); });
Dialog 类中 options
的可选参数包括onShow
、onHide
和onRemove
,其底层逻辑就是使用的上面的事件监听。
实际上,onShow
参数并不是必须的,例如下面两段 JS 代码作用其实是一样的:
new Dialog({
content: `<form id="f1"></form>`,
buttons: [{ form: 'f1' }]
onShow: function () {
f1.addEventListener('submit', event => {
event.preventDefault();
// 弹框关闭
this.remove();
});
}
});
const dialog = new Dialog({
content: `<form id="f1"></form>`,
buttons: [{ form: 'f1' }]
});
f1.addEventListener('submit', event => {
event.preventDefault();
// 弹框关闭
dialog.remove();
});
因为 new Dialog()
执行的时候,弹框元素已经在页面中实现了,通过 onShow
设置显示的回调其实有些多余了。
Alert 弹框语法
模拟浏览器 window.alert()
弹框。用法如下:
dialog.alert(content, alertOptions);
其中,dialog
可以通过 new Dialog()
方法构造,也可以使用原生 JS 语句在页面中创建 <dialog>
元素。例如下面这种常用的用法:
const eleDialog = new Dialog(options).alert(content, alertOptions);
其中:
- options
- 可选。其中
onShow
,onHide
,onRemove
这3个参数只能在这里设置。 - content
- 必须。提示的内容。支持 HTML 标签。
- alertOptions
- 可选。具体参数值见下表:
参数名称 | 支持类型 | 默认值 | 释义 |
---|---|---|---|
title | String | '' | alert 弹框默认无标题文字,本项目,此参数不需要关心。 |
type | String | 'remind' | alert弹框的类型, 参数包括'remind' , 'success' , 'warning' , 'danger' , 或者任意自定义'custom' 。 |
buttons | Array | [{}] | 表示按钮。默认为1个蓝色“确定”按钮。 |
实际开发用到可选参数场景并不多,多类似这样:
new Dialog().alert('弹弹弹,弹走鱼尾纹……');
Confirm 弹框语法
模拟浏览器 window.confirm()
弹框。语法如下:
dialog.confirm(content, alertOptions);
其中,dialog
可以通过 new Dialog()
方法构造,也可以使用原生 JS 语句在页面中创建 <dialog>
元素。例如下面这种常用的用法:
const dialog = new Dialog(options).confirm(content, confirmOptions);
其中:
- options
- 可选。其中
onShow
,onHide
,onRemove
这3个参数只能在这里设置。 - content
- 必须。提示的内容。支持HTML标签。
- confirmOptions
- 可选。具体参数值见下表:
参数名称 | 支持类型 | 默认值 | 释义 |
---|---|---|---|
title | String | '' | 弹框的标题文字,默认无标题。 |
type | String | 'danger' | 弹框的类型, 参数包括'remind' , 'success' , 'danger' , 或者任意自定义'custom' 。同Alert弹框,差别在于图标。 |
buttons | Array | [{ type: 'danger' }, {}] |
表示按钮。默认为 1 个默认色按钮和 1 个红色警示“确定”按钮。 |
一般而言,我们需要对第 2 个警示按钮写事件,也就是确认删除之后干嘛干嘛,如:
new Dialog().confirm('确定弹弹弹,弹走鱼尾纹?', { buttons: [{}, { events: function(event) { /* * 这里回调,巴拉巴拉小魔仙…… * ...... */ // event.dialog为弹框实例对象 event.dialog.remove(); } }] });
Loading 弹框语法
语法如下:
const dialog = new Dialog(options).loading();
我们可以设定弹框的宽度以及各个回调。loading 模式下,标题、关闭按钮、底部按钮都不可见,只有菊花转转转。此方法需要Loading.css,如果希望替换 loading 弹框内容,下面这些方法都是可以的:
dialog.content = newContent;
dialog.params.content = newContent;
dialog.setParams({ content: newContent; });
newContent
可以是任意的字符串、DOM 节点或者返回相应字符串或 DOM 节点的 Function 函数。
暴露的属性和方法
<dialog>
弹框元素暴露了下面这些属性和方法:
{ // 只读 element: { // 含半透明遮罩的容器 container: null, // 弹框主体元素 dialog: null, // 弹框标题元素 title: null, // 弹框关闭按钮 close: null, // 弹框主内容元素 body: null, // 弹框底部元素 footer: null, // 弹框按钮1(如果有) button0: null, // 弹框按钮2(如果有) button1: null }, // 可读可写 params: { title: '', width: 'auto', height: 'auto', buttons: [], content: '' }, // 参数设置 setParams: function (options) {}, // 一些格式化的方法 alert: function () {}, confirm: function () {}, loading: function () {}, // 弹框显示 show: function () {}, // 弹框隐藏 hide: function () {}, // 弹框移除 remove: function () {} }
本页贡献者:
zhangxinxu