placeholder插件详解

placeholder插件是用来实现input或者textarea文本框显示默认文字的功能,当获得焦点时,默认文字消失。用户按删除键,把输入的字符删除掉,并失去焦点时,默认文字又出现等功能。使用此插件,只需要$("input").placeholder();这input元素,必须有placeholder属性,属性值就是input默认显示的文本,而且input元素中的class属性值中没有placeholder值,此插件也是基于jQuery的。

再看源码之前,我先讲一个知识点:

如果我们直接用 .click() / .bind(‘click‘) 加上 .unbind(‘click‘) 来进行重复绑定,被 unbind 掉的将是绑定在元素上的所有click处理函数,潜在会影响到该元素在其他第三方的行为(比如,有另外一个插件也绑定了该元素的click事件)。当然如果在bind的时候是显式定义了function的名字的话,可以在unbind的时候提供function的名字作为第二个参数unbind其中一个处理函数,但实际应用中我们很可能会碰到各种进行匿名函数绑定的情况。

对于这种问题,jQuery的解决方案是使用事件绑定的命名空间。即在事件名称后添加 .something 来区分自己这部分行为逻辑范围。
比如用 .bind(‘click.myCustomRoutine‘,function(){...}); 同样是把匿名函数绑定到 click 事件(你可以用自己的命名空间多次绑定不同的匿名处理函数上去),当unbind的时候用 .unbind(‘click.myCustomRoutine‘) 即可释放所有绑定到 .myCustomRoutine 命名空间的 click 事件,而不会解除其他通过 .bind(‘click‘) 或另外的命名空间所绑定的click事件处理函数。
同时,使用命令空间还可以让你一次性 unbind 所有此命名空间下的事件绑定,通过 .unbind(‘.myCustomRoutine‘) 即可。
要注意的是,jQuery的命名空间并不支持多级空间。因此在jQuery里面,如果用 .unbind(‘click.myCustomRoutine.myCustomSubone‘) ,解除的是命名空间分别为 myCustomRoutine 和 myCustomSubone 的两个并列命名空间下的所有 click 事件,而不是 "myCustomRoutine 下的 myCustomSubone 子空间"。

接下来我们来看源码:

var isInputSupported = ‘placeholder‘ in document.createElement(‘input‘);   //看此浏览器的input是否默认支持placeholder属性,IE6-9不支持
var isTextareaSupported = ‘placeholder‘ in document.createElement(‘textarea‘);  
var prototype = $.fn;   //jQuery的原型对象
var valHooks = $.valHooks;   //解决浏览器兼容性的对象,它里面有很多属性,比如:option,select,radio,checkbox,这些属性是一个对象,具有set或get方法来解决浏览器兼容性问题。jQuery中针对这4个元素的value值进行了兼容性处理。
var hooks;
var placeholder;

if (isInputSupported && isTextareaSupported) {  //如果浏览器默认支持,就直接在jQuery的原型对象中添加placeholder方法,这样jQuery对象都可以调用placeholder方法了

  placeholder = prototype.placeholder = function() {
    return this;    //this其实指的就是jQuery对象,$("input")
  };

  placeholder.input = placeholder.textarea = true;  //给placeholder方法添加两个属性,属性值都为true

} else {

  placeholder = prototype.placeholder = function() {
    var $this = this;
    $this.filter(

      (isInputSupported ? ‘textarea‘ : ‘:input‘) + ‘[placeholder]‘   //如果支持input的palceholder,就是textarea[placeholder],如果不支持,就是:input[placeholder]。过滤出这些元素进行下一步操作,这些元素可能是有placeholder属性的textarea元素,也有可能是有placeholder属性的表单元素(:input选择器选取表单元素)。

    ).not(‘.placeholder‘).bind(    //删除class属性值中有placeholder的元素

      {
        ‘focus.placeholder‘: clearPlaceholder,    //绑定focus和blur事件,命名空间为placeholder,方便unbind解绑时,使用。
        ‘blur.placeholder‘: setPlaceholder
      }

    ).data(‘placeholder-enabled‘, true)   //给这些元素在缓存系统中添加placeholder-enabled为true的数据

    .trigger(‘blur.placeholder‘);   //触发blur.placeholder事件,执行setPlaceholder方法。也就是默认情况下,鼠标焦点不在input框中,因此触发input的blur事件
    return $this;
  };

  placeholder.input = isInputSupported;
  placeholder.textarea = isTextareaSupported;

  hooks = {    //定义局部变量hooks

    ‘set‘: function(element, value) {   //如果是针对密码框设置placeholder,那么这里的element就是新的input元素,如果针对的是普通的input框,那么这里的element就是这个普通的input元素,这里的value是默认文本
      var $element = $(element);

      var $passwordInput = $element.data(‘placeholder-password‘);   //如果是密码框,那么新的input的placeholder-password值就是密码框对象,如果是普通的input元素,这里返回undefined。
      if ($passwordInput) {
        $passwordInput[0].value = value;   //设置密码框的value值
      }

      if (!$element.data(‘placeholder-enabled‘)) {   //如果是普通的input元素,$element.data(‘placeholder-enabled‘)返回true,取反后会返回false,因此不会进入if语句。
        return element.value = value;
      }
      element.value = value;
      return $element;
    }
  };

  if (!isInputSupported) {   //如果浏览器不支持input的placeholder事件,就进入if语句
    valHooks.input = hooks;         //给jQuery添加input属性对象,来解决浏览器input元素设置值与取值的兼容性问题,原本valHooks只有radio,checkbox,select,option这四个属性,现在多了input。
  }
  if (!isTextareaSupported) {   //如果不支持textarea的placeholder事件,就进入if语句
    valHooks.textarea = hooks;  //针对textarea元素设置值与取值的兼容性问题的解决
  }

}

function args(elem) {    //elem是input元素,针对IE6-7
  var newAttrs = {};
  var rinlinejQuery = /^jQuery\d+$/;
  $.each(elem.attributes, function(i, attr) {    //取input元素的attributes属性对象
    if (attr.specified && !rinlinejQuery.test(attr.name)) {   //如果属性值是被用户显式设置的,那么它的specified就会为true,然后判断属性名不是jQuery的自定义属性(在元素上调用data方法,往jQuery缓存系统中添加数据时,会在元素上添加一个以jQuery开头+随机数的一个自定义属性)
      newAttrs[attr.name] = attr.value;      //把这些显式设置的属性值,保存到一个json对象中,并返回。
    }
  });
  return newAttrs;
}

function clearPlaceholder(event, value) {   //当鼠标焦点在input元素上时

  var input = this;
  var $input = $(input);
  if (input.value == $input.attr(‘placeholder‘) && $input.hasClass(‘placeholder‘)) {  //如果input的文本是默认文本,并且class属性中有placeholder值时,进入if语句,如果用户在input中输入默认的文本,然后触发blur事件,这时会把input的placeholder类删掉,因此当你再次触发focus事件时,不会进入if语句
    if ($input.data(‘placeholder-password‘)) {    //如果是密码框,这里的input其实是inputNew,因为input已经被hide了。
      $input = $input.hide().next().show().attr(‘id‘, $input.removeAttr(‘id‘).data(‘placeholder-id‘)); //把inputNew隐藏,取到input元素,显示出来,并恢复input元素的id。同时移除inputNew的id,并取得inputNew的缓存系统中placeholder-id的值(这个值就是之前input元素id的值),赋给input元素的id。
      $input.focus();  //input元素获得焦点(这时的input就是密码框的input了)
    } else {   //如果不是密码框
      input.value = "";   //就把input中的文本清空
      $input.removeClass(‘placeholder‘);   //并移除掉这个placeholder类
      input == safeActiveElement() && input.select();   //解决IE9下的一个bug,因为IE9下,如果是iframe中的元素获得了焦点,你调用document.activeElement,IE9会抛出错误。因此必须用try,catch来处理下,如果抛出错误,就不执行元素的select方法(此方法会选择input框中的文本),如果没抛出错误,就执行input的select方法(返回值是undefined).
    }
  }
}

function setPlaceholder() {   //失去焦点触发blur事件
  var $replacement;
  var input = this;   //this指的就是input元素
  var $input = $(input);  //转换成jQuery对象
  var id = this.id;   //取到input元素的id

  if (input.value == "") {  //如果input框中是空字符串
    if (input.type == ‘password‘) {   //如果input是密码输入框
      if (!$input.data(‘placeholder-textinput‘)) { //input元素在jQuery缓存系统中是否有placeholder-textinput属性值,没有就进入if语句
        try {
          $replacement = $input.clone().attr({ ‘type‘: ‘text‘ }); //克隆一个input元素,我们命名为inputNew,并设置它的type属性为text。IE老版本会报错,不能修改克隆出来的input的type值
        } catch(e) {
          $replacement = $(‘<input>‘).attr($.extend(args(this), { ‘type‘: ‘text‘ }));  //把这个input元素所有显式设置的属性取出来,然后扩展type属性。然后把这些属性全部赋值到新创建的input元素中,我们命名为inputNew
        }
        $replacement.removeAttr(‘name‘).data({    //移除掉inputNew元素的name属性,并往jQuery数据缓存系统中添加数据
          ‘placeholder-password‘: $input, 
          ‘placeholder-id‘: id
        }).bind(‘focus.placeholder‘, clearPlaceholder);    //给这个inputNew元素绑定focus事件。
        $input.data({     //给input元素往jQuery缓存系统中添加数据
          ‘placeholder-textinput‘: $replacement,
          ‘placeholder-id‘: id
        }).before($replacement);   //在元素input前面添加inputNew元素
      }
      $input = $input.removeAttr(‘id‘).hide().prev().attr(‘id‘, id).show();  //移除input元素的id属性,并隐藏,获得input元素前面的那个元素,也就是inputNew元素,然后设置它的id,并让它显示出来。
    }
    $input.addClass(‘placeholder‘);   //如果原来的input是密码框,这里的input就是inputNew,如果不是密码框,这里就是原来的input。
    $input.val($input.attr(‘placeholder‘));  //这里,如果浏览器的input或者textarea不支持placeholder事件,将调用上面定义的hooks来设置value值。具体请看hook的set方法。这里为什么要新建一个新的input元素,是因为页面上的input元素是密码框,当你输入文本进去时,会显示***这种字符,但是默认情况下,应该显示默认文本,因此创建一个新的input元素,把密码框隐藏,然后把默认文本放在新的input元素里面。当用户用鼠标去点击时,新的input获得焦点时,就会把新的input元素隐藏,同时让密码框显示出来,这样用户输入的字符就会是***这种,如果不新建一个新的input,那么默认文本在密码框中显示的是***。
  } else {   //如果input的value值不为"",就移除input的placeholder类名
    $input.removeClass(‘placeholder‘);
  }
}

function safeActiveElement() {
  try {
    return document.activeElement;  //http://bugs.jquery.com/ticket/13378
  } catch (exception) {}
}

加油!

时间: 2024-10-11 01:11:58

placeholder插件详解的相关文章

jquery-ias插件详解

内容加载到底部的时候自动加载下一批的内容,如http://k.thea.cn/index.php?c=exam&a=visitor&tcid=640&classid=743,滚动条滚动到底部就加载下一部分的内容.要实现这样的效果,可以借助jquery-ias插件.具体用法参见:http://blog.csdn.net/wlm131127/article/details/12751803. jquery-ias插件详解,布布扣,bubuko.com

iOS插件详解之----CLangFormat(代码格式化管理插件)(2016.1.12王彬)

iOS插件详解之----CLangFormat(代码格式化管理)(2016.1.12王彬) 虽然在项目创建和团队组建的初期,我们就把公共约定以及一些规范定下来了,并且由于我们的代码是通过Git来做版本控制的,web上直接就支持Markdown格式的readme文件,可以随时看到最新的版本,但是这种规范只能依靠个人的意识,或者通过代码Review来解决,而且做代码Review的时候,你也不好意思总是写上一堆诸如“这里要加个空格”.“那里要加上换行”的评论吧?如果不管,久而久之,会因为每个人的习惯不

Bootstrap transition.js 插件详解

Bootstrap transition.js 插件详解 时间 2015-01-27 12:12:00 博客园-原创精华区 原文  http://www.cnblogs.com/xyzhanjiang/p/4252513.html 主题 Bootstrap JavaScript Bootstrap 自带的 JavaScript 插件的动画效果几乎都是使用 CSS 过渡实现的,而其中的 transition.js 就是为了判断当前使用的浏览器是否支持 CSS 过渡.下面先来简单了解下 CSS 过渡

Android Studio如何导出可供Unity使用的aar插件详解 转

Android Studio如何导出可供Unity使用的aar插件详解 前言 项目之前使用Eclipse导出的jar文件来做与Android交互,最近因为工作需要需使用Android Studio的aar文件,网上参考了部分文章,也结合自己的理解重新整理一下具体的方法,通过写一个测试Demo来表述Android Studio创建aar的过程与及Unity如何使用aar文件,希望对刚好有这个需求的人能起到部分帮助与引导,同时如果文中有误希望也能不吝赐教. 版本信息 Unity 5.3.1f1, A

Java框架-MyBatis三剑客之MyBatis Generator(mybatis-generator MBG插件)详解

生成器设计思路: 连接数据库 -> 获取表结构 -> 生成文件 1 下载与安装 官网文档入口 最方便的 maven 插件使用方式 贴至pom 文件 2 新建配置文件 填充配置信息(官网示例) 项目实例 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Genera

从本地安装Eclipse的SVN插件详解

由于绝大多数Eclipse插件的Update Site服务器位于国外,甚至无法访问,再加上Eclipse自身缓慢的下载速度,导致在线安装Eclipse插件耗费的时间非常多.因此,一般情况下,我们建议先通过加速下载工具手动下载插件安装包,然后从本地安装Eclipse插件. 从本地安装Eclipse插件的方法有多种,下面我们根据难度从易到难一一为大家介绍. 1.以图形化方式从本地安装插件 Eclipse为我们提供了以图形化方式本地安装插件的方法. 首先,点击Eclipse菜单栏的[Help]->[I

jQuery lazyload插件详解

lazyload插件用于图片延迟加载,节省服务器带宽,减少服务器请求次数,提高网站的页面加载速度,用于网站性能优化,只有当图片在窗口可视范围内时才向服务器请求: 参数: threshold:设置距离窗口底部多少像素开始加载图片,提前加载图片, failure_limit:lazyload按照瀑布流加载图片,当找到(按照图片在DOM中的位置从上往下)第一张不在可视范围的图片后就停止检测延迟加载图片的位置 如上图,如果每个列表块包含两张图片,failure_limit为0时,当页面滚动到阴影位置时,

JQuery PowerTimer 插件详解

一个jQuery插件,提供定时器以下类型: 1.单运行定时器(又名的setTimeout) 2.反复运行定时器(又名的setInterval) 3.立即运行一个重复的运行计时器,然后等待的时间间隔. 4.反复运行,一定的间隔定时器(见下文睡眠选项). 5.反复运行,一定的间隔计时器,将立即运行,然后等待睡眠时间. 为什么你会使用这个库与常规的setTimeout? 因为它提供了大量的 附加功能! 例如: - 自动定时器ID跟踪. - 暂停和继续后定时器. - 独特的计时器,如果你启动一个定时器两

如何编写JQuery 插件详解

转载自:http://blog.sina.com.cn/s/blog_6154bf970101jam7.html 如今做web开发,jquery 几乎是必不可少的,就连vs神器在2010版本开始将Jquery 及ui 内置web项目里了.至于使用jquery好处这里就不再赘述了,用过的都知道.今天我们来讨论下jquery的插件机制,jquery有着成千上万的第 三方插件,有时我们写好了一个独立的功能,也想将其与jquery结合起来,可以用jquery链式调用,这就要扩展jquery,写成插件形式