实现你人生中的第一个jQuery插件

Posted 「已注销」

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现你人生中的第一个jQuery插件相关的知识,希望对你有一定的参考价值。

前言

本想把本篇取名:从0开始写前端UI框架:实现你人生中的第一个jQuery插件 ,但感觉标题太长,所以简单明了直接取后面主题为题目吧。

前一篇文章 已经对my-ui框架做了简单的介绍。谈到了我是如何想起做这个框架的,并描绘了这个框架的大致功能或者说是组件,文章最后举了个已经实现的table表格功能为例子,万里长征就从这里开始!接下来咱们就来剖析如何实现这一简单的功能了,我已经实现了一个table组件功能,也叫做插件,那么接下来你就要开始来了解什么是插件,以及如何写一个插件了。

预备知识

科普插件知识:插件(Plug-in,又称addin、add-in、addon或add-on,又译外挂)是一种遵循一定规范的应用程序接口编写出来的程序。其只能运行在程序规定的系统平台下(可能同时支持多个平台),而不能脱离指定的平台单独运行。因为插件需要调用原纯净系统提供的函数库或者数据。

简而言之,插件就是现有框架的补丁或扩展,jQuery的插件必须要依赖于jQuery库。学习插件开发之前,你最好具备以下知识:

  1. javascript面向对象思想,把这种脚本语言当成面向对象来看待。重点是提升你的JavaScript封装能力。你可以尝试封装一个带有四则运算能力的计算器对象,或者封装一个可以自由切换选项卡的对象,或者一个抽奖功能等。这里的重点是练习你的封装能力,而不是算法。
  2. 理解JavaScript中this的功能,当this处于js文件裸体内,当this处于函数内,当this处于对象内分别指向的是谁。
  3. 理解JavaScript中的原型以及原型链,搞明白对象属性和原型属性有什么区别,并且弄明白prototype关键字的用意。
  4. 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种:

  1. 第一种是工具集toolkit。就是平时开发中经常用到的代码段封装成,比如处理字符串的代码段,比如处理日期的函数,众多工具集合在一起就是一个toolkit了。
  2. 第二种是Libaray。在Vue,React以及Angluar出来之前,我们也称它们为框架,比如jQuery,BootStrap,以前我们一直以为它是一个框架,但是现在你去看它的官网,官方给它的定义是库。
  3. 第三种是Framework,比较典型就是MVVM框架,人们认为这才是真正意义上的框架。

有图有真相,jQuery官网对jQuery的定义:
Bootstrap对它自己的定义:

这一种好理解,就是工具集,关于第二种和第三种,有人总结区别如下:

库是将代码集合成的一个产品,供程序员调用。面向对象的代码组织形式而成的库也叫类库。面向过程的代码组织形式而成的库也叫函数库。

在函数库中的可直接使用的函数叫库函数。开发者在使用库的时候,只需要使用库的一部分类或函数,然后继续实现自己的功能。

框架则是为解决一个(一类)问题而开发的产品,框架用户一般只需要使用框架提供的类或函数,即可实现全部功能。可以说,框架是库的升级版。开发者在使用框架的时候,必须使用这个框架的全部代码。

框架和库的比较可以想像为:
假如我们要买一台电脑。框架为我们提供了已经装好的电脑,我们只要买回来就能用,但你必须把整个电脑买回来。这样用户自然轻松许多,但会导致
很多人用一样的电脑,或你想自定义某个部件将需要修改这个框架。而库就如自己组装的电脑。库为我们提供了很多部件,我们需要自己组装,如果某个部件
库未提供,我们也可以自己做。库的使用非常灵活,但没有框架方便。

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, indexnull,选填

开启你的编程之旅

看到这里,人生好像就有个小目标要去实现了,你要完成的工作是在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编程经验的开发者,你应该看到,这个代码段只做了两件事:

  1. ajax请求后台数据
  2. 拿到请求的数据循环遍历填充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设计中大概要求我们:

  1. 能动态接收请求数据地址url参数,必选
  2. http请求方式,可选,默认值为get
  3. 请求到的数据,可以每一列filed属性属性值填充数据
  4. 数据可能需要格式化,比如返回一个金额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以上是关于实现你人生中的第一个jQuery插件的主要内容,如果未能解决你的问题,请参考以下文章

[梁山好汉说IT] 熵的概念 & 决策树ID3如何选择子树

[梁山好汉说IT] 梁山好汉和秒杀系统

[梁山好汉说IT] 边缘计算在梁山的应用

[梁山好汉说IT] 容器概念在北宋社会的应用

[梁山好汉说IT] 以水浒传为例讲解贝叶斯定理

Java案例:正向和反向遍历单链表