JS 自定义组件
经常会用到JS插件,但从未研究过插件的写法
目前主流的写法有多种,各有各的优缺点,下面,我就以最常规的一种写法举例
// plugin.js
;(function(undefined) {//防止出现undefined问题
"use strict"
var _global; // 工具函数
// 对象合并
function extend(o,n,override) {
for(var key in n){
if(n.hasOwnProperty(key) && (!o.hasOwnProperty(key) || override)){
o[key]=n[key];
}
}
return o;
}
// 自定义模板引擎
function templateEngine(html, data) {
var re = /<%([^%>]+)?%>/g,
reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g,
code = 'var r=[];\n',
cursor = 0;
var match;
var add = function(line, js) {
js ? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') :
(code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');
return add;
}
while (match = re.exec(html)) {
add(html.slice(cursor, match.index))(match[1], true);
cursor = match.index + match[0].length;
}
add(html.substr(cursor, html.length - cursor));
code += 'return r.join("");';
return new Function(code.replace(/[\r\t\n]/g, '')).apply(data);
}
// 通过class查找dom
if(!('getElementsByClass' in HTMLElement)){
HTMLElement.prototype.getElementsByClass = function(n){
var el = [],
_el = this.getElementsByTagName('*');
for (var i=0; i<_el.length; i++ ) {
if (!!_el[i].className && (typeof _el[i].className == 'string') && _el[i].className.indexOf(n) > -1 ) {
el[el.length] = _el[i];
}
}
return el;
};
((typeof HTMLDocument !== 'undefined') ? HTMLDocument : Document).prototype.getElementsByClass = HTMLElement.prototype.getElementsByClass;
} // 插件构造函数 - 返回数组结构
function MyDialog(opt){
debugger;
this._initial(opt);
}
MyDialog.prototype = {
constructor: this,//这种原型链写法必须要加上constructor
_initial: function(opt) {
// 默认参数
var def = {
ok: true,
ok_txt: '确定',
cancel: false,
cancel_txt: '取消',
confirm: function(){},
close: function(){},
content: '',
tmpId: null
};
debugger;
this.def = extend(def,opt,true); //配置参数
this.tpl = this._parseTpl(this.def.tmpId); //模板字符串
this.dom = this._parseToDom(this.tpl)[0]; //存放在实例中的节点
this.hasDom = false; //检查dom树中dialog的节点是否存在
this.listeners = []; //自定义事件,用于监听插件的用户交互
this.handlers = {};
},
_parseTpl: function(tmpId) { // 将模板转为字符串
var data = this.def;
var tplStr = document.getElementById(tmpId).innerHTML.trim();
return templateEngine(tplStr,data);
},
_parseToDom: function(str) { // 将字符串转为dom
var div = document.createElement('div');
if(typeof str == 'string') {
div.innerHTML = str;
}
return div.childNodes;
},
show: function(callback){
var _this = this;
if(this.hasDom) return ;
debugger;
//自定义事件监听
if(this.listeners.indexOf('show') > -1) {
if(!this.emit({type:'show',target: this.dom})) return ;
}
document.body.appendChild(this.dom);
this.hasDom = true;
this.dom.getElementsByClass('close')[0].onclick = function(){
_this.hide();
if(_this.listeners.indexOf('close') > -1) {
_this.emit({type:'close',target: _this.dom})
}
!!_this.def.close && _this.def.close.call(this,_this.dom);
};
this.dom.getElementsByClass('btn-ok')[0].onclick = function(){
_this.hide();
if(_this.listeners.indexOf('confirm') > -1) {
_this.emit({type:'confirm',target: _this.dom})
}
!!_this.def.confirm && _this.def.confirm.call(this,_this.dom);
};
if(this.def.cancel){
this.dom.getElementsByClass('btn-cancel')[0].onclick = function(){
_this.hide();
if(_this.listeners.indexOf('cancel') > -1) {
_this.emit({type:'cancel',target: _this.dom})
}
};
}
callback && callback();
if(this.listeners.indexOf('shown') > -1) {
this.emit({type:'shown',target: this.dom})
}
return this;
},
hide: function(callback){
if(this.listeners.indexOf('hide') > -1) {
if(!this.emit({type:'hide',target: this.dom})) return ;
}
document.body.removeChild(this.dom);
this.hasDom = false;
callback && callback();
if(this.listeners.indexOf('hidden') > -1) {
this.emit({type:'hidden',target: this.dom})
}
return this;
},
modifyTpl: function(template){
if(!!template) {
if(typeof template == 'string'){
this.tpl = template;
} else if(typeof template == 'function'){
this.tpl = template();
} else {
return this;
}
}
this.dom = this._parseToDom(this.tpl)[0];
return this;
},
css: function(styleObj){
for(var prop in styleObj){
var attr = prop.replace(/[A-Z]/g,function(word){
return '-' + word.toLowerCase();
});
this.dom.style[attr] = styleObj[prop];
}
return this;
},
width: function(val){
this.dom.style.width = val + 'px';
return this;
},
height: function(val){
this.dom.style.height = val + 'px';
return this;
},
on: function(type, handler){
// type: show, shown, hide, hidden, close, confirm
if(typeof this.handlers[type] === 'undefined') {
this.handlers[type] = [];
}
this.listeners.push(type);
this.handlers[type].push(handler);
return this;
},
off: function(type, handler){
if(this.handlers[type] instanceof Array) {
var handlers = this.handlers[type];
for(var i = 0, len = handlers.length; i < len; i++) {
if(handlers[i] === handler) {
break;
}
}
this.listeners.splice(i, 1);
handlers.splice(i, 1);
return this;
}
},
emit: function(event){
debugger;
if(!event.target) {
event.target = this;
}
debugger;
if(this.handlers[event.type] instanceof Array) {
var handlers = this.handlers[event.type];
for(var i = 0, len = handlers.length; i < len; i++) {
handlers[i](event);
return true;
}
}
return false;
}
} // 最后将插件对象暴露给全局对象
_global = (function(){ return this || (0, eval)('this'); }());
if (typeof module !== "undefined" && module.exports) {
module.exports = MyDialog;
} else if (typeof define === "function" && define.amd) {
define(function(){return MyDialog;});
} else {
!('MyDialog' in _global) && (_global.MyDialog = MyDialog);
}
}());
调用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
<link rel="stylesheet" type="text/css" href="index.css">
</head>
<body> </body>
<script type="text/template" id="dialogTpl">
<div class="mydialog">
<span class="close">×</span>
<div class="mydialog-cont">
<div class="cont"><% this.content %></div>
</div>
<div class="footer">
<% if(this.cancel){ %>
<span class="btn btn-ok"><% this.ok_txt %></span>
<span class="btn btn-cancel"><% this.cancel_txt %></span>
<% } else{ %>
<span class="btn btn-ok" style="width: 100%"><% this.ok_txt %></span>
<% } %>
</div>
</div>
</script>
<script src="MyDialog.js" type="text/javascript"></script>
<script>
var mydialog = new MyDialog({
tmpId: 'dialogTpl',
cancel: true,
content: 'hello world!'
});
mydialog.on('confirm',function(ev){
debugger;
console.log('you click confirm!');
// 写你的确定之后的逻辑代码...
});
mydialog.show();
</script>
</html>
JS 自定义组件的更多相关文章
- vue.js自定义组件directives
自定义指令:以v开头,如:v-mybind. <input v-mybind /> directives:{ mybind:{ bind:function (el) { el.value ...
- Vue.js 自定义组件封装实录——基于现有控件的二次封装(以计时器为例)
在本人着手开发一个考试系统的过程中,出现了如下一个需求:制作一个倒计时的控件显示在试卷页面上.本文所记录的就是这样的一个过程. 前期工作 对于这个需求,自然我想到的是有没有现成的组件可以直接使用(本着 ...
- Vue结合原生js实现自定义组件自动生成
就目前三大前端主流数据驱动框架(vue,ng,react)而言,均具有创建自定义组件的api,但都是必须先做到事先写好挂载点,这个挂载点可以是原有静态元素标签也可以是自定义模板:对于多种组件通过同一数 ...
- 循序渐进BootstrapVue,开发公司门户网站(2)--- 使用wow.js动画组件以及自定义的CSS样式处理动态效果
在我们开发的页面中,让页面有一些动画效果,可以让页面更加有吸引力,只要不是处理太过,一般人还是希望有一些动态效果,如滚动动画加载,悬停处理变化等效果,本篇随笔介绍使用wow.js动画组件以及自定义的C ...
- 原生js也可以自定义组件
Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的web应用中使用它们. 它由三项主要技术组成,它们可以一起使用来创建封装功能的定制元 ...
- 为Node.js编写组件的几种方式
本文主要备忘为Node.js编写组件的三种实现:纯js实现.v8 API实现(同步&异步).借助swig框架实现. 关键字:Node.js.C++.v8.swig.异步.回调. 简介 首先介绍 ...
- PhoneGap: Android 自定义组件
Hello Core Demo Plugin Development(组件部署): http://docs.phonegap.com/en/2.0.0/guide_plugin-development ...
- iSlider手机平台JS滑动组件
iSlider手机平台JS滑动组件,无任何插件依赖.它能够处理任何元素,例如图片或者DOM元素.它有如下特性:能够自定义动画,自带的动画包括default, rotate, flip 和 depth你 ...
- vue.js自定义指令入门
Vue.js 允许你注册自定义指令,实质上是让你教 Vue 一些新技巧:怎样将数据的变化映射到 DOM 的行为.你可以使用Vue.directive(id, definition)的方法传入指令id和 ...
随机推荐
- 最新 盛天网络java校招面经 (含整理过的面试题大全)
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.盛天网络等10家互联网公司的校招Offer,因为某些自身原因最终选择了盛天网络.6.7月主要是做系统复习.项目复盘.Leet ...
- bzoj3624(Apio2008):免费道路
题目↓ Sample Input 5 7 2 1 3 0 4 5 1 3 2 0 5 3 1 4 3 0 1 2 1 4 2 1 Sample Output 3 2 0 4 3 0 5 3 1 1 2 ...
- Oracle 表的导入与导出
周末任务:将一个表从一个库导到另一个库大致思路:用expdp 将表从一个实例导出 ,再用impdp将导出的 .dmp文件导入到另一个实例1.在实例 orcl 中准备一个用于导出的表: 进入实例为orc ...
- [转帖]关于DDR4内存颗粒、单双面、主板布线和双通道的那些事儿
我们200期的期中测试大家都做了吧,今天我们放出了完整的答案,想知道自己错在哪儿的同学赶紧过去看哟=><这次期中考试你拿到满分了吗?没有就快去补习吧> https://www.exp ...
- [转帖]linux下的find文件查找命令与grep文件内容查找命令
linux下的find文件查找命令与grep文件内容查找命令 https://www.cnblogs.com/shileima/p/8431393.html 在使用linux时,经常需要进行文件查找. ...
- 一个好隐蔽的C/C++代码bug
来自:微博@ruanyf, 一本书上说,下面的 C 语言代码可能会产生无限循环.看了半天,才意识到 Bug 在哪里. 完美解答: 数组下标越界.数组a总共有10个值,a[0]~a[9].for循环里面 ...
- mysql 中表与表之间的关系
如何找出两张表的对应关系 分析步骤: 1.先找出左表的角度去找 是否左表的多条记录可以对应右表的一条记录,如果是,则证明左表的一个字段foreign key 右表一个字段 (通常是id) 2.再站 ...
- Java中自增(++)和赋值(=)运算效率比较
前言 将一个int型数组x[]从初值0变成1.有两种做法: // 只考虑后自增 int length = x.length; for (int i = 0; i < length; i++) ...
- java 字符串处理的
@Test public void testString(){ /*字符串处理 */ String email="123456789@qq.com"; System.out.pri ...
- Java Convention 公约数计算
Java Convention 公约数计算 /** * <html> * <body> * <P> Copyright 1994-2018 JasonInterna ...