JavaScript设计模式(十五):照猫画虎-模板方法模式

简介: 照猫画虎-模板方法模式

模板方法模式(Template Method)

父类中定义一组操作算法骨架,而将一些实现步骤延迟到子类中,使得子类可以不改变父类的算法结构的同时可重新定义算法中某些实现步骤。

需求:定义一个全局能用的弹出框

image.png

<style>
    * {
    
    
        padding: 0;
        margin: 0;
        outline: none;
    }

    /* 提示框容器 */
    .alert-box {
    
    
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 420px;
        background-color: #fff;
        border-radius: 4px;
        border: 1px solid #ebeef5;
        box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
        display: none;
    }

    /* Header部分 */
    .alert-box .alert-box__header {
    
    
        position: relative;
        padding: 15px 15px 10px;
    }

    .alert-box .alert-box__header .alert-box__title {
    
    
        padding-left: 0;
        margin-bottom: 0;
        font-size: 18px;
        line-height: 1;
        color: #303133;
    }

    .alert-box .alert-box__header .alert-box__headerbtn {
    
    
        position: absolute;
        top: 15px;
        right: 15px;
        padding: 0;
        border: none;
        outline: none;
        background: transparent;
        font-size: 16px;
        cursor: pointer;
    }

    /* content部分 */
    .alert-box .alert-box__content {
    
    
        padding: 10px 15px;
        color: #606266;
        font-size: 14px;
    }

    /* 操作部分 */
    .alert-box .alert-box__footer {
    
    
        padding: 5px 15px 10px 15px;
        text-align: right;
    }

    /* 按钮部分 */
    .btn {
    
    
        cursor: pointer;
        text-align: center;
        box-sizing: border-box;
        outline: none;
        padding: 0 10px;
        height: 32px;
        line-height: 16px;
        font-size: 14px;
        border-radius: 4px;
    }

    .btn+.btn {
    
    
        margin-left: 5px;
    }

    .btn.primary__btn {
    
    
        border: 1px solid #409eff;
        background-color: #409eff;
        color: #fff;
    }

    .btn.default__btn {
    
    
        border: 1px solid #b6b8bb;
        background-color: #ffffff;
        color: #333;
    }

    .btn.warning__btn {
    
    
        border: 1px solid #f56c6c;
        background-color: #f56c6c;
        color: #fff;
    }

    .title-center{
    
    
        text-align: center;
    }
</style>

<body>
    <fieldset style="margin: 20px;padding: 20px;">
        <legend>基础提示框</legend>
        <button id="show-btn" class="btn primary__btn">显示</button>
        <button id="hide-btn" class="btn primary__btn">隐藏</button>
    </fieldset>
    <fieldset style="margin: 20px;padding: 20px;">
        <legend>根据模板创建自定义提示框</legend>
        <button id="show-custom-btn" class="btn primary__btn">显示</button>
        <button id="hide-custom-btn" class="btn primary__btn">隐藏</button>
    </fieldset>
</body>
/**
 * 基础提示框模板类
 * <div class="alert-box">
 *     <div class="alert-box__header">
 *         <div class="alert-box__title"><b>提示</b></div>
 *         <button class="alert-box__headerbtn" type="button"><i>X</i></button>
 *     </div>
 *     <div class="alert-box__content">基本提示框</div>
 *     <div class="alert-box__footer">
 *         <button class="btn default__btn">取消</button>
 *         <button class="btn primary__btn">确认</button>
 *         <button class="btn warning__btn">删除</button>
 *     </div>
 * </div>
 */
const Alert = function (data) {
   
   
    // 没有数据则返回,防止后面程序执行
    if (!data) return;

    /**
     * 创建提示框面板
     */
    this.panelNode = document.createElement('div');
    this.panelNode.className = 'alert-box';

    /**
     * 创建header组件容器
     */
    this.headerNode = document.createElement('div');
    this.headerNode.className = 'alert-box__header';

    /**
     * 创建header内标题组件
     */
    this.title = data.title;
    this.titleNode = document.createElement('div');
    this.titleNode.className = 'alert-box__title';
    this.titleNode.innerHTML = data.title || '<b>提示</b>';

    /**
     * 创建header内关闭按钮组件
     */
    this.showCloseBtn = data.showCloseBtn === undefined ? true : data.showCloseBtn;
    this.closeIcon = data.closeIcon;
    this.closeBtnNode = document.createElement('button');
    this.closeBtnNode.className = 'alert-box__headerbtn';
    this.closeBtnNode.innerHTML = data.closeIcon || '<i>X</i>';

    /**
     * 创建内容组件
     */
    this.content = data.content;
    this.contentNode = document.createElement('div');
    this.contentNode.className = 'alert-box__content';
    this.contentNode.innerHTML = data.content || '';

    /**
     * 创建footer组件
     */
    this.footerNode = document.createElement('div');
    this.footerNode.className = 'alert-box__footer';

    /**
     * 创建确认按钮
     */
    this.showConfirmBtn = data.showConfirmBtn === undefined ? true : data.showConfirmBtn;
    this.confirmText = data.confirmText;
    this.confirmBtnNode = document.createElement('button');
    this.confirmBtnNode.className = 'btn primary__btn';
    this.confirmBtnNode.innerText = data.confirmText || '确认';

    /**
     * 创建取消按钮
     */
    this.showCancelBtn = data.showCancelBtn === undefined ? true : data.showCancelBtn;
    this.cancelText = data.cancelText;
    this.cancelBtnNode = document.createElement('button');
    this.cancelBtnNode.className = 'btn default__btn';
    this.cancelBtnNode.innerText = data.cancelText || '取消';

    /**
     * 监听按钮回调
     */
    this.handleClose = data.handleClose || function () {
   
    };
    this.handleConfirm = data.handleConfirm || function () {
   
    };
    this.handleCancel = data.handleCancel || function () {
   
    };
    this.handleDelete = data.handleDelete || function () {
   
    };
};

// 基础提示框 的 原型方法
Alert.prototype = {
   
   
    // 初始化基础提示框
    init() {
   
   
        // header内插入组件
        this.headerNode.appendChild(this.titleNode);
        this.showCloseBtn && this.headerNode.appendChild(this.closeBtnNode);
        // 提示框内插入header组件
        this.panelNode.appendChild(this.headerNode);
        // 提示框内插入content组件
        this.panelNode.appendChild(this.contentNode);
        // 提示框底部添加 确认、取消 按钮组件
        this.showConfirmBtn && this.footerNode.appendChild(this.confirmBtnNode);
        this.showCancelBtn && this.footerNode.appendChild(this.cancelBtnNode);
        // 提示框内插入footer组件
        this.panelNode.appendChild(this.footerNode);
        // 插入页面中
        document.body.appendChild(this.panelNode);

        // 绑定事件
        this.bindEvent();

        return this;
    },
    bindEvent() {
   
   
        const that = this;
        // 关闭按钮点击事件
        this.closeBtnNode.onclick = function () {
   
   
            // 执行关闭方法
            that.handleClose();
            // 隐藏弹层
            that.hide();
        };
        // 确定按钮点击事件
        this.confirmBtnNode.onclick = function () {
   
   
            // 执行确认方法
            that.handleConfirm();
            // 隐藏弹层
            that.hide();
        };
        // 取消按钮点击事件
        this.cancelBtnNode.onclick = function () {
   
   
            // 执行取消方法
            that.handleCancel();
            // 隐藏弹层
            that.hide();
        };
    },
    // 隐藏弹层方法
    hide() {
   
   
        this.panelNode.style.display = 'none';
    },
    // 显示弹层方法
    show() {
   
   
        this.panelNode.style.display = 'block';
    }
};
// 实例化出一个基础弹出框
let baseAlert = new Alert({
   
   
    title: '<b>提示(ง •_•)ง:</b>',
    showCloseBtn: true,
    content: '请点击您要对该条数据执行的操作按钮!',
    showConfirmBtn: true,
    showCancelBtn: true,
    handleClose() {
   
   
        console.log('关闭');
    },
    handleConfirm() {
   
   
        console.log('确认');
    },
    handleCancel() {
   
   
        console.log('取消');
    },
}).init();

// 显示
document.getElementById('show-btn').onclick = function () {
   
   
    baseAlert.show();
};

// 隐藏
document.getElementById('hide-btn').onclick = function () {
   
   
    baseAlert.hide();
};
/**
 * 继承自基础提示框的自定义提示框
 */
const CustomALert = function (data) {
   
   
    // 构造函数设计模式
    Alert.call(this, data);
    // 修改模板内的组件
    this.titleNode.className += ' title-center';
};
// 继承基本提示框方法
CustomALert.prototype = new Alert();
CustomALert.prototype.init = function () {
   
   
    // 插入标题
    this.titleNode.innerHTML += ' ヾ(≧▽≦*)o'
    this.panelNode.insertBefore(this.titleNode, this.panelNode.firstChild);
    // 调用父类原型上的方法
    Alert.prototype.init.call(this);
    return this;
};
let customAlert = new CustomALert({
   
   
    title: '<b>提示(ง •_•)ง</b>',
    showCloseBtn: true,
    content: '请点击您要对该条数据执行的操作按钮!',
    showConfirmBtn: true,
    showCancelBtn: true,
    handleClose() {
   
   
        console.log('关闭');
    },
    handleConfirm() {
   
   
        console.log('确认');
    },
    handleCancel() {
   
   
        console.log('取消');
    },
}).init();

// 显示
document.getElementById('show-custom-btn').onclick = function () {
   
   
    customAlert.show();
};

// 隐藏
document.getElementById('hide-custom-btn').onclick = function () {
   
   
    customAlert.hide();
};

特点:

模板方法核心在于对方法的重用,它将核心方法封装在基类中,让子类继承基类的方法实现基类方法的共享,达到方法共用

当然这种设计模式也将导致基类控制子类必须遵守某些法则。这是一种行为的约束。当然为了让行为的约束更可靠基类中封装的方法通常是不变的算法,或者具有稳定的调用方式

子类继承的方法亦是可以扩展的,这就要求对基类继承的方法进行重写。当然为了更好地实践,我们通常要控制这种拓展,这样才能让基类对子类有更稳健的束缚力。然而子类对自身私有行为的拓展还是很有必要的。

目录
相关文章
|
1月前
|
设计模式 JavaScript 前端开发
JavaScript设计模式--访问者模式
【10月更文挑战第1天】
30 3
|
2月前
|
设计模式 算法 Java
Java设计模式-模板方法模式(14)
Java设计模式-模板方法模式(14)
|
3月前
|
设计模式 JavaScript 前端开发
从工厂到单例再到策略:Vue.js高效应用JavaScript设计模式
【8月更文挑战第30天】在现代Web开发中,结合使用JavaScript设计模式与框架如Vue.js能显著提升代码质量和项目的可维护性。本文探讨了常见JavaScript设计模式及其在Vue.js中的应用。通过具体示例介绍了工厂模式、单例模式和策略模式的应用场景及其实现方法。例如,工厂模式通过`NavFactory`根据用户角色动态创建不同的导航栏组件;单例模式则通过全局事件总线`eventBus`实现跨组件通信;策略模式用于处理不同的表单验证规则。这些设计模式的应用不仅提高了代码的复用性和灵活性,还增强了Vue应用的整体质量。
50 1
|
3月前
|
设计模式 JavaScript 前端开发
小白请看 JS大项目宝典:设计模式 教你如何追到心仪的女神
小白请看 JS大项目宝典:设计模式 教你如何追到心仪的女神
|
4月前
|
设计模式 JavaScript Go
js设计模式【详解】—— 状态模式
js设计模式【详解】—— 状态模式
79 7
|
4月前
|
设计模式 JavaScript
js设计模式【详解】—— 桥接模式
js设计模式【详解】—— 桥接模式
67 6
|
4月前
|
设计模式 JavaScript
js设计模式【详解】—— 原型模式
js设计模式【详解】—— 原型模式
49 6
|
4月前
|
设计模式 JavaScript 算法
js设计模式【详解】—— 模板方法模式
js设计模式【详解】—— 模板方法模式
47 6
|
4月前
|
设计模式 JavaScript 前端开发
JavaScript进阶 - JavaScript设计模式
【7月更文挑战第7天】在软件工程中,设计模式是解决常见问题的标准解决方案。JavaScript中的工厂模式用于对象创建,但过度使用可能导致抽象过度和缺乏灵活性。单例模式确保唯一实例,但应注意避免全局状态和过度使用。观察者模式实现了一对多依赖,需警惕性能影响和循环依赖。通过理解模式的优缺点,能提升代码质量。例如,工厂模式通过`createShape`函数动态创建对象;单例模式用闭包保证唯一实例;观察者模式让主题对象通知多个观察者。设计模式的恰当运用能增强代码可维护性。
81 0
|
4月前
|
设计模式 缓存 JavaScript
js设计模式实例
【7月更文挑战第2天】JavaScript设计模式包含工厂、单例、建造者、抽象工厂和代理模式等,它们是最佳实践和可重用模板,解决创建、职责分配和通信等问题。例如,工厂模式封装对象创建,单例确保全局唯一实例,建造者模式用于复杂对象构建,抽象工厂创建相关对象集合,而代理模式则控制对象访问。这些模式提升代码质量、可读性和灵活性,是高效开发的关键。
37 0