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) {}
}
加油!
placeholder插件详解的更多相关文章
- Uploadify 上传文件插件详解
Uploadify 上传文件插件详解 Uploadify是JQuery的一个上传插件,实现的效果非常不错,带进度显示.不过官方提供的实例时php版本的,本文将详细介绍Uploadify在Aspnet中 ...
- Google自写插件详解
谷歌插件详解,跳转至个人主页查看. GoogleExtension
- Maven系列第6篇:生命周期和插件详解,此篇看过之后在maven的理解上可以超越同级别90%的人!
maven系列目标:从入门开始开始掌握一个高级开发所需要的maven技能. 这是maven系列第6篇. 整个maven系列的内容前后是有依赖的,如果之前没有接触过maven,建议从第一篇看起,本文尾部 ...
- ThreeJS系列1_CinematicCameraJS插件详解
ThreeJS系列1_CinematicCameraJS插件详解 接着上篇 ThreeJS系列1_CinematicCameraJS插件介绍 看属性的来龙去脉 看方法作用 通过调整属性查看效果 总结 ...
- JQuery自定义插件详解之Banner图滚动插件
前 言 JRedu JQuery是什么相信已经不需要详细介绍了.作为时下最火的JS库之一,JQuery将其"Write Less,Do More!"的口号发挥的极致.而帮助J ...
- Web自动化框架LazyUI使用手册(3)--单个xpath抓取插件详解(selenium元素抓取,有此插件,便再无所求!)
概述 前面的一篇博文粗略介绍了基于lazyUI的第一个demo,本文将详细描述此工具的设计和使用. 元素获取插件:LazyUI Elements Extractor,作为Chrome插件,用于抓取页面 ...
- maven生命周期和插件详解
生命周期 什么是生命周期? maven的生命周期就是对所有的构建过程进行抽象和统一.maven从大量项目和构建工具中总结了一套高度完善的.易扩展的生命周期.这个生命周期包含项目的清理.初始化.编译.测 ...
- Java框架-MyBatis三剑客之MyBatis Generator(mybatis-generator MBG插件)详解
生成器设计思路: 连接数据库 -> 获取表结构 -> 生成文件 1 下载与安装 官网文档入口 最方便的 maven 插件使用方式 贴至pom 文件 2 新建配置文件 填充配置信息(官网示例 ...
- maven打包插件详解
maven-jar-plugin插件的使用及详解 该插件的xml配置及详解如下: <plugin> <groupId>org.apache.maven.plugins</ ...
随机推荐
- eclipse里启动tomcat无法通过127.0.0.1访问
在eclipse里面添加tomcat,再发布一个web项目进去,然后启动tomcat,日志显示tomcat在eclipse里面正常启动,hosts里面配置了ip跟域名的对应关系. 通过域名访问可以正常 ...
- 给mysql数据添加一个只拥有一张表的权限
grant all privileges on [database].* to 'database'@'localhost' identified by 'password' 例如: grant al ...
- 2015年传智播客JavaEE 第168期就业班视频教程day38-SSH综合案例-1
为什么需要划分模块呢?因为需要知道一些大致的功能,其次呢需要知道我们后台需不需要对它进行维护.如果需要呢那它肯定是一个单独的模块, 1.1 网上商城需求分析: 1.1.1 前台:用户模块 注册: ...
- ampify shader工具学习一
如何使用lambert Amplify Shader Editor 1.5.3 高级shader编辑工具 2018_5 点击下载
- php多进程pcntl学习(采集新浪微博)
上面2篇文都简明了多进程中一些需要注意的地方,这次用多进程配合curl_mulit_*来做新浪微博的采集. 先把知识点和值得注意的坑列出 /* 需求:开3个进程,并且模拟多线程来采集新浪微博用户信息, ...
- Create Empty Project In Vs But Not Debug?
问题描述 在使用VS创建一个空的项目管理,然后,添加项目.可是,这个时候,项目虽然可以运行,但是不能Debug进行调试. 解决方法 按照下面三张图像的设置即可.
- Linux addr2line命令
一.简介 Addr2line (它是标准的 GNU Binutils 中的一部分)是一个可以将指令的地址和可执行映像转换成文件名.函数名和源代码行数的工具.这种功能对于将跟踪地址转换成更有意义的内容来 ...
- Greeplum 系列(七) 权限管理
Greeplum 系列(七) 权限管理 一.角色管理 Role 分为用户(User)和组(Group),用户有 login 权限,组用来管理用户,一般不会有 login 权限.初始化 gp 时创建了一 ...
- html符号转换
通常情况下,HTML会自动截去多余的空格.不管你加多少空格,都被看做一个空格.比如你在两个字之间加了10个空格,HTML会截去9个空格,只保留一个.为了在网页中增加空格,你可以使用 表示空格.最常用的 ...
- numpy中三维数组转变成二维数组
numpy中reshape()函数对三维数组进行转换成二维数组,见下面例子: >>>a=np.reshape(np.arange(18),(3,3,2)) >>> ...