从0开始写前端UI框架:实现你人生中的第一个jQuery插件
2020/4/20 11:18:09
本文主要是介绍从0开始写前端UI框架:实现你人生中的第一个jQuery插件,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
前一篇文章已经对my-ui框架做了简单的介绍。谈到了我是如何想起做这个框架的,并描绘了这个框架的大致功能或者说是组件,文章最后举了个已经实现的table表格功能为例子,万里长征就从这里开始!接下来咱们就来剖析如何实现这一简单的功能了,我已经实现了一个table组件功能,也叫做插件,那么接下来你就要开始来了解什么是插件,以及如何写一个插件了。
预备知识
科普插件知识:插件(Plug-in,又称addin、add-in、addon或add-on,又译外挂)是一种遵循一定规范的应用程序接口编写出来的程序。其只能运行在程序规定的系统平台下(可能同时支持多个平台),而不能脱离指定的平台单独运行。因为插件需要调用原纯净系统提供的函数库或者数据。
简而言之,插件就是现有框架的补丁或扩展,jQuery的插件必须要依赖于jQuery库。学习插件开发之前,你最好具备以下知识:
- JavaScript面向对象思想,把这种脚本语言当成面向对象来看待。重点是提升你的JavaScript封装能力。你可以尝试封装一个带有四则运算能力的计算器对象,或者封装一个可以自由切换选项卡的对象,或者一个抽奖功能等。这里的重点是练习你的封装能力,而不是算法。
- 理解JavaScript中this的功能,当this处于js文件裸体内,当this处于函数内,当this处于对象内分别指向的是谁。
- 理解JavaScript中的原型以及原型链,搞明白对象属性和原型属性有什么区别,并且弄明白prototype关键字的用意。
- JavaScript闭包和模块化编程,尤其是JavaScript为了避免变量污染如何做到隐藏对象作用域的。
嗯,上述几点我建议你在网上找找相关课程看看,或者翻阅专栏博客看看,当然了,实在找不到那翻阅我的CSDN博客看也行,不过我写的系列文章理解不深,只能作为入门级别的理解。
编写你人生的第一个jQuery插件
下面假设你已经具备上面我提到的前端编程技能了,那么接下来我们就来了解jQuery插件编程了。通过查阅jQuery帮助文档我们可以知道jQuery的插件是这样写的:
$.fn.jquery //.jquery 属性是通过 jQuery 原型赋值的,通过使用它的别名 $.fn 进行引用。 复制代码
上诉语法将属性注册到jQuery对象原型上,这里多说一句的是:jQuery本身是一个对象,属于一个大的Ojbect。现在我想在这个大型的Object上面实现自己的方法,例子如下:
$.fn.extend({ "bold": function () { // 加粗字体 return this.css({ fontWeight: "bold" }); } }); 复制代码
这时候jQuery对象就具备了一个叫做bold的属性,这个属性是一个函数。这时候jQuery的原有功能不变,额外多出了bold()函数,这个函数只实现一个功能:字体加粗。别着急运行上述代码,一般来说为了避免变量污染,我们会将上述代码放在一个匿名函数里面:
(function ($) { $.fn.extend({ "bold": function () { /// 加粗字体 return this.css({ fontWeight: "bold" }); } }); })(jQuery); 复制代码
上述代码体现了JavaScript的闭包,首先定义了一个匿名函数,并且使用(jQuery)立刻调用它,并且传递进去jQuery对象,也就是那个$对象,匿名函数的内容我就不赘述了。接下来咱就可以调用这个咱基于jQuery扩展出来的方法了。
$(function() { $('#div').bold(); }); 复制代码
上述语法你应该很熟悉,就是jQuery的标准调用语法,只不过此刻jQuery多了个bold()函数功能摆了。
亲自试一试上述例子哦!
怎么样?你人生的第一个jQuery插件就这样开发出来了,这个功能虽然很简单,它利用jQuery原有的选择器语法选择出你想要的元素,然后再链式调用,将之前选中的元素传递给你的bold()函数。至于这个函数实现怎么样的内容,那是你说了算哦,这里想要注意的是你必须注意那个this指的是谁。
实现my-ui的table组件
既然你已经开发出了人生的第一款jQuery插件了,那么我们继续吧。
框架区别
有人说,框架分3种:
- 第一种是工具集toolkit。就是平时开发中经常用到的代码段封装成,比如处理字符串的代码段,比如处理日期的函数,众多工具集合在一起就是一个toolkit了。
- 第二种是Libaray。在Vue,React以及Angluar出来之前,我们也称它们为框架,比如jQuery,BootStrap,以前我们一直以为它是一个框架,但是现在你去看它的官网,官方给它的定义是库。
- 第三种是Framework,比较典型就是MVVM框架,人们认为这才是真正意义上的框架。
这一种好理解,就是工具集,关于第二种和第三种,有人总结区别如下:
库是将代码集合成的一个产品,供程序员调用。面向对象的代码组织形式而成的库也叫类库。面向过程的代码组织形式而成的库也叫函数库。 在函数库中的可直接使用的函数叫库函数。开发者在使用库的时候,只需要使用库的一部分类或函数,然后继续实现自己的功能。 框架则是为解决一个(一类)问题而开发的产品,框架用户一般只需要使用框架提供的类或函数,即可实现全部功能。可以说,框架是库的升级版。 开发者在使用框架的时候,必须使用这个框架的全部代码。 框架和库的比较可以想像为: 假如我们要买一台电脑。框架为我们提供了已经装好的电脑,我们只要买回来就能用,但你必须把整个电脑买回来。这样用户自然轻松许多,但会导致 很多人用一样的电脑,或你想自定义某个部件将需要修改这个框架。而库就如自己组装的电脑。库为我们提供了很多部件,我们需要自己组装,如果某个部件 库未提供,我们也可以自己做。库的使用非常灵活,但没有框架方便。
api设计
上述已经讲述了框架之前的区别,我们要实现的框架属于是第二种:Libaray。
我对my-ui的定位是:基于jQuery扩展实现的前端UI框架,封装统一API调用风格,汇聚众家优秀框架以及插件之所长,借鉴了easyui api设计风格,bootsrap的样式,追求视角完美的前端框架。
那么接下来第一步就是来设计api了,虽然我还未具备设计整个框架的能力,但是仿造easyui先设计table组件是没问题的。下面是我借鉴的easyui的api,如下:
table属性
属性名 | 数据类型 | 备注 | 默认值 |
---|---|---|---|
url | 字符串 | table表格请求后台的url地址 | null,必填 |
method | 字符串 | http请求方式,支持5种请求方式[get, post, put, delete, head] | get,选填 |
函数名 | 函数 | 向组件种注册函数,一般在formatter属性中指定到该函数名,否则不会被调用 | null,选填 |
列属性
属性名 | 数据类型 | 备注 | 默认值 |
---|---|---|---|
field | 字符串 | 从后台请求到的数据列表元素的属性名 | null,必填 |
formatter | 字符串 | 数据格式化形式,框架提供了[number, date-box]类型,需要额外定义格式逻辑可指定回调函数名,调用回调函数时传递的参数列表分别是:value, row, index | null,选填 |
开启你的编程之旅
看到这里,人生好像就有个小目标要去实现了,你要完成的工作是在jQuery对象上再添加原型对象和属性,来处理一个table表格,这个原型对象能接收url,medhod以及函数等参数,并且能去扫描页面中表格每一列的属性,生成一个table表格。接下来咱要编程实现这个功能。
假设抛开什么jQuery原型对象,什么抽象,封装,什么闭包,就是用jQuery来实现一个简单的表格,你是如何做的?我思考许久之后,我是这么做的。
1.定义table用到的css样式:
/** * myui-table表格定义样式 */ @charset "UTF-8"; caption { caption-side: top; text-align:left; padding: .5em; color: black; font-weight: bold; font-size: 15px; } .myui-table { width: 99%; border-collapse: collapse; margin: 3px; font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; } .myui-table td, .myui-table th { font-size: 1em; border: 2px solid rgba(255, 255, 255, 1); padding: 3px 3px 2px 3px; text-align: center; } .myui-table th { height: 45px; font-size: 1.1em; padding-top: 5px; padding-bottom: 4px; background-color: #4fa6db; color: #ffffff; } .myui-table tbody tr:nth-child(even) td { background-color:#f9f9f9; height: 28px; } .myui-table tbody tr:nth-child(odd) td { background-color:#eeeeee; height: 28px; } 复制代码
2.在html页面中定义table元素
<table id="table" class="myui-table"> <caption>梁山好汉排名</caption> <tbody><tr> <th style="height: 5px;" field="index">座次</th> <th style="height: 5px;" field="name">原名</th> <th style="height: 5px;" field="nickName">昵称</th> <th style="height: 5px;" field="constellation">星宿</th> <th style="height: 5px;" field="birthDay" formatter="daily-date">生日</th> <th style="height: 5px;" field="sex" formatter="sexFormatter">性别</th> <th style="height: 5px;" field="effectiveness" formatter="number">战斗指数</th> <th style="height: 5px;" field="specialSkills">特殊技能</th> <th style="height: 5px;" field="remark">备注</th> </tr> <tr><td>1</td><td>宋江</td><td>呼保义</td><td>天魁星</td><td>1995-01-01</td><td>男</td><td>4.12</td><td>忠义双全</td><td>梁山好汉大BOOS</td></tr><tr><td>2</td><td>卢俊义</td><td>玉麒麟</td><td>天罡星</td><td>1996-02-01</td><td>男</td><td>4.32</td><td>替天行道</td><td>梁山No.2人物</td></tr><tr><td>3</td><td>吴用</td><td>星智多星</td><td>天机星</td><td>2000-01-01</td><td>男</td><td>5.00</td><td>锦囊妙计</td><td>我军及友军精神力上升</td></tr><tr><td>4</td><td>公孙胜</td><td>入云龙</td><td>天闲星</td><td>2001-01-01</td><td>男</td><td>4.31</td><td>五雷天罡正版法</td><td>区域内敌人禁咒</td></tr><tr><td>5</td><td>孙二娘</td><td>母夜叉</td><td>地壮星</td><td>1999-01-01</td><td>女</td><td>2.56</td><td>未知</td><td>地壮星母夜叉孙二娘</td></tr><tr><td>6</td><td>景住</td><td>金毛犬</td><td>地狗星</td><td>1996-01-01</td><td>女</td><td>2.12</td><td>判官笔</td><td>梁山好汉第108位好汉</td></tr></tbody></table> 复制代码
这样子你的页面展示如下:
函数级别的封装
上面已经页面效果渲染出来了,接下来你应该很快想到最简单级别,函数级别的封装了。你要将上诉代码封装在一个JavaScript函数里面,table body元素是动态生成出来的。那么接下来你的代码就变成这样子了:
html代码
<table id="table" class="myui-table"> <caption>梁山好汉排名</caption> <tr> <th style="height: 5px;" >座次</th> <th style="height: 5px;" >原名</th> <th style="height: 5px;" >昵称</th> <th style="height: 5px;" >星宿</th> <th style="height: 5px;" >生日</th> <th style="height: 5px;" >性别</th> <th style="height: 5px;" >战斗指数</th> <th style="height: 5px;" >特殊技能</th> <th style="height: 5px;" >备注</th> </tr> </table> 复制代码
这时候你需要写一个JavaScript代码段处理这个表格如下:
$.ajax({ type: 'get', dataType: "json", url: 'xxx/xxx/xxx' success: function (data) { var table = $("#table"); if (data.length > 0) { var html = ""; for (var i = 0; i < data.length; i++) { html += "<tr>" + "<td>" + data[i].字段名1 + "</td>" + "<td>" + data[i].字段名2 + "</td>" + "<td>" + data[i].字段名3+ "</td>" + "<td>" + data[i].字段名4 + "</td>" + ...... "<td>" + data[i].字段名9 + "</td>" + "</tr>"; } $(html).appendTo(table); } } }); 复制代码
如果你是有jQuery编程经验的开发者,你应该看到,这个代码段只做了两件事:
- ajax请求后台数据
- 拿到请求的数据循环遍历填充table表格
插件级别的封装
如果你感觉上诉代码没问题了,并且我相信你很轻松的看出我是怎么实现的,并且你实现的会更好。那么咱可以继续下去了,接下来就是插件级别的封装。
回顾本篇开头第2小节提到的jQuery插件开发,咱得把这段代码逻辑注册到jQuery对象原型上去。封装的代码如下:
(function($) { //定义全局变量 var url = ""; var method = "GET"; // plugin definition $.fn.table = function(options) { url = options.url ||''; method = options.method || "GET"; // $.ajax({ url: url, method: method, success:function (response, index) { //上诉ajax响应体里面的代码 } }); }; // ... })(jQuery); 复制代码
此时调用该插件的代码改为
$('#table').table({ url : './table_data.json', }); 复制代码
如果你已经具JavaScript对象知识,不难看到,我的table组件传过去一个字面量Object对象,对象就一个属性:url,属性值.是一个json串的url地址。而插件的构造函数中有一个options变量,可以接收Object对象,这样的好处就是参数传递很容易扩展。
api完整实现
Ok,到此可以完全来实现设计的api需求了,那个api设计中大概要求我们:
- 能动态接收请求数据地址url参数,必选
- http请求方式,可选,默认值为get
- 请求到的数据,可以每一列filed属性属性值填充数据
- 数据可能需要格式化,比如返回一个金额123.456,用户可能只需要展示12.34。比如返回性别可能是true/alse,但是展示的时候是男/女等
完整的代码如下
(function($) { // plugin definition $.fn.table = function(options) { //放弃全局变量定义的用法,避免一个页面引用两次插件数据冲突 this.url = options.url ||''; this.method = options.method || "GET"; this.dataOptions = []; this.datas = []; this.options = options || {}; var _this = this; //遍历thread的所有tr,只取带有field的列 var theads = $(this).find("tr"); $(theads).each(function(index, trObject) { $(trObject).children().each(function(index, tdObject) { if(typeof($(tdObject).attr("field")) != "undefined") { var ojbect = {}; ojbect.field = $(tdObject).attr("field"); ojbect.formatter = $(tdObject).attr("formatter"); _this.dataOptions.push(ojbect); } }); }); //请求数据 $.ajax({ url : this.url, method : this.method, success:function (response, index) { $.each(response, function(index, value) { _this.datas.push(value); }); var table = _this[0]; var html = getHtml(_this.datas, _this.dataOptions, _this.options); $(html).appendTo(table); } }); }; // 计算table的html元素 function getHtml(datas, dataOptions, options) { var html = ""; //双重for循环变量属性和值 $(datas).each(function(index, value){ html += "<tr>"; $(dataOptions).each(function (index1, value1) { if(value1.field === 'index') { //处理序号 html += "<td>" + formatter(index+1, null) +"</td>"; } else if(options.hasOwnProperty(value1.formatter) && typeof options[value1.formatter] === 'function') { //处理回调函数 //调用回调函数,并返回值 var result = options[value1.formatter].call(this, value[value1.field], value, index); html += "<td>" + result +"</td>"; } else { //处理其他类型 html += "<td>" + formatter(value[value1.field], value1.formatter) +"</td>"; } }); html += "</tr>"; }); return html; }; //格式化数据 function formatter(value, formt) { if(undefined != formt && value != null) { switch(formt) { case 'number': value = value.toFixed(2); break; case 'daily-date': '2020-01-01' break; default: value = value; } } return value; } // ... })(jQuery); 复制代码
上诉代码已经完全实现了api的基本功能,此可你可以把代码段放到单独的js文件中去了,此时调用插件的代码变为:
$('#table').table({ url : './table_data.json', sexFormatter : function (value, row, index) { //性别格式化回调函数 if(value) { return "男"; } else if(!value) { return "女"; } return value; } }); 复制代码
到此,我人生的第一款jQuery插件已经开发出来了,并且已经托管到github上面去了,如果你在动手试验过程中有问题或者想运行现成的案例,可以直接访问我的项目地址download源码来直接运行观看效果哦!
这篇关于从0开始写前端UI框架:实现你人生中的第一个jQuery插件的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-03-06jquery对css样式(jquery中的css方法)-icode9专业技术文章分享
- 2023-05-27JQuery的认识和安装
- 2023-01-06JQuery应用技巧:如何定义 HTML 模板并使用 JQuery 进行加载-icode9专业技术文章分享
- 2022-09-29复习-jQuery
- 2022-09-04Python3项目初始化10-->前端基础jquery、ajax,sweetalert--更新用户改造
- 2022-08-30day 27 jquery
- 2022-08-29jQuery筛选器,bootstrap
- 2022-08-20JQuery事件绑定
- 2022-08-20JQuery案例
- 2022-08-07关于jQuery的学习