• 用类与原型写一个组件(一)——学习笔记


      前两篇博文里学习了类与原型的相关知识,现在就理论结合实际,看看如何用类和原型来写一个插件。

      首先写好html页面如下,主要是引入jquery和bs,页面中放了一个id为memberList的div,用来放我们待会使用类和原型生成的item。

     1 <html>
     2 <head>
     3   <meta charset="UTF-8">
     4   <title>Flexx</title>
     5   <link href="http://apps.bdimg.com/libs/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet">
     6   <link rel="stylesheet" href="./css/main.css">
     7   <script src="http://apps.bdimg.com/libs/jquery/2.0.0/jquery.min.js"></script>
     8   <script src="http://apps.bdimg.com/libs/bootstrap/3.3.0/js/bootstrap.min.js"></script>
     9   <script src="./js/flexx.js"></script>
    10   <script src="./js/smartList.js"></script>
    11   <script src="./js/main.js"></script>
    12 </head>
    13 <body>
    14   <div class="container">
    15     <h1>Flexx Library</h1>
    16     <hr>
    17     <div class="row">
    18       <div class="col-xs-6">
    19         <div id="memberList"></div>
    20       </div>
    21     </div>
    22   </div>
    23 </body>
    24 </html>

      下面我们就创建一个原型,并为其初始化一个实例。

      下面我们复习一下上一篇中说过的set方法,用来更新列表。

      console可以看到,数据更新了,但还只是在console中看到,要怎么反应到页面中呢?

      为此,我们需要写一个原型方法用于生成节点(我们还会用到bs3的Collapse 插件),将生成的节点添加到DOM树上,之所以要写成原型的方法,是因为这个方法重用性高。

     1   // 生成一个条目
     2   SmartList.prototype._genItem = function (data) {
     3     var heading = 'heading_' + data.id;
     4     var collapse = 'collapse_' + data.id;
     5     var html = [
     6       '<div class="panel panel-default" data-id="' + data.id + '">',
     7       '<div class="panel-heading" role="tab" id="' + heading + '">',
     8       '<h4 class="panel-title">',
     9       '<a role="button" data-toggle="collapse" data-parent="#memberList" href="#' +
    10       collapse + '" aria-expanded="true" aria-controls="' + collapse + '">',
    11       data.title,
    12       '</a>',
    13       '<i data-act="del" class="glyphicon glyphicon-remove pull-right"></i>',
    14       '<i data-act="edit" class="glyphicon glyphicon-pencil pull-right"></i>',
    15       '</h4>',
    16       '</div>',
    17       '<div id="' + collapse + '" class="panel-collapse collapse" role="tabpanel" aria-labelledby="' + heading + '">',
    18       '<div class="panel-body">',
    19       data.content,
    20       '</div>',
    21       '</div>',
    22       '</div>'
    23     ].join('');
    24 
    25     return $(html);
    26   };

      大家可能注意到了,这个方法名称是以下划线开头,为什么和其它原型方法不同呢?是因为这个方法是打算封装在插件内部,不打算对用户可见的。详细缘由后文再说。

      那么,现在就可以使用原型的_genItem方法来生成节点,从而向页面添加节点了。

      但是页面报错了,是为什么呢?我们注意到渲染元素的时候用了this,是不是这个this导致的呢?不用猜,看不出来的话,可以打印看看this到底是什么。

      现在可以清楚的看到2个this的不同,而我们要用_genItem方法的对象应该是SmartList对象,怎么把each里面的this变一下呢?当然,变是变不了的,但是我们可以想办法在each里面用SmartList对象。方法如下,将SmartList对象用变量存起来,在each里面要用的时候就用这个变量。

     1   // 更新列表
     2   SmartList.prototype.setData = function (list) {
     3     var self = this;
     4     // 更新list数据
     5     this.list = list;
     6     // 渲染元素
     7     $.each(this.list, function (i, data) {
     8       self._genItem(data).appendTo(self.element);
     9     });
    10   };

      现在我们setData方法也有了,循环传进来的list数据,一个一个生成节点后添加到DOM里(SmartList的element属性用来表示要添加到那个DOM节点里)。那么现在代码和效果如下:

      效果图看起来是不是和bs的Collapse 插件示范的有点不一样呢?可以去参考一下bs的官方文档,原来是我们的id="memberList"的div少了一个class,但是我们又想让别人使用插件的时候页面尽可能简单,所以不把这个class写进Html里,于是,可以在原型里面加上。

    1   // 定义一个SmartList类
    2   function SmartList(selector) {
    3     this.list = [];
    4     this.element = $(selector).addClass('panel-group xx-smartlist');
    5 
    6     console.log('----创建了一个SmartList对象----');
    7   }

      同时,还可以加上我们插件的自定义样式xx-smartlist。

      现在,已经可以通过原型来生成一个member list 了,那么同样,可以利用该原型生成很多很多类似的List,比如现在我们就生成一个group list。

      现在html里放一个id="groupList"的div,再在main.js里面初始化一个groupList的实例,使它可以调用原型里的方法,接下来调用一下原型里setData方法,就可以批量生产list了。

    html代码如下:

     1 <html>
     2 <head>
     3   <meta charset="UTF-8">
     4   <title>Flexx</title>
     5   <link href="http://apps.bdimg.com/libs/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet">
     6   <link rel="stylesheet" href="./css/main.css">
     7   <script src="http://apps.bdimg.com/libs/jquery/2.0.0/jquery.min.js"></script>
     8   <script src="http://apps.bdimg.com/libs/bootstrap/3.3.0/js/bootstrap.min.js"></script>
     9   <script src="./js/flexx.js"></script>
    10   <script src="./js/smartList.js"></script>
    11   <script src="./js/main.js"></script>
    12 </head>
    13 <body>
    14   <div class="container">
    15     <h1>Flexx Library</h1>
    16     <hr>
    17     <div class="row">
    18       <div class="col-xs-6">
    19         <div id="memberList"></div>
    20       </div>
    21       <div class="col-xs-6">
    22         <div id="groupList"></div>
    23       </div>
    24     </div>
    25   </div>
    26 </body>
    27 </html>
    View Code

    main.js代码如下:

     1 + function () {
     2   'use strict';
     3 
     4   // 创建一个用来测试的模拟数据
     5   var members = [{
     6     id: 0,
     7     title: 'Brandon',
     8     content: 'hello'
     9   }, {
    10     id: 1,
    11     title: 'Kim',
    12     content: 'hi'
    13   }, {
    14     id: 2,
    15     title: 'Bunny',
    16     content: 'hi'
    17   }, {
    18     id: 3,
    19     title: 'Lovelyun',
    20     content: 'hi'
    21   }];
    22 
    23   var groups = [{
    24     id: 1,
    25     title: 'Web Dev',
    26     content: 'hello again'
    27   }];
    28 
    29   $(function () {
    30     // 初始化一个SmartList的实例对象
    31     var memberList = new xx.SmartList('#memberList');
    32     var groupList = new xx.SmartList('#groupList');
    33     memberList.setData(members);
    34     groupList.setData(groups);
    35   });
    36 
    37 }();
    View Code

      smartList.js不需要做任何改动。是不是方便快捷,实现同样的效果,避免了大段的重复代码?现在插件虽然还只有获取列表的功能,但是看了这一个功能的实现,是不是对其它功能的实现有所启发了呢?

      现在做个总结:

    1、注意this指向。

      就近原则,this指向它作用域的方法(函数)所属的对象,一个对象的方法上所有的函数中的this,都指向这个对象,即这个方法的主人。一个全局函数的this指向window,因为所有全局函数都是window上的一个方法。

    2、注意性能优化。

      选择器从dom中把一个元素选出来,是有成本的,有个查找的过程。所以要把使用次数较多的节点用变量存起来。

    3、注意js执行顺序。

      js中涉及DOM操作的,要等到document ready后再执行,否则在执行的时候DOM还没有加载。

    4、一个js潜规则。

      一般已下划线开头的方法,表示仅在类的方法内部使用的方法,不对外暴露接口。即带_开头的方法,不允许也不建议在对象上使用,仅是类内部使用,私有方法。(因为逻辑要重用,所以必须把一段段逻辑拆分成一个个方法,通过名称很清晰的能了解方法干什么用的,我又需要提供什么方法出去,哪些不提供,仅内部调用。你若不区分,会造成别人使用上的困惑,所以养成习惯)

    5、注意提前退出for循环的方法。

      原生js用 break退出for循环,jq里面用return false来退出循环(这个要记着哟,光return是没用的,要return false才行)。

    最后,感谢大神CX的讲解。

  • 相关阅读:
    下载安装ngnix
    微信小程序富文本中的图片大小超出屏幕
    微信小程序跳转(当我们不知道是普通页面还是tabbar)
    查看每年用量最多技术框架
    vue.js--遇到的一些错误
    vue-router(配置子路由--单页面多路由区域操作)
    webpack配置文件--(loader)
    webpack配置(入口出口)
    数组排序
    2021年12种高级UX/UI设计趋势
  • 原文地址:https://www.cnblogs.com/lovelyun/p/5088413.html
Copyright © 2020-2023  润新知