目录
3.组件模块化开发——使用自定义事件实现第二个对话框有input输入框
5.组件模块化开发——使用系统预定义事件(EventTarget)
6.EventTarget使用CostomEvent实现获取回调结果
7.使用EventTarget的CustomEvent实现获取input输入框的输入值
1.组件样式模块化
组件样式模块化:把组件、视图、JS分别封装起来,使用时拿来即用。
组件:内部是独立的,外部是开放的(提供各种接口,API,配置)
示例:实现一个可设置是否拖拽,是否有遮罩层,是否有取消按钮,可设置宽高等基本配置的对话框(仿写Element-UI的对话框)。
步骤:
- 封装:通过class实现默认配置还是手动配置(Object.assign(a,b)对象合并:a,b分别为两个对象,对象a有值时,合并到第一个;没有值时,取b的值);
- 生成DOM结构(一定要返回this.dialogEle = dialogEle,才能在多次生成DOM结构后,找到对应的实例化后的对象上的dialog);
- CSS初始化时,dialog需要进行隐藏,点击时显示;
- 在实例化时,需要写对话框显示/隐藏(取消/确定/X都需要隐藏)方法,并通过用户操作实现对话框的显示/隐藏;
- 控制是否显示遮罩层,是否取消,是否可拖拽;
- 页面使用(new Dialog()),并设置显示对话框的配置内容;
- 使用事件委托,实现取消、确认,X三个功能;
- 实现拖拽功能;
- 确认和取消后回调;
- 使用ES6继承方式实现第二个对话框有input输入框,并且在点击确定后,可得到input的值
以下代码只实现了基本功能:生成对话框,可配置是否有遮罩层,可配置是否可取消,可拖拽,有回调。
CSS样式:必须导入,模块化的CSS
.k-dialog {
width: 30%;
z-index: 2001;
display: block;
position: absolute;
background: #fff;
border-radius: 2px;
box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
margin: 0 auto;
top: 15vh;
left: 30%;
display: none;
}
.k-wrapper {
position: fixed;
left: 0px;
top: 0px;
bottom: 0px;
right: 0px;
background: black;
opacity: 0.4;
z-index: 2000;
display: none;
}
.k-header {
padding: 20px 20px 10px;
}
.k-header .k-title {
line-height: 24px;
font-size: 18px;
color: #303133;
float: left;
}
.k-body {
padding: 30px 20px;
color: #606266;
font-size: 14px;
}
.k-footer {
padding: 10px 20px 30px;
text-align: right;
}
.k-close {
color: #909399;
font-weight: 400;
float: right;
cursor: pointer;
}
.k-default {
color: #606266;
border: 1px solid #dcdfe6;
text-align: center;
cursor: pointer;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
font-weight: 500;
margin-right: 10px;
}
.k-default:hover {
color: #409eff;
background: #ecf5ff;
border-color: #c6e2ff;
}
.k-primary {
border: 1px solid #dcdfe6;
text-align: center;
cursor: pointer;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
font-weight: 500;
background: #409eff;
color: #fff;
margin-left: 10px;
}
.k-primary:hover {
background: #66b1ff;
}
.k-input {
width: 100%;
margin-left: 20px;
margin-bottom: 20px;
}
.input-inner {
-webkit-appearance: none;
background-color: #fff;
background-image: none;
border-radius: 4px;
border: 1px solid #dcdfe6;
box-sizing: border-box;
color: #606266;
display: inline-block;
font-size: inherit;
height: 40px;
line-height: 40px;
outline: none;
padding: 0 15px;
transition: border-color .2s cubic-bezier(.645, .045, .355, 1);
width: 100%;
margin-top: 20px;
}
JS文件:注意回调时,必须使用this.opts.cancel才能得到默认配置和手动配置合并后的结果
/*
思路:封装;渲染视图;各种方法封装;事件委托实现方法封装;取消确定回调;自定义事件实现回调
*/
class Dialog {
//传入的是调用对话框的自定义配置,当没有传入某些配置时,需要有默认配置
constructor(options) {
//使用Object.assign(a,b)方法将自定义配置和默认配置进行合并
let newOptions = Object.assign({
width: "40%",
height: "250px",
title: "默认标题",
content: "默认内容",
dragable: true, //是否可拖拽
maskable: true, //是否有遮罩
isCancel: true //是否有取消
}, options);
this.opts = newOptions;
this.init();
}
//对话框显示方法:将对话框的k-wrapper和k-dialog样式设置为显示即可
open() {
//判断有遮罩层时k-wrapper才显示
this.opts.maskable && (this.dialogEle.querySelector(".k-wrapper").style.display = "block");
this.dialogEle.querySelector(".k-dialog").style.display = "block";
}
//取消,确定,X点击时关闭对话框
close() {
this.opts.maskable && (this.dialogEle.querySelector(".k-wrapper").style.display = "none");
this.dialogEle.querySelector(".k-dialog").style.display = "none";
}
//取消时回调
cancel() {
console.log("点击取消了");
}
//确认时回调
confirm() {
console.log("点击确认了");
}
//组件初始化方法
init() {
this.renderDialog();
//如果设置了可拖拽就调用
this.opts.dragable && this.drag();
//事件委托方法:当取消,确定,X点击时,关闭对话框
this.dialogEle.addEventListener("click", e => {
//注意:此处要使用箭头函数,this才会指向 实例化对象
switch (e.target.className) {
case "k-close":
this.opts.cancel();
this.close();
break;
case "k-default":
this.opts.cancel();
this.close();
break;
case "k-primary":
this.opts.confirm();
this.close();
break;
}
});
}
//渲染初始化对话框样式
renderDialog() {
let dialogEle = document.createElement("div");
dialogEle.innerHTML = `
<div class="k-wrapper"></div>
<div class="k-dialog" style="width:${this.opts.width};height:${this.opts.height}">
<div class="k-header">
<span class="k-title">${this.opts.title}</span><span class="k-close">X</span>
</div>
<div class="k-body">
<span>${this.opts.content}</span>
</div>
<div class="k-footer">
${this.opts.isCancel ? '<span class="k-default">取消</span>' : ''}
<span class="k-primary">确定</span>
</div>
</div>
`;
document.querySelector("body").appendChild(dialogEle);
//将生成的dialog挂载在实例化后的对象上,使用时才能通过实例化获取对应某个对话框并进行处理
this.dialogEle = dialogEle;
}
//拖拽:k-dialog
drag(){
let dialog = this.dialogEle.querySelector(".k-dialog");
dialog.addEventListener("mousedown",function(ev){
let e = ev || window.event;
let l = e.clientX - dialog.offsetLeft;
let t = e.clientY - dialog.offsetTop;
function move(e){
let ev = e || window.event;
dialog.style.left = ev.clientX - l + "px";
dialog.style.top = ev.clientY - t + "px";
}
document.addEventListener("mouseover",move);
document.addEventListener("mouseup",function(){
document.removeEventListener("mouseover",move);
},{
once:true
});
e.preventDefault();
});
}
}
页面文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="dialog.css">
<title>Document</title>
</head>
<body>
<!-- <div class="k-wrapper"></div>
<div class="k-dialog">
<div class="k-header">
<span class="k-title">提示</span><span class="k-close">X</span>
</div>
<div class="k-body">
<span>这是一段文本</span>
<input class="input-inner" type="text" />
</div>
<div class="k-footer">
<span class="k-default">取消</span>
<span class="k-primary">确定</span>
</div>
</div> -->
<button class="showDailog">点击</button>
<script src="dialog.js"></script>
<script>
{
//需求:自定义组件模块化开发
/*
思路:封装;渲染视图;各种方法封装;事件委托实现方法封装;取消确定回调;自定义事件实现回调
*/
//使用:点击按钮时显示对话框
let dialog = new Dialog({
width: "30%",
height: "200px",
// title: "配置标题",
// content: "配置内容",
dragable: true, //是否可拖拽
maskable: true, //是否有遮罩
isCancel: true, //是否有取消
//取消回调
cancel(){
console.log("cancel");
},
//确认回调
confirm(){
console.log("confirm");
}
});
let showDailog = document.querySelector(".showDailog");
showDailog.addEventListener("click", function () {
dialog.open();
});
}
</script>
</body>
2.自定义事件
目的:把函数当做事件执行。可以一次点击或触发,执行多个函数。ES6中有自定义的时间API(EventTarget)。
思路:
- 添加事件,把所有的函数存在数组对象里;
- 触发事件,如果存在就执行这个事件函数;
- 移除事件,判断这个事件在对象的数组里存在就splice删除
两种方法实现:ES5和ES6
注意点:移除事件时,判断事件是否存在在数组中(!fn in this.eventObj[eventName]),和删除指定事件时的判断方式(this.eventObj[eventName][i] === fn)。
2.1方法一:使用ES5实现
分析:
- 如果不写自定义事件,多个事件需要调用多次执行;
- 使用事件监听方法addEventListener()也可以实现一次触发多次执行;
- 使用自定义事件实现一次触发,执行多个事件;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<button>点击</button>
<body>
<script>
{
//需求:自定义事件,一次触发执行多个事件
let btn = document.querySelector("button");
function event1() {
console.log("event1...");
}
function event2() {
console.log("event2...");
}
function event3() {
console.log("event3...");
}
//1.按照原始写法,多个事件执行需要进行分别调用
// event1();
// event2();
//2.事件监听,本来就可以实现一次触发执行多个事件
// btn.addEventListener("click",event1);
// btn.addEventListener("click",event2);
//3.自定义事件:实现一次触发执行多个事件
//原理:先将多个事件存放在对象的数组里,当触发时循环执行对象的数组里的事件;需要移出事件时,也可以循环找到对应事件进行移出
let eventObj = {
// event:[event1,event2]
};
//添加事件:将所有事件存到数组中
function addEvent(eventName, fn) {
//如果typeof event[eventName]为undefined证明数组中方法不存在
if (typeof eventObj[eventName] == "undefined") {
eventObj[eventName] = [];
}
eventObj[eventName].push(fn);
}
//事件触发
function triggerEvent(eventName) {
if (typeof eventObj[eventName] == "undefined") {
return;
}
eventObj[eventName].forEach(item => {
item();
});
}
//移出事件
function removeEvent(eventName, fn) {
//判断事件不存在就不移出
if (!fn in eventObj[eventName]) {
return;
}
//循环数组eventObj[eventName],如果数组中有方法为fn的就删除
for (let i = 0; i < eventObj[eventName].length; i++) {
//保证删除的是指定的事件
if (eventObj[eventName][i] === fn) {
eventObj[eventName].splice(i, 1);
//删除了就不再继续循环
break;
}
}
}
btn.addEventListener("click",function(){
addEvent("event", event1);
addEvent("event", event2);
removeEvent("event", event2);
triggerEvent("event");
});
}
</script>
</body>
</html>
2.2方法二:使用ES6实现
分析:基本思路和ES5一样,只是写法不同
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<button>点击</button>
<body>
<script>
{
//需求:自定义事件,class实现
class Event {
constructor() {
this.eventObj = {
// event:[event1,event2]
};
}
//将所有事件存到数组中
addEvent(eventName, fn) {
//如果typeof event[eventName]为undefined证明数组中方法不存在
if (typeof this.eventObj[eventName] == "undefined") {
this.eventObj[eventName] = [];
}
this.eventObj[eventName].push(fn);
}
//事件触发
triggerEvent(eventName) {
if (typeof this.eventObj[eventName] == "undefined") {
return;
}
this.eventObj[eventName].forEach(item => {
item();
});
}
//移出事件
removeEvent(eventName, fn) {
//判断事件不存在就不移出
if (!fn in this.eventObj[eventName]) {
return;
}
//循环数组eventObj[eventName],如果数组中有方法为fn的就删除
for (let i = 0; i < this.eventObj[eventName].length; i++) {
//保证删除的是指定的事件
if (this.eventObj[eventName][i] === fn) {
this.eventObj[eventName].splice(i, 1);
//删除了就不再继续循环
break;
}
}
}
}
function event1() {
console.log("event1...");
}
function event2() {
console.log("event2...");
}
function event3() {
console.log("event3...");
}
let e = new Event();
e.addEvent("event", event1);
e.addEvent("event", event2);
e.addEvent("event", event3);
e.removeEvent("event", event2);
e.triggerEvent(event1);
}
</script>
</body>
</html>
3.组件模块化开发——使用自定义事件实现第二个对话框有input输入框
Dialog继承自定义事件类Event,input输入框子类继承父类Dialog;
注意:添加函数到事件中时,必须使用this.opts.cancel,不能直接使用this.cancel,这样不会实现手动配置和默认配置的属性和方法合并
Html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="dialog.css">
<title>Document</title>
</head>
<body>
<!-- <div class="k-wrapper"></div>
<div class="k-dialog">
<div class="k-header">
<span class="k-title">提示</span><span class="k-close">X</span>
</div>
<div class="k-body">
<span>这是一段文本</span>
<input class="input-inner" type="text" />
</div>
<div class="k-footer">
<span class="k-default">取消</span>
<span class="k-primary">确定</span>
</div>
</div> -->
<button class="showDailog">点击</button>
<button class="inputDailog">点击</button>
<script src="dialog-myEvent.js"></script>
<script>
{
//需求:自定义组件模块化开发
/*
思路:封装;渲染视图;各种方法封装;事件委托实现方法封装;取消确定回调;自定义事件实现回调
*/
//使用:点击按钮时显示对话框
let dialog = new Dialog({
width: "40%",
height: "250px",
title: "配置标题",
content: "配置内容",
dragable: true, //是否可拖拽
maskable: true, //是否有遮罩
isCancel: true, //是否有取消
//取消回调
cancel(){
console.log("cancel");
},
//确认回调
confirm(e){
console.log("confirm",e);
}
});
let showDailog = document.querySelector(".showDailog");
showDailog.addEventListener("click", function () {
dialog.open();
});
//有输入框的对话框
let msgDialog = new InputDialog({
width: "40%",
height: "250px",
title: "配置标题",
content: "配置内容",
dragable: true, //是否可拖拽
maskable: true, //是否有遮罩
isCancel: true, //是否有取消
//取消回调
cancel(){
console.log("cancel");
},
//确认回调
confirm(){
console.log("confirm");
}
});
let inputDailog = document.querySelector(".inputDailog");
inputDailog.addEventListener("click", function () {
msgDialog.open();
});
}
</script>
</body>
JS文件:
/*
思路:封装;渲染视图;各种方法封装;事件委托实现方法封装;取消确定回调;自定义事件实现回调
*/
//需求:自定义事件,class实现
class Event {
constructor() {
this.eventObj = {
// event:[event1,event2]
};
}
//将所有事件存到数组中
addEvent(eventName, fn) {
//如果typeof event[eventName]为undefined证明数组中方法不存在
if (typeof this.eventObj[eventName] == "undefined") {
this.eventObj[eventName] = [];
}
this.eventObj[eventName].push(fn);
}
//事件触发
triggerEvent(eventName) {
if (typeof this.eventObj[eventName] == "undefined") {
return;
}
this.eventObj[eventName].forEach(item => {
item();
});
}
//移出事件
removeEvent(eventName, fn) {
//判断事件不存在就不移出
if (!fn in this.eventObj[eventName]) {
return;
}
//循环数组eventObj[eventName],如果数组中有方法为fn的就删除
for (let i = 0; i < this.eventObj[eventName].length; i++) {
//保证删除的是指定的事件
if (this.eventObj[eventName][i] === fn) {
this.eventObj[eventName].splice(i, 1);
//删除了就不再继续循环
break;
}
}
}
}
class Dialog extends Event {
//传入的是调用对话框的自定义配置,当没有传入某些配置时,需要有默认配置
constructor(options) {
//使用Object.assign(a,b)方法将自定义配置和默认配置进行合并
let newOptions = Object.assign({
width: "40%",
height: "250px",
title: "默认标题",
content: "默认内容",
dragable: true, //是否可拖拽
maskable: true, //是否有遮罩
isCancel: true //是否有取消
}, options);
//继承某个类时,必须先调用super()再返回this,否则返回的this里没有父类的相关属性或方法
super();
this.opts = newOptions;
this.init();
}
//对话框显示方法:将对话框的k-wrapper和k-dialog样式设置为显示即可
open() {
//判断有遮罩层时k-wrapper才显示
this.opts.maskable && (this.dialogEle.querySelector(".k-wrapper").style.display = "block");
this.dialogEle.querySelector(".k-dialog").style.display = "block";
}
//取消,确定,X点击时关闭对话框
close() {
this.opts.maskable && (this.dialogEle.querySelector(".k-wrapper").style.display = "none");
this.dialogEle.querySelector(".k-dialog").style.display = "none";
}
//取消时回调
cancel() {
console.log("点击取消了");
}
//确认时回调
confirm() {
console.log("点击确认了");
}
//组件初始化方法
init() {
this.renderDialog();
//如果设置了可拖拽就调用
this.opts.dragable && this.drag();
//把cancel和confirm加到自定义事件中(key不要一样,且不要再点击事件中设置)
this.addEvent("cancel", this.opts.cancel);
this.addEvent("confirm", this.opts.confirm);
//事件委托方法:当取消,确定,X点击时,关闭对话框
this.dialogEle.addEventListener("click", e => {
//注意:此处要使用箭头函数,this才会指向 实例化对象
switch (e.target.className) {
case "k-close":
// this.cancel();
this.triggerEvent("cancel");
this.close();
break;
case "k-default":
// this.cancel();
this.triggerEvent("cancel");
this.close();
break;
case "k-primary":
// this.confirm();
this.triggerEvent("confirm");
this.close();
break;
}
});
}
//渲染初始化对话框样式
renderDialog() {
let dialogEle = document.createElement("div");
dialogEle.innerHTML = `
<div class="k-wrapper"></div>
<div class="k-dialog" style="width:${this.opts.width};height:${this.opts.height}">
<div class="k-header">
<span class="k-title">${this.opts.title}</span><span class="k-close">X</span>
</div>
<div class="k-body">
<span>${this.opts.content}</span>
</div>
<div class="k-footer">
${this.opts.isCancel ? '<span class="k-default">取消</span>' : ''}
<span class="k-primary">确定</span>
</div>
</div>
`;
document.querySelector("body").appendChild(dialogEle);
//将生成的dialog挂载在实例化后的对象上,使用时才能通过实例化获取对应某个对话框并进行处理
this.dialogEle = dialogEle;
}
//拖拽:k-dialog
drag() {
let dialog = this.dialogEle.querySelector(".k-dialog");
dialog.addEventListener("mousedown", function (ev) {
let e = ev || window.event;
let l = e.clientX - dialog.offsetLeft;
let t = e.clientY - dialog.offsetTop;
function move(e) {
let ev = e || window.event;
dialog.style.left = ev.clientX - l + "px";
dialog.style.top = ev.clientY - t + "px";
e.preventDefault();
}
document.addEventListener("mouseover", move);
document.addEventListener("mouseup", function () {
document.removeEventListener("mouseover", move);
}, {
once: true
});
});
}
}
//有输入框的对话框
class InputDialog extends Dialog{
constructor(options){
super(options);
this.renderInput();
}
renderInput(){
//如果不可以点击是因为在鼠标按下设置了取消默认事件
//渲染时,添加上文本框
let kBody = this.dialogEle.querySelector(".k-body");
let myinput = document.createElement("input");
myinput.classList.add("input-inner");
myinput.type = "text";
kBody.appendChild(myinput);
}
}
4.系统预定义事件(EventTarget)
EventTarget是系统预定义的处理一次触发多次执行事件的方法。
使用时,
- 需要先创建事件:new Event();
- 添加事件ele.addEventListener('event', 事件);
- 触发事件:btn.dispatchEvent(event);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<button>点击</button>
<body>
<script>
{
//需求:使用系统自定义类实现一次触发,执行多个事件
function event1() {
console.log("event1...");
}
function event2() {
console.log("event2...");
}
function event3() {
console.log("event3...");
}
var event = new Event('event');//创建一个event事件
let btn = document.querySelector("button");
btn.addEventListener('event', event1);//为元素绑定事件监听
btn.addEventListener("event", event2);
btn.addEventListener("event", event3);
btn.onclick = function(){
btn.dispatchEvent(event);//派发事件
};
}
</script>
</body>
</html>
5.组件模块化开发——使用系统预定义事件(EventTarget)
HTML文件和自定义事件没有区别,只是引入的JS文件改变了
/*
思路:封装;渲染视图;各种方法封装;事件委托实现方法封装;取消确定回调;自定义事件实现回调
*/
//需求:使用系统预定义事件
class Dialog extends EventTarget {
//传入的是调用对话框的自定义配置,当没有传入某些配置时,需要有默认配置
constructor(options) {
//使用Object.assign(a,b)方法将自定义配置和默认配置进行合并
let newOptions = Object.assign({
width: "40%",
height: "250px",
title: "默认标题",
content: "默认内容",
dragable: true, //是否可拖拽
maskable: true, //是否有遮罩
isCancel: true //是否有取消
}, options);
//继承某个类时,必须先调用super()再返回this,否则返回的this里没有父类的相关属性或方法
super();
this.opts = newOptions;
this.init();
}
//对话框显示方法:将对话框的k-wrapper和k-dialog样式设置为显示即可
open() {
//判断有遮罩层时k-wrapper才显示
this.opts.maskable && (this.dialogEle.querySelector(".k-wrapper").style.display = "block");
this.dialogEle.querySelector(".k-dialog").style.display = "block";
}
//取消,确定,X点击时关闭对话框
close() {
this.opts.maskable && (this.dialogEle.querySelector(".k-wrapper").style.display = "none");
this.dialogEle.querySelector(".k-dialog").style.display = "none";
}
//取消时回调
cancel() {
console.log("点击取消了");
}
//确认时回调
confirm() {
console.log("点击确认了");
}
//组件初始化方法
init() {
this.renderDialog();
//如果设置了可拖拽就调用
this.opts.dragable && this.drag();
//把cancel和confirm加到自定义事件中(key不要一样,且不要再点击事件中设置)
// this.addEvent("cancel", this.cancel);
// this.addEvent("confirm", this.confirm);
//使用系统预定义事件处理
var cancel = new Event('cancel');//创建并绑定一个event事件
var confirm = new Event('confirm');//创建并绑定一个event事件
this.addEventListener('cancel', this.opts.cancel);
this.addEventListener('confirm', this.opts.confirm);
//事件委托方法:当取消,确定,X点击时,关闭对话框
this.dialogEle.addEventListener("click", e => {
//注意:此处要使用箭头函数,this才会指向 实例化对象
switch (e.target.className) {
case "k-close":
// this.cancel();
// this.triggerEvent("cancel");
this.dispatchEvent(cancel);
this.close();
break;
case "k-default":
// this.cancel();
// this.triggerEvent("cancel");
this.dispatchEvent(cancel);
this.close();
break;
case "k-primary":
// this.confirm();
// this.triggerEvent("confirm");
this.dispatchEvent(confirm);
this.close();
break;
}
});
}
//渲染初始化对话框样式
renderDialog() {
let dialogEle = document.createElement("div");
dialogEle.innerHTML = `
<div class="k-wrapper"></div>
<div class="k-dialog" style="width:${this.opts.width};height:${this.opts.height}">
<div class="k-header">
<span class="k-title">${this.opts.title}</span><span class="k-close">X</span>
</div>
<div class="k-body">
<span>${this.opts.content}</span>
</div>
<div class="k-footer">
${this.opts.isCancel ? '<span class="k-default">取消</span>' : ''}
<span class="k-primary">确定</span>
</div>
</div>
`;
document.querySelector("body").appendChild(dialogEle);
//将生成的dialog挂载在实例化后的对象上,使用时才能通过实例化获取对应某个对话框并进行处理
this.dialogEle = dialogEle;
}
//拖拽:k-dialog
drag() {
let dialog = this.dialogEle.querySelector(".k-dialog");
dialog.addEventListener("mousedown", function (ev) {
let e = ev || window.event;
let l = e.clientX - dialog.offsetLeft;
let t = e.clientY - dialog.offsetTop;
function move(e) {
let ev = e || window.event;
dialog.style.left = ev.clientX - l + "px";
dialog.style.top = ev.clientY - t + "px";
e.preventDefault();
}
document.addEventListener("mouseover", move);
document.addEventListener("mouseup", function () {
document.removeEventListener("mouseover", move);
}, {
once: true
});
});
}
}
//有输入框的对话框
class InputDialog extends Dialog {
constructor(options) {
super(options);
this.renderInput();
}
renderInput() {
//如果不可以点击是因为在鼠标按下设置了取消默认事件
//渲染时,添加上文本框
let kBody = this.dialogEle.querySelector(".k-body");
let myinput = document.createElement("input");
myinput.classList.add("input-inner");
myinput.type = "text";
kBody.appendChild(myinput);
}
}
6.EventTarget使用CostomEvent实现获取回调结果
创建事件时不再使用new Event() 而是使用 new CustomEvent()
//需求:使用CustomEvent获取事件回调
// add an appropriate event listener
let btn = document.querySelector("button");
btn.addEventListener("cat", function (e) { console.log(e.detail) });
// create and dispatch the event
let event = new CustomEvent("cat", {
detail: {
hazcheeseburger: true
}
});
btn.dispatchEvent(event);
// Will return an object contaning the hazcheeseburger property
let myDetail = event.detail;
7.使用EventTarget的CustomEvent实现获取input输入框的输入值
HTML文件:回调时使用e.detail得到回调值
//确认回调
confirm(e){
console.log("手动配置 confirm",e.detail);
},
完整HTML文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="dialog.css">
<title>Document</title>
</head>
<body>
<!-- <div class="k-wrapper"></div>
<div class="k-dialog">
<div class="k-header">
<span class="k-title">提示</span><span class="k-close">X</span>
</div>
<div class="k-body">
<span>这是一段文本</span>
<input class="input-inner" type="text" />
</div>
<div class="k-footer">
<span class="k-default">取消</span>
<span class="k-primary">确定</span>
</div>
</div> -->
<button class="showDailog">点击</button>
<button class="inputDailog">点击</button>
<script src="dialog-EventTarget-CustomEvent.js"></script>
<script>
{
//需求:自定义组件模块化开发
/*
思路:封装;渲染视图;各种方法封装;事件委托实现方法封装;取消确定回调;自定义事件实现回调
*/
//使用:点击按钮时显示对话框
let dialog = new Dialog({
width: "40%",
height: "250px",
title: "配置标题",
content: "配置内容",
dragable: true, //是否可拖拽
maskable: true, //是否有遮罩
isCancel: true, //是否有取消
//取消回调
cancel(){
console.log("cancel");
},
//确认回调
confirm(){
console.log("confirm");
}
});
let showDailog = document.querySelector(".showDailog");
showDailog.addEventListener("click", function () {
dialog.open();
});
//有输入框的对话框
let msgDialog = new InputDialog({
width: "40%",
height: "250px",
title: "配置标题",
content: "配置内容",
dragable: true, //是否可拖拽
maskable: true, //是否有遮罩
isCancel: true, //是否有取消
//确认回调
confirm(e){
console.log("手动配置 confirm",e.detail);
},
//取消回调
cancel(){
console.log("手动配置 cancel");
}
});
let inputDailog = document.querySelector(".inputDailog");
inputDailog.addEventListener("click", function () {
msgDialog.open();
});
}
</script>
</body>
JS文件:
重要代码:
//使用CustomEvent获取事件回调
ensure(inputVal){
this.dispatchEvent(new CustomEvent("confirm",{
detail:{
inputVal
}
}));
this.close();
}
完整JS文件:
/*
思路:封装;渲染视图;各种方法封装;事件委托实现方法封装;取消确定回调;自定义事件实现回调
*/
//需求:使用CustomEvent获取input输入框的值
class Dialog extends EventTarget {
//传入的是调用对话框的自定义配置,当没有传入某些配置时,需要有默认配置
constructor(options) {
//使用Object.assign(a,b)方法将自定义配置和默认配置进行合并
let newOptions = Object.assign({
width: "40%",
height: "250px",
title: "默认标题",
content: "默认内容",
dragable: true, //是否可拖拽
maskable: true, //是否有遮罩
isCancel: true,//是否有取消
confirm(e) {
console.log("默认配置点击了确定",e.detail);
},
cancel() {
console.log("默认配置点击了取消");
}
}, options);
//继承某个类时,必须先调用super()再返回this,否则返回的this里没有父类的相关属性或方法
super();
this.opts = newOptions;
this.init();
}
//对话框显示方法:将对话框的k-wrapper和k-dialog样式设置为显示即可
open() {
//判断有遮罩层时k-wrapper才显示
this.opts.maskable && (this.dialogEle.querySelector(".k-wrapper").style.display = "block");
this.dialogEle.querySelector(".k-dialog").style.display = "block";
}
//取消,确定,X点击时关闭对话框
close() {
this.opts.maskable && (this.dialogEle.querySelector(".k-wrapper").style.display = "none");
this.dialogEle.querySelector(".k-dialog").style.display = "none";
}
//取消时回调
cancel() {
console.log("点击取消了");
}
//确认时回调
confirm() {
console.log("点击确认了");
}
//组件初始化方法
init() {
this.renderDialog();
//如果设置了可拖拽就调用
this.opts.dragable && this.drag();
//把cancel和confirm加到自定义事件中(key不要一样,且不要再点击事件中设置)
// this.addEvent("cancel", this.cancel);
// this.addEvent("confirm", this.confirm);
//使用系统预定义事件处理
let cancel = new Event('cancel');//创建并绑定一个event事件
// var confirm = new Event('confirm');//使用CustomEvent回调时,在调用时设置
this.addEventListener('cancel', this.opts.cancel);
this.addEventListener('confirm', this.opts.confirm);
//事件委托方法:当取消,确定,X点击时,关闭对话框
this.dialogEle.addEventListener("click", e => {
//注意:此处要使用箭头函数,this才会指向 实例化对象
switch (e.target.className) {
case "k-close":
// this.cancel();
// this.triggerEvent("cancel");
this.dispatchEvent(cancel);
this.close();
break;
case "k-default":
// this.cancel();
// this.triggerEvent("cancel");
this.dispatchEvent(cancel);
this.close();
break;
case "k-primary":
// this.confirm();
// this.triggerEvent("confirm");
// this.dispatchEvent(confirm);
//通过CustomEvent获取回调
this.ensure();
// this.close();
break;
}
});
}
//渲染初始化对话框样式
renderDialog() {
let dialogEle = document.createElement("div");
dialogEle.innerHTML = `
<div class="k-wrapper"></div>
<div class="k-dialog" style="width:${this.opts.width};height:${this.opts.height}">
<div class="k-header">
<span class="k-title">${this.opts.title}</span><span class="k-close">X</span>
</div>
<div class="k-body">
<span>${this.opts.content}</span>
</div>
<div class="k-footer">
${this.opts.isCancel ? '<span class="k-default">取消</span>' : ''}
<span class="k-primary">确定</span>
</div>
</div>
`;
document.querySelector("body").appendChild(dialogEle);
//将生成的dialog挂载在实例化后的对象上,使用时才能通过实例化获取对应某个对话框并进行处理
this.dialogEle = dialogEle;
}
//拖拽:k-dialog
drag() {
let dialog = this.dialogEle.querySelector(".k-dialog");
dialog.addEventListener("mousedown", function (ev) {
let e = ev || window.event;
let l = e.clientX - dialog.offsetLeft;
let t = e.clientY - dialog.offsetTop;
function move(e) {
let ev = e || window.event;
dialog.style.left = ev.clientX - l + "px";
dialog.style.top = ev.clientY - t + "px";
e.preventDefault();
}
document.addEventListener("mouseover", move);
document.addEventListener("mouseup", function () {
document.removeEventListener("mouseover", move);
}, {
once: true
});
});
}
//使用CustomEvent获取事件回调
ensure(inputVal){
this.dispatchEvent(new CustomEvent("confirm",{
detail:{
inputVal
}
}));
this.close();
}
}
//有输入框的对话框
class InputDialog extends Dialog {
constructor(options) {
//写super时一定要把参数传进去,否则手动配置的没有效果
super(options);
this.renderInput();
}
renderInput() {
//如果不可以点击是因为在鼠标按下设置了取消默认事件
//渲染时,添加上文本框
let kBody = this.dialogEle.querySelector(".k-body");
let myinput = document.createElement("input");
myinput.classList.add("input-inner");
myinput.type = "text";
kBody.appendChild(myinput);
}
//使用CustomEvent获取事件回调
ensure(){
let inputVal = this.dialogEle.querySelector(".input-inner").value;
super.ensure(inputVal);
}
}