分析boostrap tags-input组件并进行二次封装开发-4

news/2024/7/11 1:46:07 标签: js, jquery, boostrap组件分析与二次开发

看完了构造函数,接下来看一下组件的原型吧

首先看一下在构造函数里用到的build函数

/**
     * Initializes the tags input behaviour on the element
     */
    build: function(options) {
      var self = this;
      self.options = $.extend({}, defaultOptions, options);
      // When itemValue is set, freeInput should always be false
      if (self.objectItems)
        self.options.freeInput = false;
...
...
...
      self.$container.on('click', $.proxy(function(event) {
        if (! self.$element.attr('disabled')) {
          self.$input.removeAttr('disabled');
        }
        self.$input.focus();
      }, self));

        if (self.options.addOnBlur && self.options.freeInput) {
          self.$input.on('focusout', $.proxy(function(event) {
              // HACK: only process on focusout when no typeahead opened, to
              //       avoid adding the typeahead text as tag
              if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) {
                self.add(self.$input.val());
                self.$input.val('');
              }
          }, self));
        }


      self.$container.on('keydown', 'input', $.proxy(function(event) {
        var $input = $(event.target),
            $inputWrapper = self.findInputWrapper();

        if (self.$element.attr('disabled')) {
          self.$input.attr('disabled', 'disabled');
          return;
        }

        switch (event.which) {
          // BACKSPACE
          case 8:
            if (doGetCaretPosition($input[0]) === 0) {
              var prev = $inputWrapper.prev();
              if (prev.length) {
                self.remove(prev.data('item'));
              }
            }
            break;

          // DELETE
          case 46:
            if (doGetCaretPosition($input[0]) === 0) {
              var next = $inputWrapper.next();
              if (next.length) {
                self.remove(next.data('item'));
              }
            }
            break;

          // LEFT ARROW
          case 37:
            // Try to move the input before the previous tag
            var $prevTag = $inputWrapper.prev();
            if ($input.val().length === 0 && $prevTag[0]) {
              $prevTag.before($inputWrapper);
              $input.focus();
            }
            break;
          // RIGHT ARROW
          case 39:
            // Try to move the input after the next tag
            var $nextTag = $inputWrapper.next();
            if ($input.val().length === 0 && $nextTag[0]) {
              $nextTag.after($inputWrapper);
              $input.focus();
            }
            break;
         default:
             // ignore
         }

        // Reset internal input's size
        var textLength = $input.val().length,
            wordSpace = Math.ceil(textLength / 5),
            size = textLength + wordSpace + 1;
        $input.attr('size', Math.max(this.inputSize, $input.val().length));
      }, self));

      self.$container.on('keypress', 'input', $.proxy(function(event) {
         var $input = $(event.target);

         if (self.$element.attr('disabled')) {
            self.$input.attr('disabled', 'disabled');
            return;
         }

         var text = $input.val(),
         maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
         if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) {
            // Only attempt to add a tag if there is data in the field
            if (text.length !== 0) {
               self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
               $input.val('');
            }

            // If the field is empty, let the event triggered fire as usual
            if (self.options.cancelConfirmKeysOnEmpty === false) {
               event.preventDefault();
            }
         }

         // Reset internal input's size
         var textLength = $input.val().length,
            wordSpace = Math.ceil(textLength / 5),
            size = textLength + wordSpace + 1;
         $input.attr('size', Math.max(this.inputSize, $input.val().length));
      }, self));

      // Remove icon clicked
      self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
        if (self.$element.attr('disabled')) {
          return;
        }
        self.remove($(event.target).closest('.tag').data('item'));
      }, self));

      // Only add existing value as tags when using strings as tags
      if (self.options.itemValue === defaultOptions.itemValue) {
        if (self.$element[0].tagName === 'INPUT') {
            self.add(self.$element.val());
        } else {
          $('option', self.$element).each(function() {
            self.add($(this).attr('value'), true);
          });
        }
      }
    },

————————————————————————————————————————————————————

首先通过$.extend()将调用者设置的参数与默认参数进行合并,生成组件的设置参数

以下是对$.exxtend()的解释

jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象。
注意:1. 如果只为$.extend()指定了一个参数,则意味着参数target被省略。此时,target就是jQuery对象本身。通过这种方式,我们可以为全局对象jQuery添加新的函数。
2. 如果多个对象具有相同的属性,则后者会覆盖前者的属性值。                                    摘录自http://www.runoob.com/jquery/misc-extend.html

—————————————————————————————————————————————————————

接下来查看组件显示容器$container的事件绑定

      self.$container.on('click', $.proxy(function(event) {
        if (! self.$element.attr('disabled')) {
          self.$input.removeAttr('disabled');
        }
        self.$input.focus();
      }, self));

组件在此虽然使用$.proxy维持了self的上下文一致,但是这里其实是可以不需要使用$.proxy的

      self.$container.on('click', function(event) {
        if (! self.$element.attr('disabled')) {
          self.$input.removeAttr('disabled');
        }
        self.$input.focus();
      });

此处是根据element元素中是否设置了disabled来设置输入允许在input中输入其他标签。

—————————————————————————————————————————————————————

        if (self.options.addOnBlur && self.options.freeInput) {
          self.$input.on('focusout', $.proxy(function(event) {
              // HACK: only process on focusout when no typeahead opened, to
              //       avoid adding the typeahead text as tag
              if ($('.typeahead,.twitter-typeahead',self.$container).length === 0) {
                self.add(self.$input.val());
                self.$input.val('');
              }
          }, self));
        }

此段是针对container>input输入进行赋值,需要特别指出的是此组件不支持typeahead组件的标签,typeahead是jquery的一款模糊搜素组件官网地址为http://www.runningcoder.org/jquerytypeahead/overview/

在此的

$('.typeahead,.twitter-typeahead',self.$container)

就是选出所有container下的样式为typeahead或者twitter-typeahead样式的Dom元素,以下是对$()的说明

jQuery(expression, [context]) 返回值:jQuery
概述
这个函数接收一个包含 CSS 选择器的字符串,然后用这个字符串去匹配一组元素。
jQuery 的核心功能都是通过这个函数实现的。 jQuery中的一切都基于这个函数,或者说都是在以某种方式使用这个函数。这个函数最基本的用法就是向它传递一个表达式(通常由 CSS 选择器组成),然后根据这个表达式来查找所有匹配的元素。
默认情况下, 如果没有指定context参数,$()将在当前的 HTML document中查找 DOM 元素;如果指定了 context 参数,如一个 DOM 元素集或 jQuery 对象,那就会在这个 context 中查找。在jQuery 1.3.2以后,其返回的元素顺序等同于在context中出现的先后顺序。
参考文档中 选择器 部分获取更多用于 expression 参数的 CSS 语法的信息。

参数
expressionString
用来查找的字符串
context (可选)Element, jQuery
作为待查找的 DOM 元素集、文档或 jQuery 对象。        

在此说一句惭愧,用了这么长时间的jQuery现在才知道$(expression,[context])后面还有一个参数。

————————————————————————————————————————————————————

      self.$container.on('keydown', 'input', $.proxy(function(event) {
        var $input = $(event.target),
            $inputWrapper = self.findInputWrapper();

        if (self.$element.attr('disabled')) {
          self.$input.attr('disabled', 'disabled');
          return;
        }
        switch (event.which) {
          // BACKSPACE
          case 8:
            if (doGetCaretPosition($input[0]) === 0) {
              var prev = $inputWrapper.prev();
              if (prev.length) {
                self.remove(prev.data('item'));
              }
            }
            break;

          // DELETE
          case 46:
            if (doGetCaretPosition($input[0]) === 0) {
              var next = $inputWrapper.next();
              if (next.length) {
                self.remove(next.data('item'));
              }
            }
            break;

          // LEFT ARROW
          case 37:
            // Try to move the input before the previous tag
            var $prevTag = $inputWrapper.prev();
            if ($input.val().length === 0 && $prevTag[0]) {
              $prevTag.before($inputWrapper);
              $input.focus();
            }
            break;
          // RIGHT ARROW
          case 39:
            // Try to move the input after the next tag
            var $nextTag = $inputWrapper.next();
            if ($input.val().length === 0 && $nextTag[0]) {
              $nextTag.after($inputWrapper);
              $input.focus();
            }
            break;
         default:
             // ignore
         }

        // Reset internal input's size
        var textLength = $input.val().length,
            wordSpace = Math.ceil(textLength / 5),
            size = textLength + wordSpace + 1;
        $input.attr('size', Math.max(this.inputSize, $input.val().length));
      }, self));

对于jquery的on函数的使用

=========================================================================

$(selector).on(event,childSelector,data,function)

参数描述
event必需。规定要从被选元素移除的一个或多个事件或命名空间。

由空格分隔多个事件值,也可以是数组。必须是有效的事件。
childSelector可选。规定只能添加到指定的子元素上的事件处理程序(且不是选择器本身,比如已废弃的 delegate() 方法)。
data可选。规定传递到函数的额外数据。
function可选。规定当事件发生时运行的函数。

=========================================================================

此函数是监听$container下的input 点击事件,当input点击之后,将焦点集中至input内,监听按键的keydown事件

Backspace ,Delete,左箭头,右箭头四个事件,至于每个事件的逻辑就不在说了,最后根据placeholder与input中的val长度对input的长度进行了设置

这里需要注意的是jquery的几个api为prev(),before(),after();

————————————————————————————————————————————————————

      self.$container.on('keypress', 'input', $.proxy(function(event) {
         var $input = $(event.target);

         if (self.$element.attr('disabled')) {
            self.$input.attr('disabled', 'disabled');
            return;
         }

         var text = $input.val(),
         maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
         if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) {
            // Only attempt to add a tag if there is data in the field
            if (text.length !== 0) {
               self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
               $input.val('');
            }

            // If the field is empty, let the event triggered fire as usual
            if (self.options.cancelConfirmKeysOnEmpty === false) {
               event.preventDefault();
            }
         }

         // Reset internal input's size
         var textLength = $input.val().length,
            wordSpace = Math.ceil(textLength / 5),
            size = textLength + wordSpace + 1;
         $input.attr('size', Math.max(this.inputSize, $input.val().length));
      }, self));

此函数是监听container下input的keypress事件,至于keydown与keypress的区别会在接下来其他篇幅中提及

关于此处

maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars

可以查看 https://blog.csdn.net/cherry_zhang18/article/details/77483382关于js中&&与||的使用解释

未完待续呀,去充电去了呀。


http://www.niftyadmin.cn/n/801239.html

相关文章

设计模式初谈

一直相总结自己关于设计模式的一些理解 单从字面意思理解分为设计与模式两部分,由此引出的一些问题比如设计的原则是什么,是关于什么的模式... 模式就是前人在不断的试错之后总结出的一套在特定问题场景具备普适性的解决路径,之所以没有称为解…

quickcover组件开发

今天在网上浏览发现有一个纯css完成的蒙版效果,于是思考是不是可以做一个组件只需要开发者关注蒙版内的html内容编写,而不需要关注蒙版的设置与生成,于是就诞生了quickcover组件开发效果先展示一下呀,臭美一下了。效果还可以吧&am…

蓝桥杯 算法训练 未名湖边的烦恼

问题描述每年冬天,北大未名湖上都是滑冰的好地方。北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰鞋都不剩。每天早上,租鞋窗口都会排起长龙,假设有还鞋的m个,有需要租鞋的n…

优秀的框架stylefeng——guns/roses

Guns基于SpringBoot,致力于做更简洁的后台管理系统,完美整合springmvc shiro mybatis-plus beetl!Guns项目代码简洁,注释丰富,上手容易,同时Guns包含许多基础模块(用户管理,角色管理,部门管理,字典管理等10个模块),可以直接作为一个后台管理系统的脚手架! 2018目标 更简洁,更…

Qt QTreeWidget的级联选中

在使用QTreeWidget显示文件树时,需要对树的节点做一些功能的限制: 勾选某一节点时,该节点的子项自动全部选中子项部分勾选时,父节点状态为部分勾选子项全部勾选时,父节点自动设置勾选 首先,查看了Qt文档&…

解题报告

1、Xxy 的车厢调度(train.cpp/c/pas)Description , …

在没有后端服务的支持下前端如何测试ajax接口加载本地json文件

转载自本文档 https://blog.csdn.net/qq8241994/article/details/79853530; 在桌面上打开谷歌浏览器属性界面,在目标一栏中的末尾添加 --allow-file-access-from-files 应用双击快捷方式运行(不要在编辑器里直接用浏览器打开&#xff…

大数据系列之数据仓库Hive命令使用及JDBC连接

Hive系列博文,持续更新~~~ 大数据系列之数据仓库Hive原理 大数据系列之数据仓库Hive安装 大数据系列之数据仓库Hive中分区Partition如何使用 大数据系列之数据仓库Hive命令使用及JDBC连接 本文介绍Hive的使用原理及命令行、Java JDBC对于Hive的使用。 在Hadoop项目中…