JavaScript插件化开发教程 (三)


Posted in Javascript onJanuary 27, 2015

一,开篇分析

前面两篇文章我们主要讲述了以“jQuery的方式如何开发插件”,以及过程化设计与面向对象思想设计相结合的方式是

如何设计一个插件的,两种方式各有利弊取长补短,本系列文章是以学习为导向的,具体场景大家自己定夺使用方式。那么今天从这篇文章开始,我们就以实例的方式带着大家由浅入深的开发属于自己的插件库。嘿嘿嘿,废话少说,进入正题。直接上实际效果图:

JavaScript插件化开发教程 (三)

大家看到了吧,这是一个选项卡插件,在我们日常做那种单页应用("SPA")的时候或许会接触到,就拿今天的例子来说吧,

我们做一个基于BS结构的系统,会有若干模块组成,它们是构建系统的全部组成,通过这个插件我们可以有效地管理我们模块

的体验形式以及用户可交互性,下面就具体分析一下吧。

(二),实例分析

(1),首先确定这个插件做什么事。下面看一下插件的调用方式,以及配置参数说明。如下代码:

 bigbear.ui.createTab($("#tab"),{

     buttonText : "添加模块" ,

     result : [ 

         {

             text : "向导提示" ,

             url : "help.html" ,

             showClose : "0" ,

             status : "1"

         } ,

         {

             text : "学生信息" ,

             url : "info.html" ,

             showClose : "1" ,

             status : "1"

         } ,

         {

             text : "学生分类" ,

             url : "category.html" ,

             showClose : "1" ,

             status : "1"

         } ,

         {

             text : "大熊君{{bb}}" ,

             url : "bb.html" ,

             showClose : "1" ,

             status : "1"

         } ,

         {

             text : "Beta测试模块" ,

             url : "test.html" ,

             showClose : "1" ,

             status : "1"

         }

     ]

 }) ;

“bigbear.ui.createTab”里面包含两个参数,第一个是dom节点对象,第二个是插件参数选项,"buttonText "代表“Tab“插件中,操作按钮的文字描述。

”result“是一个数组,里面包含的是选项卡项目的属性,包括文字描述,点击选项卡项目时做请求使用的url,”showClose“代表选项卡的选项是否显示关闭按钮。

”status“代表选项的状态,默认为打开状态,可能会有关闭状态,分别表示为:1-打开,0-关闭。

(2),所涉的功能有哪些

通过可选参数,动态生成相关选项条目,如下来个例子:

bigbear.ui.createTab($("#tab"),{

    buttonText : "添加模块" ,

    result : [ 

        {

            text : "jQuery源码分析" ,

            url : "help.html" ,

            showClose : "0" ,

            status : "1"

        } ,

        {

            text : "大熊君{{bb}}}" ,

            url : "bb.html" ,

            showClose : "1" ,

            status : "1"

        }

    ]

}) ;

效果如下所示:

JavaScript插件化开发教程 (三)

可自由添加以及删除条目选项,如下效果所示:

JavaScript插件化开发教程 (三)

上图为其中一种情况,无模块的时候,会提示信息。

JavaScript插件化开发教程 (三)

这是第二种情况,之前删除的可以恢复。

(三),完整代码以供学习,本代码已经过测试,包括目录结构以及相关的文件。

(1),html

<body>

        <div class="dxj-ui-hd">

            大熊君{{bb}} - DXJ UI ------ Tab

        </div>

        <div class="dxj-ui-bd">

            <div id="tab">

                <div class="title">

                    <div class="adder">

                        + 添加学生信息

                    </div>

                    <div class="items">

                        <!--<div><span class="del">X</span>欢迎页</div>

                        <div><span class="del">X</span>用户管理</div>

                        <div><span class="del">X</span>Bigbear</div>-->

                    </div>

                </div>

                <div class="console-panel">

                </div>

                <div class="content">

                    <!--<div class="c">

                        <div class="input-content"><span>姓名:</span><input type="text" /></div>

                        <div class="input-content"><span>备注:</span><textarea></textarea></div>

                    </div>    <div class="input-content"><input type="button" value="保存" /></div>

                    -->

                </div>

            </div>

        </div>

    </body>

(2),css文件代码

.dxj-ui-hd {

    padding:0px ;

    margin : 0 auto;

    margin-top:30px;

    width:780px;

    height:60px;

    line-height: 60px;

    background: #3385ff;

    color:#fff;

    font-family: "微软雅黑" ;

    font-size: 28px;

    text-align: center;

    font-weight:bold;

}

.dxj-ui-bd {

    padding:0px ;

    margin : 0 auto;

    width:778px;

    padding-top : 30px ;

    padding-bottom : 30px ;

    overflow: hidden;

    border:1px solid #3385ff;

}

.dxj-ui-bd #tab {

    padding:0px ;

    margin : 0 auto;

    width:720px;

    overflow: hidden;

}

.dxj-ui-bd #tab .title {

    width:720px;

    overflow: hidden;

    border-bottom:2px solid #3385ff;

}

.dxj-ui-bd #tab .title .adder {

    width:160px;

    height:32px;

    line-height: 32px;

    background: #DC143C;

    color:#fff;

    font-family: "微软雅黑" ;

    font-size: 14px;

    text-align: center;

    font-weight:bold;

    float : left;

    cursor:pointer;

}

.dxj-ui-bd #tab .title .items {

    height:32px;

    margin-left:20px;

    width:540px;

    overflow: hidden;

    float : left;

}

.dxj-ui-bd #tab .title .items div {

    padding:0px;

    margin-left:10px;

    width:96px;

    height:32px;

    line-height: 32px;

    background: #3385ff;

    color:#fff;

    font-family: arial ;

    font-size: 12px;

    text-align: center;

    position:relative;

    float : left;

    cursor:pointer;

}

.dxj-ui-bd #tab .title .items div span.del {

    width:16px;

    height:16px;

    line-height: 16px;

    display:block;

    background: #DC143C;

    position:absolute;

    right:0 ;

    top:0;

    cursor:pointer;

}

.dxj-ui-bd #tab .content {

    width:716px;

    padding-top:30px;

    overflow: hidden;

    border:2px solid #3385ff;

    border-top:0px;

    min-height:130px;

    text-align:center;

}

.dxj-ui-bd #tab .content table {

    margin : 0 auto ;

}

.dxj-ui-bd #tab .content div.c {

    padding-top : 20px ;

    padding-left:20px;

    background:#eee;

    height:140px;

}

.dxj-ui-bd #tab .content div.c .input-content {

    margin-top : 10px ;

    font-family: arial ;

    font-size: 12px;

}

.dxj-ui-bd #tab .console-panel {

    width:716px;

    padding-top:20px;

    padding-bottom:20px;

    overflow: hidden;

    border:2px solid #3385ff;

    border-top:0px;

    border-bottom:2px solid #3385ff;

    background:#fff;

    display:none;

}

.active {

    font-weight:bold ;

}

(3),Js代码如下:

$(function(){

    bigbear.ui.createTab($("#tab"),{

        buttonText : "添加模块" ,

        result : [ 

            {

                text : "向导提示" ,

                url : "help.html" ,

                showClose : "0" ,

                status : "1"

            } ,

            {

                text : "学生信息" ,

                url : "info.html" ,

                showClose : "1" ,

                status : "1"

            } ,

            {

                text : "学生分类" ,

                url : "category.html" ,

                showClose : "1" ,

                status : "1"

            } ,

            {

                text : "大熊君{{bb}}" ,

                url : "bb.html" ,

                showClose : "1" ,

                status : "1"

            } ,

            {

                text : "Beta测试模块" ,

                url : "test.html" ,

                showClose : "1" ,

                status : "1"

            }

        ]

    }) ;

}) ;

(function($){

    var win = window ;

    var bb = win.bigbear = win.bigbear || {

        ui : {}

    } ;

    var ui = bb.ui = {} ;

    var Tab = function(elem,opts){

        this.elem = elem ;

        this.opts = opts ;

    } ;

    var tabProto = Tab.prototype ;

    tabProto._deleteItem = function(item){

        var that = this ;

        this.getElem().find(".title .items div")

        .eq(item["index"])

        .fadeOut(function(){

            that._resetContent() ;

            that._updateStatus(item) ;

            that._triggerItem(item["index"] + 1) ;

            that.getElem().find(".title .adder").trigger("click") ;

        }) ;

    } ;

    tabProto._triggerItem = function(next){

        var nextStatus = this._getStatus(next) ;

        var items = this.getElem().find(".title .items div") ;

        next = items.eq(next) ;

        if(next.size() && "1" == nextStatus){ //后继dom节点存在

            next.trigger("click") ;

        }

        else{

            items.eq(0).trigger("click") ;

        }

    } ;

    tabProto._getStatus = function(index){

        var status = "" ;

        $.each(this.getOpts()["result"],function(i,item){

            if(index == item["index"]){

                status += item["status"] ;

                return false ;

            }

        }) ;

        return status ;

    } ;

    tabProto._updateStatus = function(item){

        var status = item["status"] ;

        item["status"] = ("1" == status) ? "0" : "1" ;

    } ;

    tabProto.init = function(){

        var that = this ;

        this.getElem().find(".title .adder")

        .text("+" + this.getOpts()["buttonText"])

        .on("click",function(){

            that._toggleConsolePanel(function(){

                var root = that.getElem().find(".console-panel").empty() ;

                $.each(that.getOpts()["result"],function(i,item){

                    if("0" == item["status"]){

                        var elem = $("<div style='float:left';></div>")

                        .data("item",item)

                        .appendTo(root) ;

                        $("<input type='radio' name='addmod' />").appendTo(elem) ;

                        $("<span></span>").text(item["text"]).appendTo(elem) ;

                    }

                }) ;

                if(root.find("div").size()){

                    $("<input type='button' value='添加模块' style='margin-left:20px'/>")

                    .on("click",function(){

                        var data = root.find("input[type=radio]:checked").parent().data("item") ;

                        that._updateStatus(data) ;

                        that.getElem().find(".title .items div").eq(data["index"]).fadeIn().trigger("click") ;

                        that.getElem().find(".title .adder").trigger("click") ;

                    })

                    .appendTo(root) ;

                }

                else{

                    root.text("暂无任何可添加的项目!") ;

                }

            }) ;

        }) ;

        $.each(this.getOpts()["result"],function(i,item){

            item["index"] = i ;

            that._render(item) ;

        }) ;

        this.getElem().find(".title .items div")

        .eq(0)

        .trigger("click") ; // 假定是必须有一项,否则插件意义就不大了!

    } ;

    tabProto._toggleConsolePanel = function(callback){

        this.getElem().find(".console-panel").slideToggle(function(){

            $.isFunction(callback) && callback() ;

        }) ;

    } ;

    tabProto._resetContent = function(){

        this.getElem().find(".content").html("") ;

    } ;

    tabProto._setContent = function(html){

        this.getElem().find(".content").html(html) ;

    } ;

    tabProto._getContent = function(url){

        return $.ajax({

            url : url

        }) ;

    } ;

    tabProto._render = function(data){

        var that = this ;

        var item = $("<div></div>")

        .text(data["text"])

        .on("click",function(){

            that._setCurrent(data["index"]) ;

            that._getContent(data["url"]).done(function(result){

                that._setContent(result) ;

            })

            .fail(function(){

                throw new Error("Net Error !") ;

            });

        })

        .appendTo(this.getElem().find(".title .items")) ;

        if("1" == data["showClose"]){

            $("<span class='del'>X</span>")

            .on("click",function(){

                if(win.confirm("是否删除此项?")){

                    that._deleteItem(data) ;

                    return false ; // 阻止冒泡

                }

            })

            .appendTo(item) ;

        } 

    } ;

    tabProto._setCurrent = function(index){

        var items = this.getElem().find(".title .items div").removeClass("active") ;

        items.eq(index).addClass("active") ;

        var contents = this.getElem().find(".content .c").hide() ;

        contents.eq(index).show() ;

    } ;    

    tabProto.getElem = function(){

        return this.elem ;

    } ;

    tabProto.getOpts = function(){

        return this.opts ;

    } ;

    ui.createTab = function(elem,opts){

        var tab = new Tab(elem,opts) ;

        tab.init() ;

        return tab ;

    } ;        

})(jQuery) ;

(四),最后总结

(1),面向对象的思考方式合理分析功能需求。

(2),以类的方式来组织我们的插件逻辑。

(3),不断重构上面的实例,如何进行合理的重构那?不要设计过度,要游刃有余,推荐的方式是过程化设计与面向对象思想设计相结合。

    (4),思考一下上面例子中,选项卡中的选项是否可以独立成单独的类那?比如“Item”,那么“Tab”类如何修改那?带着问题去思考吧。。。

以上就是本文的全部内容了,后续我们将继续完善此插件,喜欢本文的话,来给点个赞吧。

Javascript 相关文章推荐
javascript中call和apply方法浅谈
Sep 27 Javascript
javascript作用域和闭包使用详解
Apr 25 Javascript
js使用正则实现ReplaceAll全部替换的方法
Aug 22 Javascript
javascript查询字符串参数的方法
Jan 28 Javascript
JavaScript实现梯形乘法表的方法
Apr 25 Javascript
原生JS实现《别踩白块》游戏(兼容IE)
Feb 20 Javascript
Node.js安装配置图文教程
May 10 Javascript
手把手教你搭建ES6的开发运行环境
Jul 11 Javascript
vue keep-alive请求数据的方法示例
May 16 Javascript
JS基于封装函数实现的表格分页完整示例
Jun 26 Javascript
详解如何运行vue项目
Apr 15 Javascript
微信小程序自定义胶囊样式
Dec 27 Javascript
js实现简单随机抽奖的方法
Jan 27 #Javascript
JavaScript插件化开发教程 (二)
Jan 27 #Javascript
javascript将数字转换整数金额大写的方法
Jan 27 #Javascript
JS实现同时搜索百度和必应的方法
Jan 27 #Javascript
js获取域名的方法
Jan 27 #Javascript
JavaScript插件化开发教程 (一)
Jan 27 #Javascript
js的toLowerCase方法用法实例
Jan 27 #Javascript
You might like
浅析is_writable的php实现
2013/06/18 PHP
php生成N个不重复的随机数实例
2013/11/12 PHP
PHP操作mysql数据库分表的方法
2016/06/09 PHP
PHP实现接收二进制流转换成图片的方法
2017/01/10 PHP
PHP数据分析引擎计算余弦相似度算法示例
2017/08/08 PHP
setTimeout 不断吐食CPU的问题分析
2009/04/01 Javascript
基于JavaScript实现div层跟随滚动条滑动
2016/01/12 Javascript
Nodejs获取网络数据并生成Excel表格
2020/03/31 NodeJs
项目实践一图片上传之form表单还是base64前端图片压缩(前端图片压缩)
2016/07/28 Javascript
jQuery源码解读之extend()与工具方法、实例方法详解
2017/03/30 jQuery
jQuery 禁止表单用户名、密码自动填充功能
2017/10/30 jQuery
详解js中Array的方法及技巧
2018/09/12 Javascript
Vue.js的动态组件模板的实现
2018/11/26 Javascript
jQuery实现的点击图片居中放大缩小功能示例
2019/01/16 jQuery
three.js 制作动态二维码的示例代码
2020/07/31 Javascript
python基础教程之获取本机ip数据包示例
2014/02/10 Python
python判断windows系统是32位还是64位的方法
2015/05/11 Python
python中argparse模块用法实例详解
2015/06/03 Python
Python使用logging结合decorator模式实现优化日志输出的方法
2016/04/16 Python
Python信息抽取之乱码解决办法
2017/06/29 Python
elasticsearch python 查询的两种方法
2019/08/04 Python
Python双链表原理与实现方法详解
2020/02/22 Python
用Python生成HTML表格的方法示例
2020/03/06 Python
python实点云分割k-means(sklearn)详解
2020/05/28 Python
如何利用Python 进行边缘检测
2020/10/14 Python
日本网路线上商品代购服务:转送JAPAN
2016/08/05 全球购物
美国孩之宝玩具官网:Hasbro Pulse
2019/06/24 全球购物
微软巴西官方网站:Microsoft Brasil
2019/09/26 全球购物
Ajax请求总共有多少种Callback
2016/07/17 面试题
学校党的群众路线教育实践活动总结报告
2014/07/03 职场文书
天那边观后感
2015/06/09 职场文书
2015年支教教师工作总结
2015/07/22 职场文书
一年级语文教学随笔
2015/08/14 职场文书
小学三年级数学教学反思
2016/02/16 职场文书
一波干货,会议主持词开场白范文
2019/05/06 职场文书
为什么MySQL 删除表数据 磁盘空间还一直被占用
2021/10/16 MySQL