所謂的介面觸控效果,就是使用者點下去的時候,介面立刻產生變化以反饋給使用者知道:“ok,你點擊的吩咐,我已曉得羅~”,也有人說“點擊高亮的效果”。——毋庸置疑,這是人機互動中非常重要溝通手段,使用得也非常常見的。當時我要實現這效果的時候,自己還滿認為,不就是網頁上為連結加個 a:hover 效果嘛~連結不行的加個“圖片翻轉”不就可以了。——熟料,在移動終端上,花費的時間遠超想像。首先,我傾向於採用純樣式的方法,大體思路是:普通狀態寫一種樣式;使用者點擊後歸為另外一種狀態,寫出其狀態對應樣式。這樣,我立刻想到的時“元素:hover”。經測試
PC 上無問題,但手機上尤其清單控制項顯得過於靈敏,有時與滾動事件衝突,有時出現奇怪的 bug,於是想想,不應使用 hover,應是採用“元素:active”才對(active 意即“擊中”那一下,hover 僅僅“移上”意思)。改用 active 後,上述問題立即迎刃而解。簡單說,actice 效果與 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 與 acitve 意思雖貼近,但細作起來還是有區別,以往案頭大多用 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 Highlightul.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 Highlightul.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 JdropJdrop 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>
使用了事件委託比較合理。