js 写插件入门(弹出框)
阅读 (162) 2020-07-20 10:46:57
原生JS写插件,本例重点在于对this作用域的理解
一千个人眼中有一千个哈姆雷特,同样写插件实现具体的功能也有很多种方法,以下代码只是个人成长中的随笔
直接看样例:https://returnc.com/demo/alert.html
;(function(undefined) {
"use strict"
var _global
// 合并对象(深拷贝)
function extend(defaults, n) {
var n = n || {};
for (var x in defaults) {
// 对于使用时,没有设置的参数;用默认参数代替
if (typeof n[x] === 'undefined') {
n[x] = defaults[x];
}
}
return n
}
/*
* 监听函数
* obj 监听对象
* type 监听事件
* handle 执行函数
*/
function addEvent(obj,type,handle){
try{
obj.addEventListener(type,handle,false);
}catch(e){
try{
obj.attachEvent('on'+type,handle);
}
catch(e){
obj['on' + type]=handle;//早期浏览器
}
}
}
/* 插件函数
* 参数1:弹框标题
* 参数2:弹框内容
* 参数3:自定义配置
* 参数4:关闭前的回调函数
*/ 参数5:关闭后的回调函数
function KAlert(title, content, opt, beforeClose, afterClose){
// 未使用new关键词时
if (!(this instanceof KAlert)){
// 等于再new一个KAlert
return new KAlert(title, content, opt, beforeClose, afterClose)
}
this._initial(title, content, opt, beforeClose, afterClose)
}
KAlert.prototype = {
constructor: this,
// 插件初始化
_initial: function (title, content, opt, beforeClose, afterClose) {
// 默认配置
var defaults = {
showCancelBtn: true, // 是否显示“取消按钮”,即左侧按钮
showConfirmBtn: true, // 是否显示“确定按钮”,即右侧按钮
cancelBtnText: '取消', // 左侧按钮文字
confirmBtnText: '确定', // 右侧按钮文字
cancelBtnClassName: 'kalert-cancel-btn', // 左侧按钮样式名
confirmBtnClassName: 'kalert-confirm-btn', // 右侧按钮样式名
cancelBtnColor: '#d90000', // 左侧按钮文字默认颜色
confirmBtnColor: '#333333', // 右侧按钮文字默认颜色
title: '', // 弹框标题
content: '' // 弹框内容
}
// 没有设置的参数,使用默认值
this.opt = extend(defaults, opt) // 得到的this.opt, 在方法中调用;
this.opt.title = title || '提示' // 弹框标题
this.opt.content = content || '' // 弹框内容
this.beforeClose = beforeClose || function() {} // 设置用户回调函数:关闭前的回调事件
this.afterClose = afterClose || function() {} // 设置用户回调函数:关闭后的回调事件
// 弹框DOM元素创建
this._renderDOM()
},
// 渲染弹窗 DOM 结构
_renderDOM: function() {
// 创建元素
var alertMask = document.createElement("div")
var alertWrapper = document.createElement("div")
var alertBox = document.createElement("div")
var title = document.createElement("h3")
var content = document.createElement("div")
var footer = document.createElement("div")
var cancelBtn = document.createElement("button")
var confirmBtn = document.createElement("button")
// 样式名
alertMask.className = 'kalert-mask'
alertWrapper.className = 'kalert-wrapper'
alertBox.className = 'kalert-box'
title.className = 'kalert-title'
content.className = 'kalert-content'
footer.className = 'kalert-footer'
cancelBtn.className = this.opt.cancelBtnClassName
confirmBtn.className = this.opt.confirmBtnClassName
// 设置自定义样式
cancelBtn.setAttribute('style', 'color: ' + this.opt.cancelBtnColor);
confirmBtn.setAttribute('style', 'color: ' + this.opt.confirmBtnColor);
// 设置标题、内容、按钮
title.innerHTML = this.opt.title
content.innerHTML = this.opt.content
cancelBtn.innerHTML = this.opt.cancelBtnText
confirmBtn.innerHTML = this.opt.confirmBtnText
// 填充元素
if(this.opt.showCancelBtn) {
footer.appendChild(cancelBtn)
}
if(this.opt.showConfirmBtn) {
footer.appendChild(confirmBtn)
}
alertWrapper.appendChild(alertBox)
alertMask.appendChild(alertWrapper)
alertBox.appendChild(title)
alertBox.appendChild(content)
alertBox.appendChild(footer)
document.body.appendChild(alertMask)
// addEvent _onCancel 和 _onConfirm 方法内部的this指向了按钮对象,这里用bind重新指向到this,即 KAlert
addEvent(cancelBtn, 'click', this._onCancel.bind(this))
addEvent(confirmBtn, 'click', this._onConfirm.bind(this))
// body上加个特有样式
document.body.classList.add('kalert-show')
},
// 点击关闭按钮
_onCancel: function () {
// 如果换成箭头函数,下面用到的this则指向Kalert, 用function()则指向点击对象本身, 这里使用function提高兼容性,防止浏览器不支持ES6以上的语法
// 但在此例中在绑定监听事件后,我又修改了this指向,使这里的this又指向了Kalert
console.log(`您点击了${this.opt.cancelBtnText}按钮`)
this._close()
},
// 点击确定按钮
_onConfirm: function () {
console.log(`您点击了${this.opt.confirmBtnText}按钮`)
this._close()
},
// 关闭提示框
_close: function() {
this.beforeClose()
// 移除body上的className
document.body.classList.remove('kalert-show')
// 销毁DOM,由于直接写了指定的className,可以优化一下,在生成时,使用随机class名,销毁时不会相互影响
var kalert = document.getElementsByClassName('kalert-mask');
for(let i=0; i<kalert.length; i++){
//删除元素
if (kalert[i] != null) {
kalert[i].remove()
}
}
this.afterClose()
}
}
// 插件引用时就向head中插入样式,只加载一次
var css = (function css() {
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.innerHTML = '.kalert-mask {display: none;} .kalert-show .kalert-mask{ display: flex;align-items: center;justify-content: center; position: fixed;left: 0;top: 0;z-index:999;height: 100%;width: 100%;background: rgba(0,0,0,0.75);} .kalert-wrapper{ width: 75%;display: flex; justify-content: center; } .kalert-box{padding: 0;background: #fff;border-radius: 15px;max-width: 750px ;width: 100%;} .kalert-title{margin: 0;padding: 10px 10px 5px 10px; color: #333;font-size: 16px;text-align:center;}.kalert-content{padding: 5px 10px 10px 10px; color: #666;font-size: 14px;text-align: center;} .kalert-footer{border-top: 1px solid #eee;padding: 0;display: flex; align-items: center;justify-content: space-around;} .kalert-footer button{font-size: 12px;border: 0;border-radius: 0;box-shadow: none;background: transparent;display: block;width: 50%;padding: 10px 0;}.kalert-footer .kalert-cancel-btn{ border-right: 1px solid #eee; }';
head.appendChild(style);
})();
// 最后将插件对象暴露给全局对象
_global = (function(){ return this || (0, eval)('this'); }());
if (typeof module !== "undefined" && module.exports) {
module.exports = KAlert;
} else if (typeof define === "function" && define.amd) {
define(function(){return KAlert;});
} else {
!('KAlert' in _global) && (_global.KAlert = KAlert);
}
}());
插件使用:
<button onclick="customClick()">显示弹出框</button>
<script>
var customClick = function() {
// 参数1:弹框标题
// 参数2:弹框内容
// 参数3:自定义配置
// 参数4:关闭前的回调函数
// 参数5:关闭后的回调函数
KAlert('提示', '登录信息已过期, 请重新登录', {},
function () { // 关闭前的回调
console.log('关闭前的回调')
},
function () { // 关闭后的回调
console.log('关闭后的回调')
}
);
}
</script>
更新于:2020-07-22 10:36:36