2012-08-30 10 views
10

द्वारा एचटीएमएल तत्वों की तुलना करें एक ही दस्तावेज़ में दो अनियंत्रित HTML तत्व ए और बी को देखते हुए, मैं कैसे पता लगा सकता हूं कि उपयोगकर्ता के लिए कौन सा "नज़दीकी" है (यानी यदि वे ओवरलैप करते हैं, तो कौन सा दूसरे को अस्पष्ट कर रहा है)?वास्तविक जेड-इंडेक्स

W3C CSS Specification संदर्भों को ढेर करने का वर्णन करता है, जो अनुरूप प्रतिपादन इंजन को लागू करना चाहिए। हालांकि, मुझे जावास्क्रिप्ट प्रोग्राम, क्रॉस-ब्राउजर या नहीं में इस जानकारी तक पहुंचने का कोई तरीका नहीं मिला। मैं पढ़ सकता हूं कि सीएसएस z-index संपत्ति है, जो प्रति से अधिक नहीं कहती है, क्योंकि अधिकांश समय auto पर सेट किया गया है या यहां तक ​​कि जब संख्यात्मक मान के रूप में व्यक्त किया गया है, यह वास्तव में प्रदर्शित होने के तरीके के विश्वसनीय संकेतक नहीं है (यदि वे अलग-अलग स्टेटकिंग संदर्भों से संबंधित हैं, जेड-इंडेक्स की तुलना करना अप्रासंगिक है)।

कृपया ध्यान दें कि मुझे मनमानी तत्वों में रुचि है: यदि दोनों तत्व माउस पॉइंटर से नीचे हैं, तो केवल एक को "आच्छादित" माना जाएगा, इसलिए मैं आसानी से इस मामले में सबसे नज़दीकी से ढूंढ सकता हूं। हालांकि, मैं एक और सामान्य समाधान की तलाश में हूं, अधिमानतः एक जिसमें स्टैकिंग एल्गोरिदम को दोबारा लागू करने में शामिल नहीं है कि प्रतिपादन इंजन पहले से ही प्रदर्शन कर रहा है।

अद्यतन: मुझे थोड़ी इस सवाल के पीछे कारण स्पष्ट करते हैं: मैं हाल ही में a question कि jQuery के खींचें और ड्रॉप तंत्र में एक सीमा से अवगत कराया घेरने की कोशिश की है - यह ध्यान में z-अनुक्रमित नहीं ले करता है जब छोड़ने, तो एक अगर तत्व दूसरे को अस्पष्ट कर रहा है, यह अभी भी "पीछे" तत्व में ड्रॉप ऑपरेशन कर सकता है। जबकि ओपी विशेष मामले के लिए जुड़े प्रश्न का उत्तर दिया गया था, सामान्य समस्या बनी रहती है, और मुझे कोई आसान समाधान नहीं है।

नीचे alex's answer उपयोगी है, लेकिन नहीं हाथ में मामले के लिए पर्याप्त है: जब खींच, घसीटा तत्व में ही (या अधिक सटीक इसकी सहायक) माउस कर्सर के तहत सर्वोच्च तत्व है, इसलिए elementFromPoint वापस आ जाएगी यह बजाय अगला सबसे ऊपर तत्व, हमें वास्तव में आवश्यकता है (वर्कअराउंड:style the cursor इसलिए इसे सहायक के बाहर रखा गया है)। JQuery की अन्य चौराहे की रणनीतियों को भी एक बिंदु से अधिक ध्यान में रखना है, जो किसी भी तरह से सहायक को छेड़छाड़ करने वाले शीर्ष तत्व को निर्धारित करने के कार्य को जटिल बनाते हैं। वास्तविक जेड-इंडेक्स द्वारा तत्वों की तुलना करने (या क्रमबद्ध) करने में सक्षम होने से सामान्य मामले के लिए एक "जेड-इंडेक्स अवगत" चौराहे मोड व्यवहार्य हो जाएगा।

उत्तर

1

कुछ दिनों के शोध के बाद मुझे लगता है कि मैंने 2016 के नियमों के अनुसार स्टैकिंग तंत्र को सफलतापूर्वक दोबारा कार्यान्वित किया है। मैंने मूल रूप से 2013 दृष्टिकोण (ओपी द्वारा पोस्ट किया गया) अपडेट किया है। नतीजा एक ऐसा फ़ंक्शन है जो दो डोम नोड्स की तुलना करता है, और जो शीर्ष पर दृश्यमान है उसे लौटाता है।

front = $.fn.visuallyInFront(document.documentElement, document.body); 
// front == <body>...</body> because the BODY node is 'on top' of the HTML node 

तर्क

वहाँ निर्धारित करने के लिए जो तत्व दूसरे के शीर्ष पर है अन्य तरीके हैं। उदाहरण के लिए document.elementFromPoint() या document.elementsFromPoint() वसंत को ध्यान में रखें। हालांकि, ऐसे कई (अनियंत्रित) कारक हैं जो इन विधियों की विश्वसनीयता को प्रभावित करते हैं। उदाहरण के लिए, अस्पष्टता, दृश्यता, सूचक-घटनाएं, बैकफ़ेस-दृश्यता और कुछ परिवर्तन document.elementFromPoint() एक विशिष्ट तत्व का परीक्षण करने में असमर्थ हो सकते हैं। और फिर यह मुद्दा है कि document.elementFromPoint() केवल शीर्ष-तत्व (अंतर्निहित नहीं) से पूछताछ कर सकता है। इसे document.elementsFromPoint() के साथ हल किया जाना चाहिए, लेकिन वर्तमान में केवल क्रोम में लागू किया गया है। इसके अलावा, मैंने क्रोम डेवलपर्स के साथ document.elementsFromPoint() के साथ एक बग दायर की। जब एक एंकर टैग का परीक्षण मारा जाता है, तो सभी अंतर्निहित तत्व अनजान होते हैं।

इन सभी मुद्दों ने संयुक्त रूप से मुझे स्टैकिंग तंत्र के पुन: कार्यान्वयन का प्रयास करने का निर्णय लिया। इस दृष्टिकोण का लाभ यह है कि स्टैकिंग तंत्र को काफी व्यापक रूप से दस्तावेज किया गया है और इसका परीक्षण और समझा जा सकता है।

यह कैसे काम करता

मेरे दृष्टिकोण को फिर से लागू करता है एचटीएमएल स्टैकिंग तंत्र। इसका उद्देश्य उन सभी नियमों का सही पालन करना है जो HTML तत्वों के स्टैकिंग ऑर्डर को प्रभावित करते हैं। इसमें पोजीशनिंग नियम, फ्लोट्स, डीओएम ऑर्डर, लेकिन CSS3 गुण जैसे ओपेसिटी, ट्रांसफॉर्म और फ़िल्टर और मास्क जैसे अधिक प्रायोगिक गुण शामिल हैं। नियम मार्च 2016 के रूप में सही ढंग से कार्यान्वित किए जाने लगते हैं, लेकिन भविष्य में अद्यतन होने की आवश्यकता होगी जब विनिर्देश और ब्राउज़र समर्थन में परिवर्तन होगा।

मैंने सबकुछ GitHub repository में एक साथ रखा है। उम्मीद है कि यह दृष्टिकोण भरोसेमंद काम करना जारी रखेगा। कार्रवाई में कोड के example JSFiddle यहां है। उदाहरण में सभी तत्वों को वास्तविक 'जेड-इंडेक्स' द्वारा क्रमबद्ध किया जा रहा है, जो ओपी के बाद था।

इस दृष्टिकोण पर परीक्षण और प्रतिक्रिया बहुत स्वागत है!

+0

मेरे पास समय होने पर आपके कोड का अधिक सावधानी से परीक्षण होगा, लेकिन पहली नज़र में यह ठीक लगता है। मैं अभी आपके उत्तर को स्वीकार कर रहा हूं, क्योंकि यह अब तक का सबसे पूरा काम है। – mgibsonbr

2

आप तत्वों के आयाम और ऑफसेट प्राप्त कर सकते हैं, और उसके बाद document.elementFromPoint() का उपयोग यह निर्धारित करने के लिए करें कि कौन सा तत्व शीर्ष पर प्रस्तुत किया गया है।

+0

यह बहुत उपयोगी है! मैं एक ऐसी विधि की उम्मीद कर रहा था जिसके लिए किसी दिए गए बिंदु की आवश्यकता नहीं थी, लेकिन कई व्यावहारिक उद्देश्यों के लिए यह वास्तव में एक अच्छा समाधान प्रदान करता है। – mgibsonbr

3

नोट: के बाद एक एक जवाब के बिना वर्ष की तुलना में, इस सवाल का also posted at Stack Overflow in Portuguese था और - जबकि अभी भी एक निर्णायक समाधान के बिना - कुछ उपयोगकर्ताओं और मुझे replicate the stacking mechanism in JavaScript करने में सक्षम थे (पहिया पुनर्रचना, लेकिन अभी भी ...)

CSS2 specification (जोर मेरा) पर स्टैकिंग संदर्भ एल्गोरिथ्म का हवाला देते हुए:

मूल तत्व जड़ स्टैकिंग संदर्भ रूपों। अन्य स्टैकिंग संदर्भ किसी भी द्वारा तत्व (अपेक्षाकृत स्थानित तत्वों सहित) द्वारा 'ऑटो' के अलावा 'z-index' के गणना मूल्य के साथ उत्पन्न होते हैं। संदर्भों को ढेर करना जरूरी ब्लॉक से संबंधित नहीं है।सीएसएस के भविष्य के स्तरों में, अन्य संपत्तियों, अत्यधिक संदर्भों का परिचय हो सकता है उदाहरण 'अस्पष्टता'

कि वर्णन से के लिए , यहाँ वापस जाने के लिए एक समारोह है: क) एक तत्व की z-index, अगर यह एक नया स्टैकिंग उत्पन्न करता है contex; या ख) undefined अगर यह होता है>

function zIndex(ctx) { 
    if (!ctx || ctx === document.body) return; 

    var positioned = css(ctx, 'position') !== 'static'; 
    var hasComputedZIndex = css(ctx, 'z-index') !== 'auto'; 
    var notOpaque = +css(ctx, 'opacity') < 1; 

    if(positioned && hasComputedZIndex) // Ignoring CSS3 for now 
     return +css(ctx, 'z-index'); 
} 

function css(el, prop) { 
    return window.getComputedStyle(el).getPropertyValue(prop); 
} 

यह तत्व है कि विभिन्न अत्यधिक संदर्भों का फार्म अलग सेट करने के लिए सक्षम होना चाहिए नहीं। तत्वों के बाकी समय में (और एक समान z-index साथ तत्वों के लिए) Appendix E कहते हैं कि वे "पेड़ आदेश" का सम्मान करना चाहिए: के लिए तार्किक (नहीं दृश्य) क्रम में प्रतिपादन पेड़ की

Preorder गहराई-प्रथम ट्रेवर्सल, बिडरेक्शनल सामग्री, खाता गुणों को लेने के बाद जो आसपास के बक्से ले जाते हैं।

उन "गुण है कि चारों ओर बक्से ले जाएँ" के अलावा, इस समारोह को सही ढंग से लागू करता है ट्रेवर्सल shoud:

/* a and b are the two elements we want to compare. 
* ctxA and ctxB are the first noncommon ancestor they have (if any) 
*/ 
function relativePosition(ctxA, ctxB, a, b) { 
    // If one is descendant from the other, the parent is behind (preorder) 
    if ($.inArray(b, $(a).parents()) >= 0) 
     return a; 
    if ($.inArray(a, $(b).parents()) >= 0) 
     return b; 
    // If two contexts are siblings, the one declared first - and all its 
    // descendants (depth first) - is behind 
    return ($(ctxA).index() - $(ctxB).index() > 0 ? a : b); 
} 

इन दोनों कार्यों परिभाषित के साथ, हम अंत में हमारे तत्व तुलना समारोह बना सकते हैं:

function inFront(a, b) { 
    // Skip all common ancestors, since no matter its stacking context, 
    // it affects a and b likewise 
    var pa = $(a).parents(), ia = pa.length; 
    var pb = $(b).parents(), ib = pb.length; 
    while (ia >= 0 && ib >= 0 && pa[--ia] == pb[--ib]) { } 

    // Here we have the first noncommon ancestor of a and b 
    var ctxA = (ia >= 0 ? pa[ia] : a), za = zIndex(ctxA); 
    var ctxB = (ib >= 0 ? pb[ib] : b), zb = zIndex(ctxB); 

    // Finds the relative position between them  
    // (this value will only be used if neither has an explicit 
    // and different z-index) 
    var relative = relativePosition(ctxA, ctxB, a, b); 

    // Finds the first ancestor with defined z-index, if any 
    // The "shallowest" one is what matters, since it defined the most general 
    // stacking context (affects all the descendants) 
    while (ctxA && za === undefined) { 
     ctxA = ia < 0 ? null : --ia < 0 ? a : pa[ia]; 
     za = zIndex(ctxA); 
    } 
    while (ctxB && zb === undefined) { 
     ctxB = ib < 0 ? null : --ib < 0 ? b : pb[ib]; 
     zb = zIndex(ctxB); 
    } 

    // Compare the z-indices, if applicable; otherwise use the relative method 
    if (za !== undefined) { 
     if (zb !== undefined) 
      return za > zb ? a : za < zb ? b : relative; 
     return za > 0 ? a : za < 0 ? b : relative; 
    } 
    else if (zb !== undefined) 
     return zb < 0 ? a : zb > 0 ? b : relative; 
    else 
     return relative; 
} 

अभ्यास में इस विधि को दर्शाने वाले तीन उदाहरण यहां दिए गए हैं: Example 1, Example 2, Example 3 (क्षमा करें, सब कुछ अनुवाद करने से परेशान नहीं था नागाजी ... यह एक ही कोड है, बस अलग-अलग फ़ंक्शन और चर नाम)।

यह समाधान सबसे अधिक संभावना अधूरा है, और किनारे के मामलों में विफल होना चाहिए (हालांकि मुझे कोई भी नहीं मिला)। अगर किसी के पास सुधार के लिए कोई सुझाव है, तो इसकी सराहना की जाएगी।

संबंधित मुद्दे