模板方法模式(Template Method)
父类中定义一组操作算法骨架,而将一些实现步骤延迟到子类中,使得子类可以不改变父类的算法结构的同时可重新定义算法中某些实现步骤。
需求:定义一个全局能用的弹出框
<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();
};
特点:
模板方法
的核心
在于对方法的重用
,它将核心方法封装在基类中
,让子类继承基类的方法
,实现基类方法的共享
,达到方法共用
。当然这种设计模式也将
导致基类控制子类必须遵守某些法则
。这是一种行为的约束
。当然为了让行为的约束更可靠
,基类中封装的方法通常是不变的算法
,或者具有稳定的调用方式
。
子类继承的方法
亦是可以扩展
的,这就要求对基类继承的方法进行重写
。当然为了更好地实践,我们通常要控制这种拓展,这样才能让基类对子类有更稳健的束缚力。然而子类对自身私有行为的拓展还是很有必要的。