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

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

首先看一下在构造函数里用到的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中&&与||的使用解释

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一个功能齐全的仪表板和管理模板,带有精心设计的UI元素、组件、小部件和页面。超级干净和灵活的布局将使您可以轻松地构建Web应用程序。它可用于创建基于SaaS的界面、自定义管理面板、仪表板、CRM、CMS、电子商务面板等。 Hyper is a fully featured dashboard and admin template comes with tones of well designed UI elements, components, widgets and pages. The super clean and flexible layout would enable you to easily build web applications. It can be used to create a saas based interface, custom admin panels, dashboard, CRM, CMS, e-commerce panel, etc. Features: Built on latest bootstrap (v4.3.1) Easy customizations with extensive use of SCSS variables Fully responsive and works across all modern/supported browsers, devices Documentation on all available components, widgets, etc Easy development and tooling with Gulp workflow Components: All of Bootstrap components Icons Multiple widgets Toast Notifications Chartjs Charts Brite Charts Apex Charts Select2, Date Range Picker, Input Mask included Bootstrap form wizard Timepickers Spinner Max Length Validator Advanced Datatables Dragula – Simple Drag and Drop Multiple File Uploads WYSIWYG Editors (Summernote and SimpleMDE) Google and Vector Maps Layouts: Vertical Horizontal Detached Sidenav Light Sidenav Collapsed Sidenav Boxed (Fixed width) – Vertical and Horizontal Apps: Calendar Projects (List page, Detail Page) Tasks (List Page, Detail Modal, Add Task Modal) Ecommerce (Product listing, product detail, order listing, order detail, shopping cart, checkout, seller listing, etc) Pages: Sample Dashboard Profile Invoice FAQ Pricing Maintenance Login (Two variations) Register (Two variations) Logout (Two variations) Recover Password (Two variations) Lock Screen (Two variations) Confirm Mail (Two variations) Error 404 Error 500
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值