想做一个幽灵按钮出来,效果大概如下图:
当点击按钮的时候,会有四根线条从四个方向飞入,经历从“无-有-无”的闪入过程。
那么我的设计想法是,先在HTML中定义一个按钮,然后在jQuery中设计按钮点击事件,当点击事件发生后,添加四个控件,即四根线,并且为他们设计animation。
先看一下HTML中的布局:
<div id="magic-test">
<div class="am-btn am-btn-success magic-button" id="magicbtn">魔法按钮</div>
</div>
这里使用到了amazeui的css样式,而".magic-button"只是调整一下按钮的位置。
那么在jQuery中,比如要设计右边那条横线,应该这样写:
$(function(){
var rline = '<div class="magic-line1" id="rline"></div>';
var $magicbtn = $('#magicbtn');
var x = $magicbtn.position();
var topvalue = x.top; // 按钮在包含其容器中的顶部坐标
var botvalue = topvalue + $magicbtn.outerHeight(true);
var leftvalue = x.left; // 按钮在包含其容器中的左边界坐标
var rightvalue = leftvalue + $magicbtn.outerWidth(true);
$('#magicbtn').on('click', function(){
$('#rline').css({
position: 'absolute',
left: rightvalue + 200 + 'px',
top: topvalue + 'px',
width: 0
});
$('#magic-test').append(rline);
})
})
a) 这里先解释一下关于控件位置定位的一些函数。
1. 首先看到.position(),这个函数返回的值是当前控件在包含其的容器中的相对位置,在这里就是说,$magicbtn在$magic-test中的相对位置,返回值有两个属性:top和left。
(更加expert的说法是:使用position()方法时事实上是把该元素当绝对定位来处理,获取的是该元素相当于最近的一个拥有绝对或者相对定位的父元素的偏移位置。)
对比一下.offset().top(),我查了一下,这个函数返回的是在整个页面(视窗)中的偏移量.
2. .outerWidth和.outerHeight,这个是整个控件的宽度和高度,包括其外边距。
3. css中的position:absolute,所设定的位置是相对于其父元素(定义为绝对或者相对定位)的位置,比如"top: topvalue + 'px'",就是其顶部相对于$magic-test顶部的位置,也就是与$magicbtn同高
position:relative,就是相对元素static定位时的位置进行偏移(相对自己默认位置偏移),如果指定static时top是50象素,那么指定relative并指定top是10象素时,元素实际top就是60象素了。
b) 但是这段代码的效果让我瞠目结舌,首先点击按钮后,横线出现在了按钮的下一行位置,再点一次,终于出现在了按钮的右侧。。。
出现在下一行是什么情况?很简单,就是#rline的css属性没有赋值成功,这样它的默认定位就会在按钮的下一行。
这如何理解呢?那我的理解只能是,在click事件发生后,.css()和.append()同时执行了,这有点迷。。
处理方法很简单:把css的赋值函数放到on()的外面,即在文档加载完成后,rline的css属性就已经赋值完成了,这样,点击按钮就会出现右边的线条。
这样,异步的问题算是解决了,但是效果不能这么做啊!要知道,我们要的效果是:每次点击按钮,线条都经历“无-有-无”的事件,也就是css样式的赋值还是得放在click事件中。
那怎么办呢?我想了一下,只能是在点击事件之前,先声明这四根线的存在,也就是先把这四根线append到$magic-test中,而且还不能同时给css样式,得在on()里面给,最终代码如下:
$(function(){
var rline = '<div class="magic-line1" id="rline"></div>';
var tline = '<div class="magic-line2" id="tline"></div>';
var lline = '<div class="magic-line1" id="lline"></div>';
var bline = '<div class="magic-line2" id="bline"></div>';
var $magicbtn = $('#magicbtn');
var x = $magicbtn.position();
var topvalue = x.top;
var botvalue = topvalue + $magicbtn.outerHeight(true);
var leftvalue = x.left;
var rightvalue = leftvalue + $magicbtn.outerWidth(true);
$('#magic-test').append(rline);
$('#rline').hide();
$('#magic-test').append(tline);
$('#tline').hide();
$('#magic-test').append(lline);
$('#lline').hide();
$('#magic-test').append(bline);
$('#bline').hide();
$('#magicbtn').on('click', function(){
$('#rline').css({
position: 'absolute',
left: rightvalue + 200 + 'px',
top: topvalue + 'px',
width: 0
});
$('#rline').show();
$('#rline').animate({
width:$magicbtn.outerWidth(true)+'px', //outer是包括外边框的整个控件的大小
left: leftvalue
},500);
$('#tline').css({
position: 'absolute',
left: leftvalue,
top: topvalue - 120 + 'px',
height: 0
});
$('#tline').show();
$('#tline').animate({
top : topvalue,
height: $magicbtn.outerHeight(true)+'px'
},500)
$('#lline').css({
position: 'absolute',
left: leftvalue - 120 + 'px',
top: botvalue -1 + 'px', //减一是考虑到了线宽
width: 0
});
$('#lline').show();
$('#lline').animate({
left: leftvalue,
width: $magicbtn.outerWidth(true)+'px' // 按钮的宽度
}, 500)
$('#bline').css({
position: 'absolute',
left: rightvalue -1 +'px',
top: botvalue + 'px'
});
$('#bline').show();
$('#bline').animate({
top: topvalue,
height: $magicbtn.outerHeight(true)+'px'
})
})
})
这段代码的思想是:先在文档生成的时候,把四根线条赋为$magic-test的子元素,暂时先将其隐藏起来。在click事件产生后,立马将这四根线条定位到按钮的四周,长度先设为0,状态为show。
之后再设置动画事件,使得线长由0变到按钮的长度/宽度,并且与按钮重合,产生“消失”的效果。
这样,每次点击按钮时,都会重复,“线宽0” -> "变长" -> "与按钮重合"的操作。
其实,更加聪明一点的写法时,从一开始就把线条作为$magic-test的子元素写在HTML代码中,并且在css样式中设置“未点击”时的状态,以及点击时的状态(:active),这样就不用再js中那么繁琐地实现动画效果了。