फ़ाइल अपलोड फ़ील्ड जिसके हम हकदार हैं

सब कुछ बहता है, सब कुछ बदल जाता है, लेकिन केवल input[type=file] रूप में यह सभी नौसिखिया वेब डेवलपर्स की नसों को खराब कर देता है, और अब तक ऐसा करना जारी रखता है। अपने आप को एन साल पहले याद रखें, जब आप वेबसाइट बनाने की मूल बातें समझने लगे थे। युवा और अनुभवहीन, आप वास्तव में आश्चर्यचकित थे जब फ़ाइल चयन बटन ने पृष्ठभूमि रंग को आपके पसंदीदा आड़ू में बदलने से पूरी तरह से इनकार कर दिया। यह उस क्षण था जब आपने पहली बार "डाउनलोडिंग फाइल्स" नामक इस अविनाशी हिमखंड का सामना किया था, जो आज भी नौसिखिया वेब डेवलपर्स को "डूबने" के लिए जारी है।

फ़ाइल अपलोड फ़ील्ड बनाने के उदाहरण का उपयोग करते हुए, मैं आपको दिखाऊंगा कि input[type=file] को कैसे छिपाया जाए input[type=file] सही तरीके से, उस ऑब्जेक्ट पर ध्यान केंद्रित करें जिसमें फोकस नहीं हो सकता है, ड्रैग-एंड-ड्रॉप ईवेंट्स को हैंडल करें और AJAX के माध्यम से फाइल भेजें। और इसके अलावा, मैं आपको कुछ ब्राउज़र बग और उनके आसपास काम करने के तरीके से परिचित कराऊंगा। लेख शुरुआती लोगों के लिए लिखा गया है, लेकिन कुछ बिंदुओं पर यह उपयोगी और मनोरंजक हो सकता है, यहां तक ​​कि अनुभवी डेवलपर्स के लिए भी।

मार्कअप और प्राथमिक शैली


एचटीएमएल मार्कअप के साथ शुरू करते हैं:

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>  ,   </title> <link rel="stylesheet" href="style.css"> <script type="text/javascript" src="jquery-3.3.1.min.js"></script> <script type="text/javascript" src="script.js"></script> </head> <body> <form id="upload-container" method="POST" action="send.php"> <img id="upload-image" src="upload.svg"> <div> <input id="file-input" type="file" name="file" multiple> <label for="file-input"> </label> <span>   </span> </div> </form> </body> </html> 

शायद मुख्य तत्व जिसे आपको ध्यान देना चाहिए

 <label for="file-input"> </label> 

HTML विनिर्देशन हमें सीधे input[type=file] पर दृश्य गुणों को लगाने की अनुमति नहीं देता है, लेकिन हमारे पास एक label टैग है, जिस पर क्लिक करने से फॉर्म तत्व पर एक क्लिक होता है जिससे यह जुड़ा हुआ है। हमारे आनंद के लिए, इस टैग की शैलीीकरण में कोई सीमा नहीं है: हम इसके साथ जो चाहें कर सकते हैं।

एक कार्य योजना उभरती है: हम लेबल को स्टाइल करते हैं, जैसा कि हम कृपया करते हैं, और input[type=file] को दृष्टि से छिपाते हैं। सबसे पहले, सामान्य पृष्ठ शैलियाँ सेट करें:

 body { padding: 0; margin: 0; display: flex; justify-content: center; align-items: center; min-height: 100vh; } #upload-container { display: flex; justify-content: center; align-items: center; flex-direction: column; width: 400px; height: 400px; outline: 2px dashed #5d5d5d; outline-offset: -12px; background-color: #e0f2f7; font-family: 'Segoe UI'; color: #1f3c44; } #upload-container img { width: 40%; margin-bottom: 20px; user-select: none; } 

अब हमारे लेबल को स्टाइल करें:

 #upload-container label { font-weight: bold; } #upload-container label:hover { cursor: pointer; text-decoration: underline; } 

हम जो प्रयास कर रहे हैं ( input[type=file] मार्कअप से हटा दिया गया है):

बेशक, आप लेबल को केंद्र में रख सकते हैं, एक पृष्ठभूमि और सीमा जोड़ सकते हैं, एक पूर्ण बटन प्राप्त कर सकते हैं, लेकिन हमारी प्राथमिकता ड्रैग-एंड-ड्रॉप है।

इनपुट छिपा रहे हैं


अब हमें input[type=file] को छिपाने की आवश्यकता है। पहली चीज जो सिर पर वार करती है वह है display: none और visibility: hidden संपत्ति। लेकिन यह इतना आसान नहीं है। कुछ पुराने ब्राउज़रों पर, लेबल पर क्लिक करने से अब कोई प्रभाव नहीं पड़ेगा। लेकिन यह सब नहीं है। जैसा कि आप जानते हैं, अदृश्य तत्व फोकस प्राप्त नहीं कर सकते हैं, और कोई फर्क नहीं पड़ता कि वे क्या कहते हैं, फोकस महत्वपूर्ण है, क्योंकि कुछ लोगों के लिए यह साइट के साथ बातचीत करने का एकमात्र तरीका है। तो यह तरीका हमें शोभा नहीं देता। आइए इस पर चलते हैं:

 #upload-container div { position: relative; z-index: 10; } #upload-container input[type=file] { width: 0.1px; height: 0.1px; opacity: 0; position: absolute; z-index: -10; } 

हम पूरी तरह से हमारे input[type=file] को इसके मूल ब्लॉक के सापेक्ष रखते हैं, इसे 0.1px तक कम करते हैं, इसे पारदर्शी बनाते हैं और इसके z-index को माता-पिता की तुलना में कम सेट करते हैं, इसलिए, ऐसा बोलने के लिए, सुनिश्चित करें।

बधाई, हमने वह हासिल किया जो हम चाहते थे: हमारा क्षेत्र पिछली तस्वीर जैसा दिखता है।

फोकस समायोजित करें


चूंकि हमारा input[type=file] भौतिक रूप से पृष्ठ पर मौजूद है, इसमें फोकस प्राप्त करने की क्षमता है। यही है, अगर हम पृष्ठ पर Tab कुंजी दबाते हैं, तो कुछ बिंदु पर ध्यान input[type=file] । लेकिन समस्या यह है कि हम इसे नहीं देखेंगे: जिस क्षेत्र को हमने छिपाया है वह बाहर खड़ा होगा। हां, यदि इस समय हम Enter दबाते हैं, तो डायलॉग बॉक्स खुलेगा और सब कुछ उसी तरह काम करेगा जैसा कि हमें करना चाहिए, लेकिन हम कैसे समझते हैं कि इसे दबाने का समय है?

हमारा काम उस समय एक निश्चित तरीके से एक निशान का चयन करना है जब फ़ाइल अपलोड फ़ील्ड पर ध्यान केंद्रित किया गया है। लेकिन अगर टैग फोकस नहीं कर सकते तो हम यह कैसे कर सकते हैं? CSS3 के पारखी तुरंत छद्म वर्ग के बारे में सोचेंगे :focus , जो फ़ोकस में तत्वों के लिए शैलियों को परिभाषित करता है, और + या ~ चयनकर्ता जो सही पड़ोसियों का चयन करते हैं: एक ही नेस्टिंग स्तर पर स्थित तत्व, चयनित तत्व के बाद आने वाले। यह देखते हुए कि हमारे मार्कअप input[type=file] सीधे label टैग के सामने स्थित है, निम्नलिखित प्रविष्टि होती है:

 #upload-container input[type=file]:focus + label { /*  */ } 

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

WebKet इंजन (Google Chrome, Opera, Safari) पर आधारित ब्राउज़रों में, फ़ोकस में तत्वों के लिए डिफ़ॉल्ट संपत्ति का रूप है:

 :focus { outline: -webkit-focus-ring-color auto 5px; } 

यहाँ -webkit-focus-ring-color केवल इस इंजन के लिए फ़ोकस-स्ट्रोक -webkit-focus-ring-color । यही है, यह लाइन विशेष रूप से WebKit ब्राउज़रों में काम करेगी, और ठीक यही हमें चाहिए। इस गुण को हमारे लेबल के लिए निर्दिष्ट करें:

 #upload-container input[type=file]:focus + label { outline: -webkit-focus-ring-color auto 5px; } 

हम Google Chrome या Opera खोलते हैं, हम देखते हैं। सब कुछ के रूप में यह काम करना चाहिए:

आइए देखें कि मोज़िला फ़ायरफ़ॉक्स और माइक्रोसॉफ्ट एज में चीजें कैसे फोकस हैं। इन ब्राउज़रों के लिए, डिफ़ॉल्ट गुण है:

 :focus { outline: 1px solid #0078d7; } 

और

 :focus { outline: 1px solid #212121; } 

क्रमशः।

दुर्भाग्य से, -moz- उपसर्ग outline संपत्ति के साथ काम नहीं करेगा। इसलिए, हमें यह चुनना होगा कि इन दोनों गुणों में से कौन सा हम चुनते हैं। चूंकि फ़ायरफ़ॉक्स उपयोगकर्ताओं की संख्या बहुत अधिक है, इसलिए इस विशेष ब्राउज़र को वरीयता देना अधिक तर्कसंगत है। इसका मतलब यह नहीं है कि हम एज के उपयोगकर्ताओं और अवसर के अन्य ब्राउज़रों को यह देखने से वंचित करते हैं कि फोकस अब कहां है, यह सिर्फ उनसे अलग दिखाई देगा। खैर, आपको बलिदान देना होगा।

हम WebKit के लिए शैली से पहले मोज़िला फ़ायरफ़ॉक्स से शैली जोड़ते हैं: पहले सभी ब्राउज़र पहली संपत्ति को लागू करेंगे, और फिर वे (Google क्रोम, ओपेरा, सफारी, आदि) दूसरा लागू करेंगे।

 #upload-container input[type=file]:focus + label { outline: 1px solid #0078d7; outline: -webkit-focus-ring-color auto 5px; } 

और यहाँ अजीब शुरू होता है: एज में सब कुछ ठीक काम करता है, लेकिन किसी अज्ञात कारण के लिए फ़ायरफ़ॉक्स input[type=file] पर ध्यान देने के साथ गुणों को लागू करने से मना कर देता है input[type=file] । और focus ईवेंट स्वयं होता है - जावास्क्रिप्ट के माध्यम से जाँच की जाती है। इसके अलावा, यदि आप डेवलपर टूल के माध्यम से फ़ाइल चयन क्षेत्र पर ध्यान केंद्रित करते हैं, तो संपत्ति लागू होगी और हमारा स्ट्रोक दिखाई देगा! जाहिरा तौर पर, यह ब्राउज़र का एक बग है, लेकिन अगर किसी के पास विचार हैं कि ऐसा क्यों होता है - टिप्पणियों में लिखें।

खैर, कुछ भी नहीं, सामान्य नायक हमेशा घूमते रहते हैं। जैसा कि मैंने पहले कहा था, focus इवेंट होता है, जिसका अर्थ है कि हम गुणों को सीधे जावास्क्रिप्ट से समायोजित कर सकते हैं। लेकिन इसके लिए हमें अपने चयनकर्ता के तर्क को बदलना होगा:

 #upload-container label.focus { outline: 1px solid #0078d7; outline: -webkit-focus-ring-color auto 5px; } 

हम अपने लेबल के लिए .focus वर्ग का वर्णन करेंगे और हम इसे हर बार जोड़ेंगे जब input[type=file] फोकस प्राप्त करता है और खो जाने पर इसे हटा देता है।

 $('#file-input').focus(function() { $('label').addClass('focus'); }) .focusout(function() { $('label').removeClass('focus'); }); 

अब सब कुछ वैसा ही काम करता है जैसा उसे करना चाहिए। बधाई हो, हमने ध्यान केंद्रित किया।

खींचें और ड्रॉप


ड्रैग-एंड-ड्रॉप के साथ काम विशेष ब्राउज़र घटनाओं को ट्रैक करके किया जाता है: drag, dragstart, dragend, dragover, dragenter, dragleave, drop । आप इंटरनेट पर उनमें से प्रत्येक का विस्तृत विवरण आसानी से पा सकते हैं। हम उनमें से कुछ को ही ट्रैक करेंगे।

सबसे पहले, एक ड्रैग-एंड-ड्रॉप तत्व को परिभाषित करें:
 var dropZone = $('#upload-container'); 

फिर हम सीएसएस में एक विशेष वर्ग का वर्णन करते हैं कि हम dropZone को असाइन dropZone जब फ़ाइल खींचने वाला कर्सर सीधे इसके ऊपर होता है। यह उपयोगकर्ता को नेत्रहीन रूप से सूचित करने के लिए आवश्यक है कि फ़ाइल पहले से ही जारी की जा सकती है।

 #upload-container.dragover { background-color: #fafafa; outline-offset: -17px; } 

अब हम JS फाइल पर जाते हैं। आरंभ करने के लिए, हमें ड्रैग-एंड-ड्रॉप ईवेंट के लिए सभी डिफ़ॉल्ट क्रियाओं को पूर्ववत करना होगा। उदाहरण के लिए, ऐसी घटनाओं में से एक ब्राउज़र द्वारा फेंकी गई फ़ाइल का उद्घाटन है। हमें इसकी बिल्कुल भी आवश्यकता नहीं है, इसलिए हम निम्नलिखित पंक्तियों को लिखेंगे:

 dropZone.on('drag dragstart dragend dragover dragenter dragleave drop', function(){ return false; }); 

JQuery में, return false कॉल करना एक ही बार में दो फ़ंक्शन को कॉल करने के बराबर है: e.preventDefault() और e.preventDefault() e.stopPropagation()

हम अपने स्वयं के ईवेंट हैंडलर का वर्णन करना शुरू करते हैं। हम उसी तरह से काम करेंगे जैसे हमने फोकस के साथ किया था, लेकिन इस बार हम dragenter और dragenter की घटनाओं को ट्रैक करने के लिए एक क्लास और dragleave इवेंट को जोड़ने के लिए ट्रैक करेंगे:

 dropZone.on('dragover dragenter', function() { dropZone.addClass('dragover'); }); dropZone.on('dragleave', function(e) { dropZone.removeClass('dragover'); }); 

और फिर से, एक अप्रिय आश्चर्य हमें इंतजार कर रहा है: जब आप फ़ाइल के साथ माउस के साथ dropZone साथ आगे dropZone , तो क्षेत्र झिलमिलाहट शुरू होता है। यह Microsoft Edge और WebKit ब्राउज़र में होता है। वैसे, इन वेबकिट ब्राउज़रों में से अधिकांश वर्तमान में ब्लिंक इंजन (सराहना, हुह) की सराहना कर रहे हैं। लेकिन मोज़िला में, कुछ भी नहीं झाड़ता। जाहिर है, मैंने फ़ोकस बग के बाद इसे ठीक करने का फैसला किया।

और यह झिलमिलाहट इस तथ्य के कारण होता है कि जब आप dropZone पर मंडराते हैं, तो यह एक चित्र या फ़ाइल चयन फ़ील्ड और एक लेबल के साथ div हो, किसी कारण से dragleave घटना dragleave । यह हमारे लिए स्पष्ट है कि हम क्षेत्र को नहीं छोड़ रहे हैं, लेकिन ब्राउज़र किसी कारण से, नहीं करते हैं, और इस वजह से वे .focus से dropZone से dropZone वर्ग को dropZone

और फिर, हमें किसी तरह बाहर निकलना होगा। यदि ब्राउज़र खुद नहीं समझ पाता है कि हम मैदान नहीं छोड़ रहे हैं, तो हमें उसकी मदद करनी होगी। और हम इसे अतिरिक्त स्थितियों के माध्यम से करेंगे: हम dropZone सापेक्ष माउस के निर्देशांक की गणना करते हैं, और फिर जांचें कि कर्सर ब्लॉक के बाहर है या नहीं। यदि छोड़ दिया जाता है, तो हम शैली को हटा देते हैं:

 dropZone.on('dragleave', function(e) { let dx = e.pageX - dropZone.offset().left; let dy = e.pageY - dropZone.offset().top; if ((dx < 0) || (dx > dropZone.width()) || (dy < 0) || (dy > dropZone.height())) { dropZone.removeClass('dragover'); }; }); 

और सब कुछ, समस्या हल हो गई है! ऐसा लगता है कि फ़ाइल के साथ हमारा क्षेत्र कैसा दिखता है:


चलिए drop इवेंट को खुद ही हैंडल करते हैं। लेकिन सबसे पहले, याद रखें कि, ड्रैग-एंड-ड्रॉप के अलावा, हमारे पास input[type=file] , और इनमें से प्रत्येक विधि अपने सार में स्वतंत्र है, लेकिन एक ही क्रिया करना चाहिए: फ़ाइलों को अपलोड करें। इसलिए, मैं दोनों तरीकों के लिए एक अलग फ़ंक्शन सार्वभौमिक बनाने का प्रस्ताव करता हूं, जिसमें हम फाइलें स्थानांतरित करेंगे, और यह पहले से ही तय करेगा कि उनके साथ क्या करना है। हम इसे sendFiles() , लेकिन हम इसे थोड़ा बाद में sendFiles() । आरंभ करने के लिए, drop ईवेंट को संभालें:

 dropZone.on('drop', function(e) { dropZone.removeClass('dragover'); let files = e.originalEvent.dataTransfer.files; sendFiles(files); }); 

सबसे पहले, .dragover से dropZone वर्ग को हटा दें। फिर हमें फाइल रखने वाली एक सरणी मिलती है। यदि आप jQuery का उपयोग करते हैं, तो पथ e.originalEvent.dataTransfer.files होगा, यदि आप शुद्ध JS में लिखते हैं, तो e.dataTransfer.files । ठीक है, फिर हम सरणी को अभी तक अनारक्षित फ़ंक्शन के रूप में पास करते हैं।

अब हम लोडिंग विधि को input[type=file] माध्यम से करेंगे:

 $('#file-input').change(function() { let files = this.files; sendFiles(files); }); 

हम फ़ाइल चयन बटन पर change घटना को ट्रैक करते change , हम इस के माध्यम से सरणी प्राप्त करते हैं। इसे फंक्शन में भेजते हैं।

AJAX के माध्यम से फाइल भेजना


अंतिम चरण - फ़ाइल प्रोसेसिंग फ़ंक्शन का विवरण - सभी के लिए अद्वितीय है। यह सीधे उस लक्ष्य पर निर्भर करेगा जो आप अपनाते हैं। एक उदाहरण के लिए मैं दिखाऊंगा कि AJAX के माध्यम से सर्वर पर फाइलें कैसे भेजें।

मान लीजिए कि हम फ़ोटो अपलोड करने के लिए एक फ़ील्ड बनाते हैं। हम अपने सर्वर से कुछ और नहीं चाहते हैं, इसलिए हम फ़ाइल प्रकारों पर निर्णय लेंगे: इसे PNG और JPEG होने दें। यह एक फोटो के अधिकतम आकार को विनियमित करने के लायक भी है जो एक उपयोगकर्ता भेज सकता है। पाँच मेगाबाइट तक सीमित। हम अपने कार्य का वर्णन करना शुरू करते हैं:

 function sendFiles(files) { let maxFileSize = 5242880; let Data = new FormData(); $(files).each(function(index, file) { if ((file.size <= maxFileSize) && ((file.type == 'image/png') || (file.type == 'image/jpeg'))) { Data.append('images[]', file); } }); }; 

चर maxFileSize अधिकतम फ़ाइल आकार maxFileSize जो हम सर्वर को भेजेंगे। FormData() फ़ंक्शन FormData() , हम FormData वर्ग की एक नई वस्तु FormData , जो हमें कुंजी-मूल्य वाले जोड़े के सेट उत्पन्न करने की अनुमति देता है। इस तरह की वस्तु को AJAX के माध्यम से आसानी से भेजा जा सकता है। अगला, हम files ऐरे के लिए jQuery .each कंस्ट्रक्शन का उपयोग करते हैं, जो हमारे प्रत्येक तत्व के लिए निर्धारित फंक्शन को लागू करेगा। तत्व की संख्या और तत्व स्वयं फ़ंक्शन के तर्क के रूप में पारित किए जाएंगे, जिसे हम क्रमशः index और file रूप में संसाधित करेंगे। फ़ंक्शन में ही, हम अपने मानदंडों के खिलाफ फ़ाइल की जांच करेंगे: आकार पांच मेगाबाइट से कम है, और प्रकार पीएनजी या जेपीईजी है। यदि फ़ाइल परीक्षण पास करती है, तो इसे append() फ़ंक्शन को कॉल करके हमारी FormData ऑब्जेक्ट में append() । कुंजी स्ट्रिंग 'photos[]' , जिसके अंत में वर्ग कोष्ठक इंगित करते हैं कि यह एक सरणी है जिसमें कई ऑब्जेक्ट हो सकते हैं। ऑब्जेक्ट स्वयं file होगी।

अब AJAX के माध्यम से फाइल भेजने के लिए सब कुछ तैयार है। हमारे समारोह में निम्नलिखित पंक्तियाँ जोड़ें:

 $.ajax({ url: dropZone.attr('action'), type: dropZone.attr('method'), data: Data, contentType: false, processData: false, success: function(data) { alert('   '); } }); 

पैरामीटर url और type हम क्रमशः input[type=file] की action और method विशेषताओं के मूल्यों को इंगित करते हैं। AJAX से गुजरने के लिए हम एक Data ऑब्जेक्ट होंगे। पैरामीटर contentType: false और processData: false की आवश्यकता होती है ताकि ब्राउज़र अनजाने में हमारी फ़ाइलों को किसी अन्य प्रारूप में अनुवाद न करे। success पैरामीटर में, हम उस फ़ंक्शन को निर्दिष्ट करते हैं जिसे निष्पादित किया जाएगा यदि फाइलें सफलतापूर्वक सर्वर में स्थानांतरित हो जाती हैं। इसकी सामग्री आपकी कल्पना पर निर्भर करती है, लेकिन मैं खुद को एक सफल डाउनलोड के बारे में संदेश के एक मामूली आउटपुट तक सीमित कर दूंगा।

बधाई हो, अब आप अपनी फ़ाइल अपलोड फ़ील्ड बना सकते हैं! बेशक, मैं अपनी पद्धति को एकमात्र सही और सही के रूप में नहीं रखता हूं। मेरा लक्ष्य मुख्य रूप से शुरुआती लोगों के लिए उपयुक्त, इस समस्या को हल करने के सामान्य पाठ्यक्रम को दिखाना था। अगर आपको लगता है कि कहीं आप कुछ बेहतर कर सकते हैं - टिप्पणियों में लिखें, हम चर्चा करेंगे!

वह सब है। आपका ध्यान के लिए धन्यवाद!

डाउनलोड:

  1. अंतिम संस्करण
  2. फोकस समस्या
  3. टिमटिमाती हुई समस्या

लग रहा है:

  1. अंतिम संस्करण
  2. फोकस समस्या
  3. टिमटिमाती हुई समस्या

Source: https://habr.com/ru/post/hi423035/


All Articles