记一次 JS 模拟 CSS active 效果的过程

简介: 所谓的界面触控效果,就是用户点下去的时候,界面立刻产生变化以反馈给用户知道:“ok,你点击的吩咐,我已晓得罗~”,也有人说“点击高亮的效果”。——毋庸置疑,这是人机交互中非常重要沟通手段,使用得也非常常见的。

所谓的界面触控效果,就是用户点下去的时候,界面立刻产生变化以反馈给用户知道:“ok,你点击的吩咐,我已晓得罗~”,也有人说“点击高亮的效果”。——毋庸置疑,这是人机交互中非常重要沟通手段,使用得也非常常见的。当时我要实现这效果的时候,自己还满认为,不就是网页上为链接加个 a:hover 效果嘛~链接不行的加个“图片翻转”不就可以了。——孰料,在移动终端上,花费的时间远超想像。首先,我倾向于采用纯样式的方法,大体思路是:普通状态写一种样式;用户点击后归为另外一种状态,写出其状态对应样式。这样,我立刻想到的时“元素:hover”。经测试 PC 上无问题,但手机上尤其列表控件显得过于灵敏,有时与滚动事件冲突,有时出现奇怪的 bug,于是想想,不应使用 hover,应是采用“元素:active”才对(active 意即“击中”那一下,hover 仅仅“移上”意思)。改用 active 后,上述问题立即迎刃而解。简单说,active 效果与 hover 效果相比,就是 active 点击后会撤销手指松开的样式。

/* 普通效果 */
.x_list li {
    padding: 3px;
    width: 100%;
    list-style: none;
    background-color: #999;/*普通效果的背景色*/
    border-bottom: 1px solid #333;
    border-top: 1px solid white;
    clear: both;
    display: inline-table;
    position: relative;
}
/* 点击效果 */
.x_list li:active{
    background-color:red;
}

看来,hover 与 active 意思虽相近,但细作起来还是明显差别。以往讨论桌面的时候,大多用 hover 即可,而现如今在手机上却把两者的区别给凸显出来了。我想,这是什么缘故呢,——为什么以往桌面的做法行得通,而手机上却把问题暴露出来呢。我觉得,执行“事件的媒介”也是重要的原因,因为桌面上输入事件的乃鼠标器居多,而且手机上则围绕手指触控的居多。两者的分野,导致所处于的经验与法则也不尽相同。可以说,承接下来的那个 bug,都有同样的缘故在作祟。

可是,即使使用 active,又遇到浏览器支持的问题:——Android 2.x 仍不支持元素:active,新版的 Android 4.x 和 iOS 则顺利通过。于是我安排 iOS 与 Android 4 就用 CSS 的写法,而 Android 另一边厢安排 js 方法实现之。

既然用 js 方法实现之,我第一时间想到的用 setTimeout() 定时器实现之。点击后添加一样式,timeout 之后撤销样式。

// 用户按下之后,为元素加入高亮样式,然后立刻消褪,——这就是所谓的 active 样式。
// 请注意,这个方法属于“反面教材”
function onActive(el, fn){
	el.addCls('active');
	setTimeout(function(){
		fn && fn();
		el.removeCls('active');
	}, 300);
}

这个貌似可行的办法实则不正确!因为经过领导演示,人家 Sencha Touch 的选中高亮是可以跟随滚动的,我的在首页上的点击高亮是可以但不会响应点击滚动,有反常理!甚幸,恰恰有正确的案例在前,让我可以参照,可以纠正。后来结果通过 touchstart/touchend 事件实现这个界面触控效果。代码如下:

HTMLElement.prototype.onActive = (function () {
	/**
	 * this 应为 CSS Selector
	 * @param {Event} e
	 */
	function highlight(e){
		var targetEl = e.target;
		if(targetEl && targetEl.tagName == this.toUpperCase()){
			targetEl.toggleCls('active');
		}else if(targetEl){
			arguments.callee.call(this, {
				target : targetEl.parentNode
			});
		}
	}

    // 是否支持触摸事件
    var isSupportTouch = 'ontouchstart' in window || "ontouchend" in window.document;
	// 支持触摸式使用相应的事件替代
	var hightEvent_in  = isSupportTouch ? 'touchstart': 'mouseover',
		hightEvent_out = isSupportTouch ? 'touchend' : 'mouseout';

    /**
      * @param {String} highlightCfg
      */
    return function(el_cssSelector){
    	// ONLY FOR Moblie?
    	if (!window.navigator.isAndroid_2) {
    		return false;
    	}
    	var eventHandler = highlight.bind(el_cssSelector || 'LI'); // 默认 li 修改样式
    	// $$.addListener 为跨浏览器的事件添加器
		$$.addListener(this,  hightEvent_in, eventHandler);
		$$.addListener(this, hightEvent_out, eventHandler);
//		$$.addListener(this, 'touchcancel',eventHandler, isUseCapture); /*@todo考察该事件,比较特殊*/
		 return this; // 方便链式调用
	}
})();
上述代码扩展的浏览器原生对象 HTMLElment 原型,因此在任一元素身上都有 onActive 方法,另外 toggleCls(className) 也是通过扩展元素原型来提供的。相应地,样式不经过伪类来实现,而是定义一个 .active 的样式类:

/* 点击效果 */
.x_list li.active{ /* 注意这里冒号被改为点号*/
    background-color:red;
}

函数 highlight 中,因为登记事件时不能触发 userCapture,所以没有使用“事件冒泡”的方式而是递归上报的方式。

2013-4-7 重新整理一下这个函数,请注意这是没有版本检测,你应该自己加一个,因为只针对 android 2.x。

/**
 * 模拟 el:active
 * @param {Element} ul 参数为元素
 */
function onActive(ul){
	// ONLY FOR Android 2.x? Yes!
	// 检测是否 android 2.x 的属性,你可以依赖你自己的方案,我的就不贴了,比较简单的。
	// if (!window.navigator.isAndroid_2) {
		// return ul; //尽管该函数不工作,也要返回 this,以方便链式调用
	// }
	
	// add Highlight
	ul.addEventListener('touchstart', function (e){
		var targetEl = e.target;
		while(targetEl && targetEl.tagName != 'LI'){// 默认为 li 修改样式
			targetEl = targetEl.parentNode; 		// 找到要操作的目标元素为止
		}
		// do sth……
		console.log(targetEl.tagName);
		targetEl.addCls('active');
	});

	// remove Highlight
	ul.addEventListener('touchend',   function (e){
		var targetEl = e.target;
		while(targetEl && targetEl.tagName != "LI"){
			targetEl = targetEl.parentNode; // 找到要操作的目标元素为止
		}
		// do sth……
		console.log(targetEl.tagName);
		targetEl.removeCls('active');
	}); 
	
	return ul; // 方便链式调用
}

CSS 样式如下:

/* 点击效果 */
ul.x_list li:active, ul.x_list li.active {
    background-image: -webkit-gradient(linear, center top, center bottom, from(lightGrey), to(white));
}

2013-04-18 把问题重新整理了一下,给出如下“药方”:

<style type="text/css">
p:active, p.active{
	background-color:red;
}
</style>
<body>
	<p>Welcome to Jdrop
Jdrop provides a place to store JSON data in the cloud. The initial application is for storing performance data gathered from mobile devices. It's hard to analyze large amounts of information (HTTP waterfall charts, HTTP headers, document source, etc.) on a mobile device. Jdrop lets you gather this data on the mobile device but analyze it remotely on a larger screen. </p>
</body>
<script type="text/javascript">
	document.addEventListener('touchstart', function (e) {
		e.target.className = 'active';
	}, false);
	document.addEventListener('touchend', function (e) {
		e.target.className = '';
	}, false);
</script>
使用了事件委托比较合理。

目录
相关文章
|
3月前
|
移动开发 前端开发 JavaScript
征信报告修改器,征信报告生成器,制作软件无痕修改软件【js+html+css】
本项目为信用评分模拟器教学工具,采用HTML5实现,仅供学习参考。核心功能通过JavaScript构建,包含虚拟数据生成、权重分配及信用因素分析(如还款记录、信用使用率等)。
|
3月前
|
前端开发 JavaScript
个人征信电子版无痕修改, 个人信用报告pdf修改,js+html+css即可实现【仅供学习用途】
本代码展示了一个信用知识学习系统的前端实现,包含评分计算、因素分析和建议生成功能。所有数据均为模拟生成
|
3月前
|
存储 前端开发 JavaScript
仿真银行app下载安装, 银行卡虚拟余额制作app,用html+css+js实现逼真娱乐工具
这是一个简单的银行账户模拟器项目,用于学习前端开发基础。用户可进行存款、取款操作,所有数据存储于浏览器内存中
|
3月前
|
前端开发
个人征信PDF无痕修改软件,个人征信模板可编辑,个人征信报告p图神器【js+html+css仅供学习用途】
这是一款信用知识学习系统,旨在帮助用户了解征信基本概念、信用评分计算原理及信用行为影响。系统通过模拟数据生成信用报告,涵盖还款记录
|
3月前
|
前端开发 JavaScript 容器
制作b超单生成器, 假怀孕b超单图片制作, p图医院证明【css+html+js装逼恶搞神器】
本资源提供一个适合用于熟人之间恶搞的工具,效果逼真,仅供学习参考与娱乐。包含前端技术学习要点:语义化布局、响应式设计、Flexbox、图片自适应
|
3月前
|
前端开发
医院检查单子p图软件,在线制作仿真病历,js+css+html装逼神器
本示例展示如何用HTML/CSS创建医疗信息页面,内容仅供学习参考。页面模拟“阳光医院体检中心”场景,提供预约功能验证(如姓名、手机号、日期)。所有数据仅用于演示
|
3月前
|
存储 自然语言处理 前端开发
抖音快手小红书虚拟评论截图生成器,模拟对话制作工具,html+js+css
这是一款纯前端实现的多平台虚拟评论生成器,支持抖音、快手、小红书风格,适用于产品演示与UI设计。采用Vanilla JS与Flexbox布局,利用IndexedDB存储数据,CSS Variables切换主题。
|
3月前
|
存储 前端开发 安全
病历单生成器在线制作,病历单生成器app,HTML+CSS+JS恶搞工具
本项目为医疗病历模拟生成器,旨在为医学教学和软件开发测试提供数据支持,严格遵守《医疗机构病历管理规定》。
|
3月前
|
前端开发 容器
处方单图片生成器, 处方单在线制作免费,js+css+html恶搞神器
这是一个电子处方模拟生成系统,使用html2canvas库实现图片导出功能。系统生成的处方单包含多重防伪标识,并明确标注为模拟数据,仅供学习