方法:iOSにカーソルを合わせると...

誰にとっても、タッチデバイスがデスクトップブラウザでのようにではなく、少し異なる方法でマウスイベントを処理することは秘密ではないと思います...



私にとって最も印象的な例は、疑似クラス:hover



です。 たとえば、iOS7は、クリックイベントが要素またはその親に関連付けられていない限り、ホバーに応答しません。 これは、この例ではっきりとわかります。jsfiddle.net / H8EmG-テキストをいくつ指で突いても、アンダースコアは表示されません。 また、この例では、 jsfiddle.net / H8EmG / 1がテキストに指を「 突っ込む 」と下線が引かれます。 興味深い事実-別の要素に突入するまで、テキストはホバーの下に置かれます...



別の興味深い例は、ホバー要素の処理です: jsfiddle.net/ASRm9/1テキストをクリックしてみてください。 最初に、行内に「HOVER!」というテキストが表示されますが、2回目に押すとすでにalert('click')



トリガーされalert('click')



。 これは、iOSが:hover



が隠されていることを理解し、サイトの作成者が侵入した動作を中断させないようにするためです。



しかし、これまで説明できなかったこのようなバグに遭遇すると、それをローカライズするためにiPadでデバッグするのに1日以上かかりました...私にとっては、詳細、そして賢い方法が必要です。すぐに-猫の下で、してください...







突然、サービスの次の更新後、私の「プラットフォーム」の開発者である不快な問題が明らかになりました-iPadでは、サービスにあるほとんどすべての「テーブル」で単一の行を選択できません。 「クリック」は機能しません! 「テーブル」は単なる行と列ではないことに注意してください。 私たちの場合、これはノート、ソート、グループ化、フィルター、あらゆる種類の「はしご」が印刷されてPDFおよびExcelにエクスポートされた、かなり「リッチな」UI要素です。



問題を長く退屈にローカライズした後、私たちは同様の結果をもたらしたHTML + CSSの孤立したシンプルな部分を強調しました...







次に例を示します。jsfiddle.net / 822eG / 4 。 テーブルの行をクリックしてみてください。 ホバーは機能しますが(「チェックボックス」が表示されclick



)、 click



(およびalert



alert



、線をclick



しないようにする方法は表示されません。



このテーマで、私はSOに投稿を開始しました) -webkit-overflow-scrolling: touch



jsFiddleの例では実際には役立ちましたが、実際のアプリケーションでは役に立たなかったタブレットコンテナーを-webkit-overflow-scrolling: touch



します。



この混乱について考える過程で、次の解決策が出てきました(SOに関する質問に対する私自身の答え)-どうすれば:hover



、コードで「ラップ」され、 mouseenter



/ mouseleave



キャッチするCSSクラスに置き換えられますか? この簡単な修正は本当にすべてを解決します。 「楽しい」でさえ機能し始めます-これ以上ダブルクリックする必要はありません。 最初のプレスから、アラートと「チェックボックス」の両方を取得します: jsfiddle.net/822eG/10



より良い選択肢がないため、彼らはこれについて考え始めました...実際、非常に大きなコードベースがあります。 このプラットフォームに基づいた「プラットフォーム」コードと「アプリケーション」コードの両方がたくさんあります。 そして、誰が、誰が、どこで、いつ、どのような条件で使用したいのかを知っています。ホバーと、何かを隠したいのか、見せたいのか。 一般に、「すべてを単独で」持つ必要があり、平均的な開発者はiOSの問題について考えませんでした。



その結果、次のソリューションが得られました。







幸いなことに、それは非常に単純であることが判明しました...各styleSheet



にはrules



コレクションが含まれ、これにはルール自体が含まれます。 各ルールには、外出先で変更できるselectorText



プロパティがあります。 また、最初に、このスタイルで定義された一連のプロパティを含むstyle



コレクションがあります。これらは「配列」として保存されます。 style



.length



、長さをソートして、このスタイルで変更されたすべてのプロパティを取得します。 次に、 style



には変更されたプロパティの値が含まれます。 プロパティの名前に等しいインデックスには、プロパティの値が格納されます。



つまり、たとえばCSSコードがある場合:



 .myClass:hover .block, .myItem:hover .element { color: red; display: block; }
      
      







このルールにはselectorText == '.myClass:hover .block, .myItem:hover .element'



style.length == 2



style[0] == 'color'



style[1] == 'display'



style.color == 'red'



およびstyle.display == 'block'







それ以外はすべて技術の問題です...



残念ながら、ルールの主要なバイパスが(スタイルとリンクタグのボリュームで)すぐに機能しないことが判明しました...プロファイリングは、 rules



へのアクセスに時間がかかることを示しました。 おそらくWebKitはこのプロパティを遅延的に初期化し、最初の呼び出しでスタイルの深い解析を開始してオブジェクトのセットにします。



結果は次のとおりです。



 $(document).ready(function(){ // ,    ,     if (!$ws._const.browser.isMobileSafari) { return; } var $body = $('body'); //     function addPseudoHover() { this.classList.add('ws-pseudo-hover'); } //     "" function removePseudoHover() { this.classList.remove('ws-pseudo-hover'); } //   [].filter(...) function uniq(item, index, array) { return array.indexOf(item, index + 1) == -1; } function trimHoverBase(selector) { return selector.substr(0, selector.indexOf(':hover')).trim(); } function filterHoverSelectors(selector) { return selector.indexOf(':hover') != -1; } function createBodyDelegate(hoverSelector){ $body.delegate(hoverSelector, 'mouseenter', addPseudoHover); $body.delegate(hoverSelector, 'mouseleave', removePseudoHover); } function processMutationRecord(mutationRecord) { var needRefresh = false; if (mutationRecord.addedNodes) { for(var i = 0, l = mutationRecord.addedNodes.length; i < l; i++) { if (mutationRecord.addedNodes[i].nodeName == 'LINK') { needRefresh = true; break; } } } if (needRefresh) { checkStylesheetSetDebonuced(); //       } } function checkStylesheetSet() { var allHoverSelectors = [], allRules = [], sheet, sheetCheckResult; for(var i = 0, l = document.styleSheets.length; i < l; i++) { sheet = document.styleSheets[i]; // ,      if (sheet.processed || sheet.rules.length === 0) { continue; } sheetCheckResult = checkCSSRuleSet(sheet); if (sheetCheckResult.rules.length > 0 && sheetCheckResult.selectors.length > 0) { Array.prototype.push.apply(allHoverSelectors, sheetCheckResult.selectors); Array.prototype.push.apply(allRules, sheetCheckResult.rules); } //           sheet.processed = true; } //   allRules.forEach(function(aRule){ aRule.selectorText = aRule.selectorText.replace(':hover', '.ws-pseudo-hover'); }); //   ,    body allHoverSelectors.map(trimHoverBase).filter(uniq).forEach(createBodyDelegate); } var checkStylesheetSetDebonuced = checkStylesheetSet.debounce(420); function checkCSSRuleSet(sheet) { var result = { selectors: [], rules: [] }; for(var i = 0, l = sheet.rules.length; i < l; i++) { var rule = sheet.rules[i]; if (rule.styleSheet && rule.href /* instanceof CSSImportRule*/) { //    @import checkCSSRuleSet(rule.styleSheet); } else if (rule.selectorText /* instanceof CSSStyleRule*/) { var hoverSelectors = getHoverSelectors(rule); if (hoverSelectors.length > 0) { if (checkStyles(rule)) { Array.prototype.push.apply(result.selectors, hoverSelectors); result.rules.push(rule); } } } } return result; } function checkStyles(rule) { for(var i = 0, l = rule.style.length; i < l; i++) { var styleItem = rule.style[i]; if (styleItem == 'display' && rule.style.display !== 'none') { return true; } if (styleItem == 'visibility' && rule.style.visibility !== 'hidden') { return true; } } return false; } function getHoverSelectors(rule) { return rule.selectorText.split(',').filter(filterHoverSelectors); } //      head new MutationObserver(function(mutationRecords){ mutationRecords.forEach(processMutationRecord); }).observe(document.getElementsByTagName('head')[0], { childList: true }); });
      
      







いくつかのリンク:




All Articles