面向对象三(组件样式模块化、系统预定义事件)

84 篇文章 3 订阅
3 篇文章 0 订阅

目录

1.组件样式模块化

2.自定义事件

2.1方法一:使用ES5实现

2.2方法二:使用ES6实现

3.组件模块化开发——使用自定义事件实现第二个对话框有input输入框

4.系统预定义事件(EventTarget)

5.组件模块化开发——使用系统预定义事件(EventTarget)

6.EventTarget使用CostomEvent实现获取回调结果

7.使用EventTarget的CustomEvent实现获取input输入框的输入值


1.组件样式模块化

组件样式模块化:把组件、视图、JS分别封装起来,使用时拿来即用。

组件:内部是独立的,外部是开放的(提供各种接口,API,配置)

示例:实现一个可设置是否拖拽,是否有遮罩层,是否有取消按钮,可设置宽高等基本配置的对话框(仿写Element-UI的对话框)。

步骤:

  1. 封装:通过class实现默认配置还是手动配置(Object.assign(a,b)对象合并:a,b分别为两个对象,对象a有值时,合并到第一个;没有值时,取b的值);
  2. 生成DOM结构(一定要返回this.dialogEle = dialogEle,才能在多次生成DOM结构后,找到对应的实例化后的对象上的dialog);
  3. CSS初始化时,dialog需要进行隐藏,点击时显示;
  4. 在实例化时,需要写对话框显示/隐藏(取消/确定/X都需要隐藏)方法,并通过用户操作实现对话框的显示/隐藏;
  5. 控制是否显示遮罩层,是否取消,是否可拖拽;
  6. 页面使用(new Dialog()),并设置显示对话框的配置内容;
  7. 使用事件委托,实现取消、确认,X三个功能;
  8. 实现拖拽功能;
  9. 确认和取消后回调;
  10. 使用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)。

思路:

  1. 添加事件,把所有的函数存在数组对象里;
  2. 触发事件,如果存在就执行这个事件函数;
  3. 移除事件,判断这个事件在对象的数组里存在就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是系统预定义的处理一次触发多次执行事件的方法。

使用时,

  1. 需要先创建事件:new Event();
  2. 添加事件ele.addEventListener('event', 事件);
  3. 触发事件: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);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值