利用不到200行代码写一款属于你自己的js类库


Posted in Javascript onJuly 08, 2019

前言

JavaScript 的核心是支持面向对象的,同时它也提供了强大灵活的 OOP 语言能力。本文将使用面向对象的方式,来教大家用原生js写出一个类似jQuery这样的类库。我们将会学到如下知识点:

  • 闭包:减少变量污染,缩短变量查找范围
  • 自执行函数在对象中的运用
  • extend的实现原理
  • 如何实现跨浏览器的事件监听
  • 原型链与继承

接下来我会对类库的核心api进行讲解和展示,文章最后后附带类库的完整源码,在我之前的文章《3分钟教你用原生js实现具有进度监听的文件上传预览组件》中也使用了类似的方式,感兴趣的可以一起学习,交流。

更加完整的类库地址,请移步github《Xuery——仿jquery API风格的轻量级可扩展的原生js框架》(本地下载)

类库设计思路

利用不到200行代码写一款属于你自己的js类库

API介绍和效果展示

1、事件绑定 Xuery.on(eventName, fn)案例如下:

Xuery('#demo').on('click', function(e){
 alert('hello world!')
})

2、访问和设置css Xuery.css(string|object, ?[string])案例如下:

// 访问css
Xuery('#demo').css('width')
// 设置css
Xuery('#demo').css('width', '1024px')
// 设置css
Xuery('#demo').css({
 width: '1024px',
 height: '1024px'
})

3、访问和设置属性 Xuery.attr(string|object, ?[string])案例如下:

// 访问attr
Xuery('#demo').attr('title')
// 设置attr
Xuery('#demo').attr('title', '1024px')
// 设置attrs
Xuery('#demo').attr({
 title: '1024px',
 name: '1024px'
})

4、访问和设置html案例如下:

// 访问
Xuery('#demo').html()
// 设置
Xuery('#demo').html('前端学习原生框架')

还有其他几个常用的API在这里就不介绍了,大家可以在我的github上查看,或者基于这套基础框架,去扩展属于自己的js框架。

核心源码

以下源码相关功能我做了注释,建议大家认真阅读,涉及到原型链和构造函数的指向的问题,是实现上述调用方式的核心,又不懂可以在评论区交流沟通。

/**
 * 链模式实现自己的js类库
 */
(function(win, doc){
 var Xuery = function(selector, context) {
  return new Xuery.fn.init(selector, context)
 };

 Xuery.fn = Xuery.prototype = {
 constructor: Xuery,
 init: function(selector, context) {
  // 设置元素长度
  this.length = 0;
  // 默认获取元素的上下文document
  context = context || document;
  // id选择符,则按位非将-1转化为0
  if(~selector.indexOf('#')) {
  this[0] = document.getElementById(selector.slice(1));
  this.length = 1;
  }else{
  // 在上下文中选择元素
  var doms = context.getElementsByTagName(selector),
  i = 0,
  len = doms.length;
  for(; i<len; i++){
   this[i] = doms[i];
  }
  }
  this.context = context;
  this.selector = selector;
  return this
 },
 // 增强数组
 push: [].push,
 sort: [].sort,
 splice: [].splice
 };

 // 方法扩展
 Xuery.extend = Xuery.fn.extend = function(){
 // 扩展对象从第二个参数算起
 var i = 1,
 len = arguments.length,
 target = arguments[0],
 j;
 if(i === len){
  target = this;
  i--;
 }
 // 将参数对象合并到target
 for(; i<len; i++){
  for(j in arguments[i]){
  target[j] = arguments[i][j];
  }
 }
 return target
 }

 // 扩展事件方法
 Xuery.fn.extend({
 on: (function(){
  if(document.addEventListener){
  return function(type, fn){
   var i = this.length -1;
   for(; i>=0;i--){
   this[i].addEventListener(type, fn, false)
   }
   return this
  }
  // ie浏览器dom2级事件
  }else if(document.attachEvent){
  return function(type, fn){
   var i = this.length -1;
   for(; i>=0;i--){
   this[i].addEvent('on'+type, fn)
   }
   return this
  }
  // 不支持dom2的浏览器
  }else{
  return function(type, fn){
   var i = this.length -1;
   for(; i>=0;i--){
   this[i]['on'+type] = fn;
   }
   return this
  }
  }
 })()
 })

 // 将‘-'分割线转换为驼峰式
 Xuery.extend({
 camelCase: function(str){
  return str.replace(/\-(\w)/g, function(all, letter){
  return letter.toUpperCase();
  })
 }
 })

 // 设置css
 Xuery.extend({
 css: function(){
  var arg = arguments,
  len = arg.length;
  if(this.length < 1){
  return this
  }
  if(len === 1) {
  if(typeof arg[0] === 'string') {
   if(this[0].currentStyle){
   return this[0].currentStyle[arg[0]];
   }else{
   return getComputedStyle(this[0], false)[arg[0]]
   }
  }else if(typeof arg[0] === 'object'){
   for(var i in arg[0]){
   for(var j=this.length -1; j>=0; j--){
    this[j].style[Xuery.camelCase(i)] = arg[0][i];
   }
   }
  }
  }else if(len === 2){
  for(var j=this.length -1; j>=0; j--){
   this[j].style[Xuery.camelCase(arg[0])] = arg[1];
  }
  }
  return this
 }
 })

 // 设置属性
 Xuery.extend({
 attr: function(){
  var arg = arguments,
  len = arg.length;
  if(len <1){
  return this
  }
  if(len === 1){
  if(typeof arg[0] === 'string'){
   return this[0].getAttribute(arg[0])
  }else if(typeof arg[0] === 'object'){
   for(var i in arg[0]){
   for(var j=this.length -1; j>= 0; j--){
    this[j].setAttribute(i, arg[0][i])
   }
   }
  }
  }
  else if(len === 2){
  for(var j=this.length -1; j>=0; j--){
   this[j].setAttribute(arg[0], arg[1]);
  }
  }
  return this
 }
 })

 // 获取或者设置元素内容
 Xuery.fn.extend({
 html: function(){
  var arg = arguments,
  len = arg.length;
  if(len === 0){
  return this[0] && this[0].innerHTML
  }else{
  for(var i=this.length -1; i>=0; i--){
   this[i].innerHTML = arg[0];
  }
  }
  return this
 }
 })

 Xuery.fn.init.prototype = Xuery.fn;
 window.Xuery = Xuery;
})(window, document);

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
Webkit的跨域安全问题说明
Sep 13 Javascript
游览器中javascript的执行过程(图文)
May 20 Javascript
JS判断不同分辨率调用不同的CSS样式文件实现思路及测试代码
Jan 23 Javascript
判断一个对象是否为jquery对象的方法
Mar 12 Javascript
JavaScript控制各种浏览器全屏模式的方法、属性和事件介绍
Apr 03 Javascript
深入探密Javascript数组方法
Jan 08 Javascript
基于jquery实现鼠标左右拖动滑块滑动附源码下载
Dec 23 Javascript
自学实现angularjs依赖注入
Dec 20 Javascript
在Vue methods中调用filters里的过滤器实例
Aug 30 Javascript
vue cli使用融云实现聊天功能的实例代码
Apr 19 Javascript
vue登录页实现使用cookie记住7天密码功能的方法
Feb 18 Vue.js
JavaScript实现复选框全选功能
Apr 11 Javascript
Vue中util的工具函数实例详解
Jul 08 #Javascript
详解基于 Node.js 的轻量级云函数功能实现
Jul 08 #Javascript
使用 node.js 模仿 Apache 小部分功能
Jul 07 #Javascript
echarts统计x轴区间的数值实例代码详解
Jul 07 #Javascript
vue + typescript + video.js实现 流媒体播放 视频监控功能
Jul 07 #Javascript
详解django模板与vue.js冲突问题
Jul 07 #Javascript
django中使用vue.js的要点总结
Jul 07 #Javascript
You might like
利用php来自动调用不同服务器上的flash
2006/10/09 PHP
比较discuz和ecshop的截取字符串函数php版
2012/09/03 PHP
PHP-redis中文文档介绍
2013/02/07 PHP
PHP数组操作实例分析【添加,删除,计算,反转,排序,查找等】
2016/12/24 PHP
JavaScript定义类或函数的几种方式小结
2011/01/09 Javascript
jQuery的context属性用法实例
2014/12/27 Javascript
jQuery获取标签文本内容和html内容的方法
2015/03/27 Javascript
探讨跨域请求资源的几种方式(总结)
2016/12/02 Javascript
详解js的事件处理函数和动态创建html标记方法
2016/12/16 Javascript
jQuery、zepto、js常用小技巧
2017/02/12 Javascript
详解vue数据渲染出现闪烁问题
2017/06/29 Javascript
vue-cli3全面配置详解
2018/11/14 Javascript
详解Vue基于vue-quill-editor富文本编辑器使用心得
2019/01/03 Javascript
详解JavaScript原生封装ajax请求和Jquery中的ajax请求
2019/02/14 jQuery
详解vue 不同环境配置不同的打包命令
2019/04/07 Javascript
js中数组常用方法总结(推荐)
2019/04/09 Javascript
基于vue开发微信小程序mpvue-docs跳转页面功能
2019/04/10 Javascript
探究一道价值25k的蚂蚁金服异步串行面试题
2020/08/21 Javascript
Python 过滤字符串的技巧,map与itertools.imap
2008/09/06 Python
Python标准库之多进程(multiprocessing包)介绍
2014/11/25 Python
Python实现基于权重的随机数2种方法
2015/04/28 Python
用Python计算三角函数之acos()方法的使用
2015/05/15 Python
python3+PyQt5实现柱状图
2018/04/24 Python
python对list中的每个元素进行某种操作的方法
2018/06/29 Python
python3 爬取图片的实例代码
2018/11/06 Python
详解用python写网络爬虫-爬取新浪微博评论
2019/05/10 Python
ML神器:sklearn的快速使用及入门
2019/07/11 Python
Python人工智能之路 之PyAudio 实现录音 自动化交互实现问答
2019/08/13 Python
Python在OpenCV里实现极坐标变换功能
2019/09/02 Python
解决ROC曲线画出来只有一个点的问题
2020/02/28 Python
静态变量和实例变量的区别
2015/07/07 面试题
数学国培研修感言
2014/02/13 职场文书
银行求职信范文
2014/05/26 职场文书
学生安全责任协议书
2016/03/22 职场文书
大学生创业,为什么都会选择快餐饮?
2019/08/08 职场文书
vue项目打包后路由错误的解决方法
2022/04/13 Vue.js