一个文笔一般,想到哪是哪的唯心论前端小白。
前言
没错,跟jQuery磕上了!
前两天无奈之下用jQuery写了个分页,今天又写了一个弹框组件。没有特殊的地方,就是弹框组件,和 el-dialog
是一模一样的。
效果大概是这样子的:

觉得可能在不知道什么时候可能用一下,所以做个文档记录一下吧!
思路
需求分析:
- 通过点击dom对象,或者触发js方法,触发 open 方法,打开弹框。
- 弹框自动添加 header 和 footer,并把业务放在 body 中。
- 支持按钮自定义,并可以绑定自定义方法。自定义方法执行完成以后关闭弹框。
使用方法设想
根据最近的开发习惯,dom结构当然是这样的最舒服了!
html
<div class="cm-dialog" id="dialogDemo">
<p>hello world!</p>
</div>
即我们只关注业务内容,由插件动生成弹框的头部和底部。
然后是js结构则是这样的:
js
$(function () {
const dialogDemo = $('#dialogDemo').initDialog({
title: '查看详情',
cancel: {
label: '取消',
handler: function () {
console.log('触发了取消');
return true;
}
},
submit: {
label: '确定',
handler: function () {
console.log('触发了确定');
return true;
}
}
})
$('#button').on('click', function () {
dialogDemo.trigger('open')
})
})
可以看到,针对jQuery扩展了一个名为 initDialog
的方法,传入配置内容,配置内容包含常用的 title 和两个按钮,分别对应【取消】按钮和【确定】按钮,并绑定两个方法。
关键是最后要使用一个变量来记录这个初始化以后的 dialog 对象,可以使用 trigger 方法去触发内部的 open 方法,打开弹框。
坑点补充
以上这个方案里面有几个点需要注意:
- 如果按钮绑定的方法抛出异常,需要阻止关闭,所以这个方法应该有一个 Boolearn 类型的返回值。
- 如果只有一个按钮或者多个按钮,则需要动态的去渲染按钮。
- body 部分应该有个最大高度,避免超出可视范围的尴尬局面。
开发
开发这块比较简单,提前声明一下,上面三个坑点只有第三个做了,前面两个没做!
意不意外? 但是还会把思路写出来。
开发过程中因为没想明白怎么使用模版把 头部和底部 使用模板渲染出来,一度想着在 cm-dialog 里面再套一层,然后再向里面添加 htm 的方法,后来被 pass 掉了。
最终的方案是这样子的:
js
$.fn.extend({
initDialog: function (conf) {
var inner = $(this).html();
// 解析 config
var title = conf.title || "标题";
var cancel = conf.cancel || null;
var submit = conf.submit || null;
// 模板
var htm = `
<div class="cm-dialog-wrap">
<div class="cm-dialog-header">
<span>${title}</span>
</div>
<div class="cm-dialog-body">
${inner}
</div>
<div class="cm-dialog-footer">
<button class="cm-button-cancel">${cancel.label}</button>
<button class="cm-button-submit">${submit.label}</button>
</div>
</div>
`;
// 初始化 dialog
$(this).html(htm);
$(this).hide();
// 绑定 open 方法
$(this).bind("open", function () {
$(this).fadeIn();
});
// 绑定 close 方法
$(this).bind("close", function () {
$(this).fadeOut();
});
// 绑定按钮事件
$(".cm-button-cancel").on("click", function () {
if(cancel.handler && cancel.handler()){
$(this).trigger("close");
};
});
$(".cm-button-submit").on("click", function () {
if(submit.handler && submit.handler()){
$(this).trigger("close");
}
});
// 返回 dialog
return $(this);
},
});
其实结构很简单,主要是一个思路,就是在方法的一开始,将 inner 提出来,然后放在模板中。这样就实现了dom结构很简单,但是后面会包含头部和底部的开发方式。
然后就是剩余的两个坑点的处理方式:
- 其实已经解决了,返回值为 true 和false 的事情,但是如果是异步方法需要注意了,可以使用 trigger 去触发 close 方法。
- 传入按钮改为一个数组,使用map函数将数组转换成dom结构,并重新绑定一下方法就好了。
代码分享
主要分享三个文件:
dialog.extends.js
js
$.fn.extend({
initDialog: function (conf) {
var inner = $(this).html();
// 解析 config
var title = conf.title || "标题";
var cancel = conf.cancel || null;
var submit = conf.submit || null;
// 模板
var htm = `
<div class="cm-dialog-wrap">
<div class="cm-dialog-header">
<span>${title}</span>
</div>
<div class="cm-dialog-body">
${inner}
</div>
<div class="cm-dialog-footer">
<button class="cm-button-cancel">${cancel.label}</button>
<button class="cm-button-submit">${submit.label}</button>
</div>
</div>
`;
// 初始化 dialog
$(this).html(htm);
$(this).hide();
// 绑定 open 方法
$(this).bind("open", function () {
$(this).fadeIn();
});
// 绑定 close 方法
$(this).bind("close", function () {
$(this).fadeOut();
});
// 绑定按钮事件
$(".cm-button-cancel").on("click", function () {
if(cancel.handler && cancel.handler()){
$(this).trigger("close");
};
});
$(".cm-button-submit").on("click", function () {
if(submit.handler && submit.handler()){
$(this).trigger("close");
}
});
// 返回 dialog
return $(this);
},
});
dialog.extends.css
需要注意,这里只包含了 dialog 相关的样式,需要配合全局样式去使用。
类似:
*{ padding :0; margin: 0}
css
.cm-dialog {
height: 100%;
width: 100%;
position: fixed;
z-index: 999;
top: 0;
left: 0;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
background: rgba(48, 42, 42, 0.5);
}
.cm-dialog-wrap {
height: auto;
width: 960px;
background: #fff;
box-shadow: 0 0 10px #000;
position: relative;
overflow: hidden;
}
.cm-dialog-header {
position: absolute;
top: 0;
left: 0;
right: 0;
padding: 5px 20px;
background: #ebecee;
height: 40px;
line-height: 40px;
}
.cm-dialog-body {
padding: 70px 20px 70px 20px;
max-height: 500px;
overflow-y: auto;
overflow-x: hidden;
}
.cm-dialog-footer {
position: absolute;
bottom: 0;
background: #ebecee;
padding: 5px 20px;
left: 0;
right: 0;
line-height: 40px;
text-align: right;
}
.cm-dialog-footer button {
padding: 6px 16px;
background: skyblue;
border: none;
outline: none;
border-radius: 4px;
cursor: pointer;
transition: background linear 0.1s;
}
/* .cm-dialog-footer button.cm-button-submit {
background: red;
} */
.cm-dialog-footer button:hover {
background: rgb(58, 182, 231);
}
dialog-demo.html
就是展示一下怎么用。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./index.css">
<link rel="stylesheet" href="./dialog.extend.css">
</head>
<body>
<button id="button">Click Me!</button>
<div class="cm-dialog" id="dialogDemo">
<p>hello world!</p>
</div>
</body>
<script src="./jquery.js"></script>
<script src="./dialog.extends.js"></script>
<script>
$(function () {
const dialogDemo = $('#dialogDemo').initDialog({
title: '查看详情',
cancel: {
label: '取消',
handler: function () {
console.log('触发了取消');
}
},
submit: {
label: '确定',
handler: function () {
console.log('触发了确定');
}
}
})
$('#button').on('click', function () {
dialogDemo.trigger('open')
})
})
</script>
</html>
后记
思路很简单,代码量也很少,关键就是一个将原模板里面的内容重写一遍的思路。
有所思必有所得:
- 一个开箱即用的 dialog jQuery 插件。
- 一个 jQuery 或者原生代码中使用模板开发的开发思路。
- MVVM 模式的浅显探索?