在上一次我设计了一个带光晕的文本框,类似于QQ2011,给我们的网页增加了美感和动感。最后,我留给大家的是对文本框的继续优化,这次我增加了水印效果和提示效果。可能很多人说这些在Jquery中已经有内置插件了,为什么还需要自己去写呢?我历来的标准是:“拿来主义”分情况。对于已经满足我们要求且易于配置的的插件,我们直接拿来用就是。但是对于不能满足我们要求且本身已经很复杂的插件,则更愿意自己动手去写,以便了解整个插件的设计流程。下面就不废话了,先来看水印吧。我们设想了一个最简单的例子就是普通的文本框(<input type='text' id='txtName' value=''>),不外乎就是出发textbox的focus和blur事件作出不同的响应。以下是主要的文件结构和主要代码:
jquery.watermark.1.0.js:
(function ($) {
$.fn.watermark = function (defaultText) {
return this.each(function () {
var $this = $(this);
var text = $this.val();
if (defaultText) {
text = defaultText;
$this.val(text).addClass("watermark");
}
$this.focus(function () {
if ($this.val() == defaultText) {
$this.val('').removeClass("watermark");
}
}).blur(function () {
if ($this.val() == '') {
$this.val(defaultText).addClass("watermark");
}
});
});
}
})(jQuery);
注意其中有一个css效果,watermark:
.span
{
padding: 3px 2px 0 0;
float: left;
display: inline;
}
.textbox
{
border: 0px;
height: 22px;
line-height: 22px;
overflow: hidden;
background: url(images/border.png) 0 -72px repeat-x;
}
.aq_box
{
padding-left: 3px;
background: url(images/border.png) left -24px no-repeat;
float: left;
}
.aq_box_wrap
{
padding-right: 3px;
background: url(images/border.png) right -24px no-repeat;
}
.aq_box.hover
{
background-position: left top;
}
.aq_box.hover .aq_box_wrap
{
background-position: right top;
}
.aq_box.hover .textbox
{
background-position: 0 -48px;
}
.watermark
{
color: #999;
}
当插件写好之后,我们开始应用这个插件,前台页面如下:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<link href="[path]/Scripts/plugins/textbox/textbox.css" rel="stylesheet" type="text/css" />
</head>
<body>
<input type="text" id="name" class="textbox" /><br />
<br />
<input type="password" id="password" class="textbox" />
<script src="[path]/Scripts/plugins/textbox/jquery-1.5.1.min.js" type="text/javascript"></script>
<script src="[path]/Scripts/plugins/textbox/jquery.textbox.js" type="text/javascript"></script>
<script src="[path]/Scripts/plugins/textbox/jquery.watermark.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#name").textbox().watermark("用户名");
$("#password").textbox().watermark("密码");
});
</script>
</body>
</html>
当运行之后你就可以看到效果:
默认以及鼠标离开(未填写任何值)的效果:
鼠标进入后的效果:
当填写文字之后的效果:
是不是很完美呢?但是我们发现密码那个框就没有这么幸运了,它的水印文字却变成了黑点,如下图:
怎么办呢?我们需要扩展我们的水印插件以支持密码水印效果。细想一下,我们可以发现密码框和文本框除了type不一致,其他均为一样的。此时,我们设想以做好的文本框作支撑,辅助实现密码水印效果。目标是动态配置一个与密码等宽登高的文本框来实现和密码框的切换(在focus和blur事件中)。由于需要支持以前的插件,因此我们单独对密码框来进行处理,我们可以通过以下语句来筛选密码框:
var ispwd = $this.attr("type").toLowerCase() == "password";
以下是我扩展以后支持密码框的水印效果(注意高亮处): jquery.watermark.1.1.js:
(function ($) {
$.fn.watermark = function (defaultText) {
return this.each(function () {
var $this = $(this);
var ispwd = $this.attr("type").toLowerCase() == "password";
var text = $this.val();
if (defaultText) {
text = defaultText;
if (ispwd) {
var tb = $("<input type='text' class='textbox'/>");
$this.hide().parent().append(tb.addClass("watermark").width($this.width()).val(text));
} else {
$this.val(text).addClass("watermark");
}
}
if (ispwd) {
$this.next().focus(function () {
if ($this.next().val() == defaultText) {
$this.next().hide().end().show().focus();
}
}).end().blur(function () {
if ($this.val() == '') {
$this.hide().next().show();
}
});
} else {
$this.focus(function () {
if ($this.val() == defaultText) {
$this.val('').removeClass("watermark");
}
}).blur(function () {
if ($this.val() == '') {
$this.val(defaultText).addClass("watermark");
}
});
}
});
}
})(jQuery);
做了这些工作后,再次运行之前的页面,你会发觉密码水印效果变成了这个样子:
当输入密码时,密码框变成:
这样就完美实现文本框和密码框的水印效果了。接下来,我们继续探讨提示的实现效果,其实这个功能已经在jquery中实现,其原理是:设置元素的title属性,然后以div浮动的形式来展现。
(function($){
$.fn.tooltip = function(options) {
var defaults = {
activation: "hover",
keepAlive: false,
maxWidth: "200px",
edgeOffset: 3,
defaultPosition: "bottom",
delay: 400,
fadeIn: 200,
fadeOut: 200,
attribute: "title",
content: false, // HTML or String to fill TipTIp with
enter: function(){},
exit: function(){}
};
var opts = $.extend(defaults, options);
// Setup tip tip elements and render them to the DOM
if($("#tiptip_holder").length <= 0){
var tiptip_holder = $('<div id="tiptip_holder" style="max-width:'+ opts.maxWidth +';"></div>');
var tiptip_content = $('<div id="tiptip_content"></div>');
var tiptip_arrow = $('<div id="tiptip_arrow"></div>');
$("body").append(tiptip_holder.html(tiptip_content).prepend(tiptip_arrow.html('<div id="tiptip_arrow_inner"></div>')));
} else {
var tiptip_holder = $("#tiptip_holder");
var tiptip_content = $("#tiptip_content");
var tiptip_arrow = $("#tiptip_arrow");
}
return this.each(function(){
var org_elem = $(this);
if(opts.content){
var org_title = opts.content;
} else {
var org_title = org_elem.attr(opts.attribute);
}
if(org_title != ""){
if(!opts.content){
org_elem.removeAttr(opts.attribute); //remove original Attribute
}
var timeout = false;
if(opts.activation == "hover"){
org_elem.hover(function(){
active_tiptip();
}, function(){
if(!opts.keepAlive){
deactive_tiptip();
}
});
if(opts.keepAlive){
tiptip_holder.hover(function(){}, function(){
deactive_tiptip();
});
}
} else if(opts.activation == "focus"){
org_elem.focus(function(){
active_tiptip();
}).blur(function(){
deactive_tiptip();
});
} else if(opts.activation == "click"){
org_elem.click(function(){
active_tiptip();
return false;
}).hover(function(){},function(){
if(!opts.keepAlive){
deactive_tiptip();
}
});
if(opts.keepAlive){
tiptip_holder.hover(function(){}, function(){
deactive_tiptip();
});
}
}
function active_tiptip(){
opts.enter.call(this);
tiptip_content.html(org_title);
tiptip_holder.hide().removeAttr("class").css("margin","0");
tiptip_arrow.removeAttr("style");
var top = parseInt(org_elem.offset()['top']);
var left = parseInt(org_elem.offset()['left']);
var org_width = parseInt(org_elem.outerWidth());
var org_height = parseInt(org_elem.outerHeight());
var tip_w = tiptip_holder.outerWidth();
var tip_h = tiptip_holder.outerHeight();
var w_compare = Math.round((org_width - tip_w) / 2);
var h_compare = Math.round((org_height - tip_h) / 2);
var marg_left = Math.round(left + w_compare);
var marg_top = Math.round(top + org_height + opts.edgeOffset);
var t_class = "";
var arrow_top = "";
var arrow_left = Math.round(tip_w - 12) / 2;
if(opts.defaultPosition == "bottom"){
t_class = "_bottom";
} else if(opts.defaultPosition == "top"){
t_class = "_top";
} else if(opts.defaultPosition == "left"){
t_class = "_left";
} else if(opts.defaultPosition == "right"){
t_class = "_right";
}
var right_compare = (w_compare + left) < parseInt($(window).scrollLeft());
var left_compare = (tip_w + left) > parseInt($(window).width());
if((right_compare && w_compare < 0) || (t_class == "_right" && !left_compare) || (t_class == "_left" && left < (tip_w + opts.edgeOffset + 5))){
t_class = "_right";
arrow_top = Math.round(tip_h - 13) / 2;
arrow_left = -12;
marg_left = Math.round(left + org_width + opts.edgeOffset);
marg_top = Math.round(top + h_compare);
} else if((left_compare && w_compare < 0) || (t_class == "_left" && !right_compare)){
t_class = "_left";
arrow_top = Math.round(tip_h - 13) / 2;
arrow_left = Math.round(tip_w);
marg_left = Math.round(left - (tip_w + opts.edgeOffset + 5));
marg_top = Math.round(top + h_compare);
}
var top_compare = (top + org_height + opts.edgeOffset + tip_h + 8) > parseInt($(window).height() + $(window).scrollTop());
var bottom_compare = ((top + org_height) - (opts.edgeOffset + tip_h + 8)) < 0;
if(top_compare || (t_class == "_bottom" && top_compare) || (t_class == "_top" && !bottom_compare)){
if(t_class == "_top" || t_class == "_bottom"){
t_class = "_top";
} else {
t_class = t_class+"_top";
}
arrow_top = tip_h;
marg_top = Math.round(top - (tip_h + 5 + opts.edgeOffset));
} else if(bottom_compare | (t_class == "_top" && bottom_compare) || (t_class == "_bottom" && !top_compare)){
if(t_class == "_top" || t_class == "_bottom"){
t_class = "_bottom";
} else {
t_class = t_class+"_bottom";
}
arrow_top = -12;
marg_top = Math.round(top + org_height + opts.edgeOffset);
}
if(t_class == "_right_top" || t_class == "_left_top"){
marg_top = marg_top + 5;
} else if(t_class == "_right_bottom" || t_class == "_left_bottom"){
marg_top = marg_top - 5;
}
if(t_class == "_left_top" || t_class == "_left_bottom"){
marg_left = marg_left + 5;
}
tiptip_arrow.css({"margin-left": arrow_left+"px", "margin-top": arrow_top+"px"});
tiptip_holder.css({"margin-left": marg_left+"px", "margin-top": marg_top+"px"}).attr("class","tip"+t_class);
if (timeout){ clearTimeout(timeout); }
timeout = setTimeout(function(){ tiptip_holder.stop(true,true).fadeIn(opts.fadeIn); }, opts.delay);
}
function deactive_tiptip(){
opts.exit.call(this);
if (timeout){ clearTimeout(timeout); }
tiptip_holder.fadeOut(opts.fadeOut);
}
}
});
}
})(jQuery);
#tiptip_holder
{
display: none;
position: absolute;
top: 0;
left: 0;
z-index: 99999;
}
#tiptip_holder.tip_top
{
padding-bottom: 5px;
}
#tiptip_holder.tip_bottom
{
padding-top: 5px;
}
#tiptip_holder.tip_right
{
padding-left: 5px;
}
#tiptip_holder.tip_left
{
padding-right: 5px;
}
#tiptip_content
{
font-size: 11px;
color: #fff;
text-shadow: 0 0 2px #000;
padding: 4px 8px;
border: 1px solid rgba(255,255,255,0.25);
background-color: #191919;
background-color: rgba(25,25,25,0.92);
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(transparent), to(#000));
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
box-shadow: 0 0 3px #555;
-webkit-box-shadow: 0 0 3px #555;
-moz-box-shadow: 0 0 3px #555;
}
#tiptip_arrow, #tiptip_arrow_inner
{
position: absolute;
border-color: transparent;
border-style: solid;
border-width: 6px;
height: 0;
width: 0;
}
#tiptip_holder.tip_top #tiptip_arrow
{
border-top-color: #fff;
border-top-color: rgba(255,255,255,0.35);
}
#tiptip_holder.tip_bottom #tiptip_arrow
{
border-bottom-color: #fff;
border-bottom-color: rgba(255,255,255,0.35);
}
#tiptip_holder.tip_right #tiptip_arrow
{
border-right-color: #fff;
border-right-color: rgba(255,255,255,0.35);
}
#tiptip_holder.tip_left #tiptip_arrow
{
border-left-color: #fff;
border-left-color: rgba(255,255,255,0.35);
}
#tiptip_holder.tip_top #tiptip_arrow_inner
{
margin-top: -7px;
margin-left: -6px;
border-top-color: #191919;
border-top-color: rgba(25,25,25,0.92);
}
#tiptip_holder.tip_bottom #tiptip_arrow_inner
{
margin-top: -5px;
margin-left: -6px;
border-bottom-color: #191919;
border-bottom-color: rgba(25,25,25,0.92);
}
#tiptip_holder.tip_right #tiptip_arrow_inner
{
margin-top: -6px;
margin-left: -5px;
border-right-color: #191919;
border-right-color: rgba(25,25,25,0.92);
}
#tiptip_holder.tip_left #tiptip_arrow_inner
{
margin-top: -6px;
margin-left: -7px;
border-left-color: #191919;
border-left-color: rgba(25,25,25,0.92);
}
/* Webkit Hacks */
@media screen and (-webkit-min-device-pixel-ratio:0)
{
#tiptip_content
{
padding: 4px 8px 5px 8px;
background-color: rgba(45,45,45,0.88);
}
#tiptip_holder.tip_bottom #tiptip_arrow_inner
{
border-bottom-color: rgba(45,45,45,0.88);
}
#tiptip_holder.tip_top #tiptip_arrow_inner
{
border-top-color: rgba(20,20,20,0.92);
}
}
当做完这些之后,我们开始设计前台页面调用:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<link href="[path]/Scripts/plugins/tooltip/tooltip.css" rel="stylesheet" type="text/css" />
</head>
<body>
<input type="text" id="name" class="textbox" title="请填写姓名" />
<input type="text" id="phone" class="textbox" title="请填写电话,格式:(010)87524576" />
<script src="[path]/Scripts/plugins/textbox/jquery-1.5.1.min.js" type="text/javascript"></script>
<script src="[path]/Scripts/plugins/textbox/jquery.textbox.js" type="text/javascript"></script>
<script src="[path]/Scripts/plugins/tooltip/jquery.tooltip.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#name").textbox({ label: "姓名" }).tooltip();
$("#phone").textbox({ label: "电话" }).tooltip();
});
</script>
</body>
</html>
当运行页面之后,你会发现文本框的提示效果:
是不是觉得比以前的alert以及模态框更有用户体验呢?我想就不用多言了吧。至此,我们做完了水印和提示的效果。总结一句话:插件的目的在于增加用户体验,封装所有细节,提供最简单的调用接口。 有兴趣的朋友在这里下载新版源码(解压后可以打开demo.htm欣赏效果)。 也许,这还没有完,我下一讲也将提供带图标的文本框以及智能感知效果的文本框,这些留给大家思考,我会逐步扩展并提供最终实现,欢迎交流。