我们经常对html元素使用hover选择器来做一些效果,比如当鼠标放在一个a标签上时改变文字颜色:
a{color: #F4A801} //超链接的文字是橘黄色 a:hover{color: #FF0000} //当鼠标经过时变成红色
如果加上css3的一些过渡属性就会出现变化的过程,成为简单的css3动画。
但是之前我没想到 ::before 和 ::after 这俩伪元素也可以用类似hover的选择器触发它们的动画。今天见识到了,感觉很棒。
如下效果,当鼠标放到这个按钮上时会在底部展开一条线:
这个是怎么做的呢?
按钮是A标签,需要给它设置相对定位和超出隐藏:
a{position: relative;overflow: hidden;}
然后用::before伪元素在底部做一条线,只不过一开始没让这条线显示出来。::before伪元素需要设置绝对定位,这样可以让它位于按钮内部。
最后,当鼠标经过按钮时(hover)改变::before伪元素的css属性,如同文章开头的代码中改变a标签的属性一样,只是写法不同:
a:hover::before{ /*css属性*/ }
最终实现的代码如下:
<a href="" id="more">查看更多</a> <style> #more{display: inline-block;width: 150px;height: 48px;line-height: 48px;text-align: center;font-size: 20px;color: #fff;text-decoration: none !important;text-shadow:none !important;background: #8EE964; /*最后的por和ovh是必须的*/ position: relative;overflow: hidden; } #more:before{ /*设置初始状态*/ content: ""; position: absolute; left: 50%; right: 50%; bottom: 0; background: #ff9d2e; height:5px; /*transition-property 设置过渡时要改变的属性 若不设置则为all*/ transition-property: left, right; transition-duration: 0.3s; transition-timing-function: ease-out; } #more:hover:before, #more:focus:before, #more:active:before { /*当鼠标经过、或按钮被焦点、被激活时对before的属性进行改变*/ left: 0; right: 0; } </style>
ps:
我这次没使用::after伪元素,大家可以按需使用。
伪元素前面写两个冒号是符合标准的写法,写一个冒号是为了兼容比较旧的浏览器,实际使用中写一个或两个均可。
如有需要,也在hover外部定义动画,然后在hover内引用。如:
#more:hover:before, #more:focus:before, #more:active:before { animation:showUnderline .3s forwards; } @keyframes showUnderline { to{ left: 0; right: 0; } }
注意,@keyframes定义的动画和直接在样式里写的动画有区别:
以鼠标hover时执行动画为例,@keyframes定义的动画,当鼠标离开后没有逐渐恢复至原来状态的过程,而在元素样式内定义的则有。
以本文的按钮为例,@keyframes定义的动画,当鼠标离开按钮后那个底边不会逐渐向中间收缩,而是瞬间就消失了。
使用 ::before 和 ::after 伪元素来制作CSS3动画
我最近做了一个带下拉菜单的导航,学到了event.currentTarget的使用。
demo如下:
代码:
<nav> <ul> <li class="lelve1"> <a href="">下拉菜单</a> <div class="subNav"> <a href="">企业简介</a> <a href="">发展历程</a> <a href="">主营业务</a> </div> </li> </ul> </nav> <script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> <script> var isHover=false; $(".lelve1").mouseenter( function (event) { isHover=true; $(this).find(".subNav").fadeIn(); //$(event.currentTarget).find(".subNav").fadeIn(); } ); $(".lelve1").mouseleave( function (event) { isHover=false; var a=$(this); setTimeout(function () { if (!isHover) { a.find('.subNav').fadeOut(); //$(event.currentTarget).find(".subNav").fadeOut(); } },50) } ); </script>
因为鼠标进入、鼠标离开事件都是绑定在一级导航上的,所以操作子导航的显示、隐藏时,都是通过在一级导航的元素里寻找子元素达到的:
$(this).find(".subNav").fadeIn(); a.find('.subNav').fadeOut();
这时都是使用this来指代一级导航,但除了使用this,还有另一个办法,就是使用event.currentTarget。
那event.currentTarget是什么呢?event.currentTarget指向事件所绑定的元素。
我们的鼠标进入、鼠标离开都是绑定在一级导航上,所以event.currentTarget所指向的元素始终是一级导航,使用起来很方便,而且可靠。
this在多层事件函数嵌套时经常会发生改变。但如果使用event.currentTarget的话,在这个作用域链里,event.currentTarget都不会变。所以我觉得event.currentTarget更方便可靠。
ps:event的属性里有一个大概比event.currentTarget更常用的,是event.target,指向触发该事件的元素。
event.currentTarget指向事件所绑定的元素,而event.target始终指向事件发生时的元素。
以前我有个错误的认知,以为哪个元素绑定的事件,那么触发事件的元素也是这个元素。其实不是的,像本例,当鼠标从子导航上离开时,触发一级导航mouseleave事件的元素(event.target)是a标签,而不是一级导航li标签。
JavaScript中event.currentTarget的使用
今天看到一个代码,通过document.all函数判断浏览器是否是IE。代码大致是这样的:
if (document.all){ // 是IE }else{ // 不是IE }
这里面有个有意思的地方。
document.all函数会返回页面上所有html元素的集合,现在主流浏览器均支持,比如在chrome中执行一下:
在返回的集合中包含了页面上所有的html元素。
那么问题来了,既然chrome也支持这个函数,结果也不为空,这样判断时不应该是true吗?
试一下将其转换为布尔值,结果竟然是false!惊了!
其实,在IE之外的浏览器里,运行 typeof document.all ,得到的都是结果都是undefined。而在IE里就是object。
这个现象是有历史原因的。document.all最早是由IE4实现的,当时很多程序猿就通过document.all来判断是否是IE浏览器。后来其他浏览器也实现了document.all,但是又不想被旧程序判断为IE浏览器,所以就把document.all的类型设置为undefined了。
这样,在IE之外的浏览器里判断document.all就会得到false了。
ps:IE11里判断document.all也是false了,所以此方法已经不可靠。
在JavaScript中使用document.all来判断是否是IE浏览器
JavaScript中要对小数取整的话(单纯舍弃小数部分,不涉及四舍五入),有原生函数parseInt()。不过除此之外还有两种“歪门邪道”的写法,这三种写法合起来比较一下:
parseInt(10/3) // 返回 3 ~~(10/3) // 返回 3 10/3|0 // 返回 3
其实第二种的波浪号和第三种的竖线都是“位操作符”。
注意:
第二种写法是两个波浪线哦。一个波浪线是达不到取整效果的。
第三种写法的竖线和0是一个整体哦,不然也是达不到取整效果的。
JavaScript小数取整的3种方法
前两天做的项目中使用了SuperSlide,做了个焦点图切换效果和图片向左滚动展示的效果。使用时参照官方demo做了些细微改动,现在我再把代码单独存一份,方便以后使用。
1.焦点图切换(通屏):
2.图片向左滚动:
SuperSlide的demo
如果url中有特殊字符符号,可能会导致url不能被正确识别。
我们可以在传递参数前将url编码来解决这个问题。不过需要注意的是,有些字符在url中有独特的作用的(例如#表示锚点位置,&表示连接多个参数),所以JavaScript的encodeURI函数(意思是编码url)是不能编码这些有单独意义的字符的的。需要把它们也转码的话需要用encodeURIComponent函数(意思是编码url组件)。
下面直接列出一下有特殊含义的字符及其编码后的结果:
+ URL 中+号表示空格 %2B
空格 URL中的空格可以用+号或者编码 %20
/ 分隔目录和子目录 %2F
? 分隔实际的URL和参数 %3
% 指定特殊字符 %25
# 表示书签 %23
& URL 中指定的参数间的分隔符 %26
= URL 中指定参数的值 %3D
url参数中特殊字符的转义处理
一直以来,JavaScript对于鼠标事件和触摸事件提供的支持都比较初级,此问题在pc端不是很明显,但是移动端的触摸手势就比较多样化了,为此我们有必要使用js库来帮助我们处理触摸事件。
Hammer.JS是一款轻量级的移动设备触摸手势库,不依赖其他js库,兼容性好(支持WP),支持常见的点击、拖动、缩放、旋转等触摸事件,也可支持多点触控。
Hammer.JS支持的六大事件:
Hammer.JS支持在pc端浏览器上用鼠标模拟触摸事件,这样我们开发时可以在pc上进行测试,极大提高了开发效率(看它官网的描述,似乎是可以在pc上模拟出全部的6种动作。不过缩放和旋转我试不出来,按下shift模拟双指操作也没反应①)。
下面是一个左右滑动的示例:
var myElement =document.querySelector("#a"); var mc = new Hammer(myElement); mc.on("swipeleft swiperight", function(ev) { if (ev.deltaTime>100) { // 判断一下延迟时间,小于100ms的不处理 if (ev.deltaX>0) { //向右滑动,展示左侧内容 // code }else if (ev.deltaX<0) { //向左滑动,展示右侧内容 // code } } console.log(ev); });
hammer.js用起来还真是费了不少劲。
首先是它有好几个可以下载的地方,但不同的地方不但有的版本号不同,有些甚至完全不生效。我现在用的是https://hammerjs.github.io/dist/hammer.min.js。也可能是其他版本改了api?
第二是注意禁用浏览器自己的选择事件和拖动事件。
举个例子,网页中的图片是可以被拖动的。当你按下鼠标并移动来模拟滑动事件时,会发现图片变成了拖拽状态,这时候就触发不了hammer.js上绑定的事件了,所以要用css禁止拖动该元素。
拖动文字可能导致文字被选中,所以也要禁止选中该元素。
一开始我没发现这个事情,当我把可以正常使用的demo的代码移植到我的项目里之后,发现不生效,这让我郁闷了好久,最后琢磨出来是这个原因。
hammer.js会给直接绑定的元素自动增加禁止拖动和选择的属性,但如果该元素有子元素,则需要我们视情况对该处理的子元素进行处理。
hammer.js的使用说明也较少,所以有时候我们要输出ev来自己查看当前事件的一些属性。
参考资料1
移动端手势库hammerJS 2.0.4官方文档翻译
① 有资料说,pinch 和rotate 默认情况下是禁用的,因为他们会使元件闭锁(这里貌似是机翻),如有需要可以通过下面的方法调用:
hammertime.get('pinch').set({ enable: true }); hammertime.get('rotate').set({ enable: true });
不过我还没用到这个,没去试验。
移动设备触摸手势库——Hammer.JS
WordPress设置网站副标题需要到后台的设置项里设置,操作起来太繁琐,于是我用php做了个设置网站副标题的接口。这个没什么技术含量,主要是熟悉下php对mysql数据库的基本操作流程。
首先是到数据库里找到网站副标题的字段:
找到之后写出用于修改它的sql语句,如下:
UPDATE wp_options SET option_value = '大好き' WHERE option_name = 'blogdescription'
接下来做一个html文件和一个php文件,用html文件给php文件发送要设置的副标题,php接到请求后执行数据库操作。
功能做好之后,把html传到网站上,并保存成书签。以后想修改修改副标题只要打开这个书签,输入文字就可以了。
Read More →
用PHP做一个设置网站副标题的接口
JavaScript原生的document.querySelector和document.querySelectorAll方法很好用,不过依旧摆脱不了原生方法名太长的麻烦。所以我们可以封装下,如:
function $(selector) { return document.querySelector(selector) } function $$(selector) { return Array.prototype.slice.call(document.querySelectorAll(selector)) }
这里用了$、$$作为方法名,分别对document.querySelector方法和document.querySelectorAll方法进行封装。
$方法返回单个元素(第一个符合的元素),$$以数组形式返回所有符合的元素(即使符合的元素只有一个)。
这样我们就可以方便的使用封装的方法来选择DOM元素了:
$("#div .class img") $$("#div .class img")
不过如果$、$$的定义冲突了可能会出问题,所以如果页面上引用jQuery了的话,可以换个方法名。
ps:至于为什么方法名要用$和$$呢,并不是模仿jQuery,而是模仿chrome(至于chrome是不是模仿jQuery的方法名那我就不清楚了)。
chrome浏览器控制台里内置了封装好的$、$$方法,可以直接使用。(当然,如果$、$$的定义被页面上的代码覆盖了就不行了)
如图:
封装document.querySelector和document.querySelectorAll方法
更新:两年过去了,现在推荐使用 vw + rem 自适应布局。
我们页面布局中,可以通过动态设置rem并使用rem单位来设置宽高,来使得页面元素的尺寸可以随设备宽度而变化,这样就能保持布局的一致性。
使用JavaScript动态设置rem的代码如下:
(function (doc, win) { var docEl = doc.documentElement, resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize', recalc = function () { var clientWidth = docEl.clientWidth; if (!clientWidth) return; docEl.style.fontSize = 100 * (clientWidth / 640) + 'px'; }; if (!doc.addEventListener) return; win.addEventListener(resizeEvt, recalc, false); doc.addEventListener('DOMContentLoaded', recalc, false); })(document, window);
公式是这样的:
100 * ( 浏览器页面宽度 / 设计稿宽度 )
第一部分:100是什么
这个100其实是我们使用的rem基础值,等于设置html标签的font-size=100px,这样,1rem也就是100px。
当1rem为100px时,页面上所有元素设置宽高大小时都除以100,就得出了该元素的rem值。比如设计稿上300px宽的元素,用rem设置就是width=3rem。
1rem并不是非要设置为100px,我们也可以设置成别的,比如设置1rem=50px,那么300px的元素是6rem。我们一般取1rem=100px是为了方便计算。如果实际项目中计算页面元素的rem值时不是按1rem=100px来算的,则需要修改公式里的100为实际使用的1rem值。
第二部分:浏览器页面宽度 / 设计稿宽度 是什么
这个可以理解为页面在设备上的缩放比例。比如iphone 6 plus的设备宽度是414px,我们的设计稿是640px。
414/640=0.646875,得出我们的页面在iphone 6 plus上应该显示为设计稿大小的0.646875倍。
最后我们把rem的基础值与页面缩放比例相乘,得出实际使用的rem基础值。rem的基础值变了,页面上所有元素的宽高、大小也会随之改变,这样就达到了页面自适应的效果。
Read More →