# टेरारियम प्रोजेक्ट भाग ३: DOM म्यानिपुलेसन र क्लोजर ![DOM र क्लोजर](../../../../translated_images/webdev101-js.10280393044d7eaaec7e847574946add7ddae6be2b2194567d848b61d849334a.ne.png) > स्केच नोट [Tomomi Imura](https://twitter.com/girlie_mac) द्वारा ## प्रि-लेक्चर क्विज [प्रि-लेक्चर क्विज](https://ff-quizzes.netlify.app/web/quiz/19) ### परिचय DOM, अर्थात् "डकुमेन्ट अब्जेक्ट मोडेल" लाई म्यानिपुलेट गर्नु वेब विकासको मुख्य पक्ष हो। [MDN](https://developer.mozilla.org/docs/Web/API/Document_Object_Model/Introduction) अनुसार, "डकुमेन्ट अब्जेक्ट मोडेल (DOM) वेबमा डकुमेन्टको संरचना र सामग्री बनाउने वस्तुहरूको डाटा प्रतिनिधित्व हो।" वेबमा DOM म्यानिपुलेसनको चुनौतीहरूले प्रायः JavaScript फ्रेमवर्कहरू प्रयोग गर्न प्रेरित गरेको छ, तर हामी यसलाई भ्यानिला JavaScript प्रयोग गरेर आफैं व्यवस्थापन गर्नेछौं! यसका साथै, यो पाठले [JavaScript क्लोजर](https://developer.mozilla.org/docs/Web/JavaScript/Closures) को अवधारणा प्रस्तुत गर्नेछ, जसलाई तपाईं एउटा फङ्सनले अर्को फङ्सनलाई घेरेको रूपमा सोच्न सक्नुहुन्छ ताकि भित्री फङ्सनले बाहिरी फङ्सनको स्कोपमा पहुँच पाउन सक्छ। > JavaScript क्लोजरहरू एक विशाल र जटिल विषय हो। यो पाठले टेरारियमको कोडमा क्लोजरको आधारभूत विचारलाई मात्र छुन्छ: एउटा भित्री फङ्सन र बाहिरी फङ्सन यस्तो तरिकाले निर्माण गरिएको छ कि भित्री फङ्सनले बाहिरी फङ्सनको स्कोपमा पहुँच पाउन सक्छ। यसले कसरी काम गर्छ भन्ने थप जानकारीको लागि [व्यापक डकुमेन्टेशन](https://developer.mozilla.org/docs/Web/JavaScript/Closures) हेर्नुहोस्। हामी DOM म्यानिपुलेट गर्न क्लोजर प्रयोग गर्नेछौं। DOM लाई एउटा रुखको रूपमा सोच्नुहोस्, जसले वेब पेज डकुमेन्टलाई म्यानिपुलेट गर्न सक्ने सबै तरिकाहरूलाई प्रतिनिधित्व गर्दछ। विभिन्न API (Application Program Interfaces) लेखिएका छन् ताकि प्रोग्रामरहरूले आफ्नो रोजाइको प्रोग्रामिङ भाषा प्रयोग गरेर DOM पहुँच गर्न र सम्पादन, परिवर्तन, पुनःव्यवस्थित, र अन्यथा व्यवस्थापन गर्न सकून्। ![DOM रुखको प्रतिनिधित्व](../../../../translated_images/dom-tree.7daf0e763cbbba9273f9a66fe04c98276d7d23932309b195cb273a9cf1819b42.ne.png) > DOM र HTML मार्कअपको प्रतिनिधित्व जसले यसलाई सन्दर्भित गर्दछ। [Olfa Nasraoui](https://www.researchgate.net/publication/221417012_Profile-Based_Focused_Crawler_for_Social_Media-Sharing_Websites) बाट। यस पाठमा, हामी हाम्रो इन्टरएक्टिभ टेरारियम प्रोजेक्ट पूरा गर्नेछौं जसले प्रयोगकर्तालाई पेजमा रहेका बोटबिरुवाहरू म्यानिपुलेट गर्न अनुमति दिनेछ। ### पूर्वशर्त तपाईंले आफ्नो टेरारियमको लागि HTML र CSS बनाइसक्नुपर्छ। यस पाठको अन्त्यसम्ममा तपाईं बोटबिरुवाहरूलाई टेरारियममा राख्न र बाहिर निकाल्न ड्र्याग गरेर सक्षम हुनुहुनेछ। ### कार्य तपाईंको टेरारियम फोल्डरमा `script.js` नामको नयाँ फाइल बनाउनुहोस्। उक्त फाइललाई `` सेक्सनमा इम्पोर्ट गर्नुहोस्: ```html ``` > नोट: HTML फाइल पूर्ण रूपमा लोड भएपछि मात्र JavaScript कार्यान्वयन गर्न `defer` प्रयोग गर्नुहोस्। तपाईं `async` एट्रिब्युट पनि प्रयोग गर्न सक्नुहुन्छ, जसले स्क्रिप्टलाई HTML फाइल पार्स गर्दा कार्यान्वयन गर्न अनुमति दिन्छ, तर हाम्रो केसमा, HTML तत्वहरू पूर्ण रूपमा उपलब्ध हुनु महत्त्वपूर्ण छ ताकि ड्र्याग स्क्रिप्ट कार्यान्वयन गर्न सकियोस्। --- ## DOM तत्वहरू सबैभन्दा पहिले तपाईंले DOM मा म्यानिपुलेट गर्न चाहिने तत्वहरूको सन्दर्भ बनाउनु पर्छ। हाम्रो केसमा, ती १४ वटा बोटबिरुवाहरू हुन् जो हाल साइड बारमा छन्। ### कार्य ```html dragElement(document.getElementById('plant1')); dragElement(document.getElementById('plant2')); dragElement(document.getElementById('plant3')); dragElement(document.getElementById('plant4')); dragElement(document.getElementById('plant5')); dragElement(document.getElementById('plant6')); dragElement(document.getElementById('plant7')); dragElement(document.getElementById('plant8')); dragElement(document.getElementById('plant9')); dragElement(document.getElementById('plant10')); dragElement(document.getElementById('plant11')); dragElement(document.getElementById('plant12')); dragElement(document.getElementById('plant13')); dragElement(document.getElementById('plant14')); ``` यहाँ के भइरहेको छ? तपाईंले डकुमेन्टलाई सन्दर्भ गर्दै यसको DOM मा गएर विशेष Id भएको तत्व खोज्दै हुनुहुन्छ। HTML को पहिलो पाठमा तपाईंले प्रत्येक बोटबिरुवाको इमेजलाई व्यक्तिगत Id (`id="plant1"`) दिएको सम्झनुहोस्? अब तपाईंले उक्त प्रयासको उपयोग गर्नेछौं। प्रत्येक तत्वलाई पहिचान गरेपछि, तपाईंले उक्त आइटमलाई `dragElement` नामको फङ्सनमा पास गर्नुहुन्छ, जुन तपाईंले केही समयपछि निर्माण गर्नुहुनेछ। यसरी HTML मा रहेको तत्व अब ड्र्याग-इनेबल हुनेछ, वा चाँडै हुनेछ। ✅ किन हामी तत्वहरूलाई Id द्वारा सन्दर्भ गर्छौं? किन CSS क्लास द्वारा होइन? यस प्रश्नको उत्तर दिन CSS को अघिल्लो पाठलाई सन्दर्भ गर्नुहोस्। --- ## क्लोजर अब तपाईं `dragElement` क्लोजर बनाउन तयार हुनुहुन्छ, जुन एउटा बाहिरी फङ्सन हो जसले भित्री फङ्सन वा फङ्सनहरूलाई घेर्छ (हाम्रो केसमा, तीनवटा हुनेछ)। क्लोजरहरू उपयोगी हुन्छन् जब एक वा धेरै फङ्सनहरूले बाहिरी फङ्सनको स्कोपमा पहुँच गर्न आवश्यक हुन्छ। यहाँ एउटा उदाहरण छ: ```javascript function displayCandy(){ let candy = ['jellybeans']; function addCandy(candyType) { candy.push(candyType) } addCandy('gumdrops'); } displayCandy(); console.log(candy) ``` यस उदाहरणमा, `displayCandy` फङ्सनले एउटा फङ्सनलाई घेर्छ जसले पहिले नै फङ्सनमा रहेको एरेमा नयाँ क्यान्डी प्रकार थप्छ। यदि तपाईंले यो कोड चलाउनुभयो भने, `candy` एरे अनडिफाइन्ड हुनेछ, किनकि यो एउटा स्थानीय भेरिएबल हो (क्लोजरको स्थानीय स्कोपमा मात्र उपलब्ध)। ✅ तपाईंले `candy` एरेलाई कसरी पहुँचयोग्य बनाउन सक्नुहुन्छ? यसलाई क्लोजरको बाहिर सार्न प्रयास गर्नुहोस्। यसरी एरे ग्लोबल हुन्छ, स्थानीय स्कोपमा मात्र सीमित नरहेर। ### कार्य `script.js` मा तत्व घोषणाहरूको तल एउटा फङ्सन बनाउनुहोस्: ```javascript function dragElement(terrariumElement) { //set 4 positions for positioning on the screen let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; terrariumElement.onpointerdown = pointerDrag; } ``` `dragElement` ले आफ्नो `terrariumElement` वस्तु स्क्रिप्टको शीर्षमा रहेको घोषणाबाट प्राप्त गर्दछ। त्यसपछि, तपाईंले उक्त फङ्सनमा पास गरिएको वस्तुको लागि केही स्थानीय पोजिसनहरू `0` मा सेट गर्नुहुन्छ। यी स्थानीय भेरिएबलहरू प्रत्येक तत्वको लागि म्यानिपुलेसन गरिनेछ जब तपाईं प्रत्येक तत्वमा ड्र्याग र ड्रप कार्यक्षमता थप्नुहुन्छ। टेरारियम यी ड्र्याग गरिएको तत्वहरूले भरिनेछ, त्यसैले एप्लिकेसनले तिनीहरू कहाँ राखिएका छन् भनेर ट्र्याक गर्न आवश्यक छ। यसका साथै, `terrariumElement` जसलाई यो फङ्सनमा पास गरिएको छ, `pointerdown` इभेन्टमा असाइन गरिएको छ, जुन [वेब API](https://developer.mozilla.org/docs/Web/API) को भाग हो जसले DOM व्यवस्थापनमा मद्दत गर्दछ। `onpointerdown` तब फायर हुन्छ जब कुनै बटन थिचिन्छ, वा हाम्रो केसमा, कुनै ड्र्याग गर्न मिल्ने तत्वलाई टच गरिन्छ। यो इभेन्ट ह्यान्डलर [वेब र मोबाइल ब्राउजरहरू](https://caniuse.com/?search=onpointerdown) मा काम गर्दछ, केही अपवादहरू सहित। ✅ [इभेन्ट ह्यान्डलर `onclick`](https://developer.mozilla.org/docs/Web/API/GlobalEventHandlers/onclick) ले धेरै ब्राउजरहरूमा समर्थन गर्दछ; तपाईंले यसलाई यहाँ किन प्रयोग गर्नुहुन्न? तपाईंले यहाँ सिर्जना गर्न खोजेको स्क्रिन इन्टरएक्शनको प्रकारबारे सोच्नुहोस्। --- ## `pointerDrag` फङ्सन `terrariumElement` अब वरिपरि ड्र्याग गर्न तयार छ; जब `onpointerdown` इभेन्ट फायर हुन्छ, `pointerDrag` फङ्सनलाई बोलाइन्छ। उक्त लाइनको ठीक तल यो फङ्सन थप्नुहोस्: `terrariumElement.onpointerdown = pointerDrag;`: ### कार्य ```javascript function pointerDrag(e) { e.preventDefault(); console.log(e); pos3 = e.clientX; pos4 = e.clientY; } ``` धेरै कुरा हुन्छ। पहिलो, तपाईंले `e.preventDefault();` प्रयोग गरेर `pointerdown` मा सामान्यतया हुने डिफल्ट इभेन्टहरूलाई रोक्नुहुन्छ। यसरी तपाईंले इन्टरफेसको व्यवहारमा बढी नियन्त्रण पाउनुहुन्छ। > जब तपाईंले स्क्रिप्ट फाइल पूर्ण रूपमा बनाइसक्नुभयो, यो लाइन हटाएर प्रयास गर्नुहोस् - के हुन्छ? दोस्रो, `index.html` लाई ब्राउजर विन्डोमा खोल्नुहोस्, र इन्टरफेसलाई निरीक्षण गर्नुहोस्। जब तपाईं कुनै बोटबिरुवा क्लिक गर्नुहुन्छ, तपाईंले 'e' इभेन्ट कसरी क्याप्चर गरिएको छ देख्न सक्नुहुन्छ। इभेन्टमा कति धेरै जानकारी संकलन गरिएको छ हेर्नुहोस्! त्यसपछि, ध्यान दिनुहोस् कि स्थानीय भेरिएबलहरू `pos3` र `pos4` लाई `e.clientX` मा सेट गरिएको छ। तपाईंले निरीक्षण प्यानमा `e` मानहरू पाउन सक्नुहुन्छ। यी मानहरूले तपाईंले क्लिक वा टच गर्दा बोटबिरुवाको x र y कोर्डिनेटहरू क्याप्चर गर्छन्। तपाईंले बोटबिरुवाहरूलाई क्लिक र ड्र्याग गर्दा तिनीहरूको व्यवहारमा सूक्ष्म नियन्त्रण आवश्यक छ, त्यसैले तपाईंले तिनीहरूको कोर्डिनेटहरू ट्र्याक गर्नुहुन्छ। ✅ के यो स्पष्ट हुँदैछ कि किन यो सम्पूर्ण एप्लिकेसन एक ठूलो क्लोजरमा बनाइएको छ? यदि यो नभएको भए, तपाईंले १४ वटा ड्र्याग गर्न मिल्ने बोटबिरुवाहरूको स्कोप कसरी व्यवस्थापन गर्नुहुन्थ्यो? प्रारम्भिक फङ्सनलाई पूरा गर्न `pos4 = e.clientY` को तल दुईवटा थप `pointer` इभेन्ट म्यानिपुलेसनहरू थप्नुहोस्: ```html document.onpointermove = elementDrag; document.onpointerup = stopElementDrag; ``` अब तपाईंले बोटबिरुवालाई कर्सरसँगै ड्र्याग गर्न चाहनुभएको संकेत दिनुभएको छ, र बोटबिरुवा चयन नगर्दा ड्र्याग गर्ने इशारा रोक्न चाहनुभएको छ। `onpointermove` र `onpointerup` `onpointerdown` जस्तै API को भाग हुन्। इन्टरफेसले अब त्रुटिहरू फाल्नेछ किनकि तपाईंले `elementDrag` र `stopElementDrag` फङ्सनहरू अझै परिभाषित गर्नुभएको छैन, त्यसैले अब ती निर्माण गर्नुहोस्। ## `elementDrag` र `stopElementDrag` फङ्सनहरू तपाईंले दुईवटा थप आन्तरिक फङ्सनहरू थपेर आफ्नो क्लोजर पूरा गर्नुहुनेछ, जसले बोटबिरुवा ड्र्याग गर्दा र ड्र्याग रोक्दा के हुन्छ भन्ने व्यवस्थापन गर्नेछ। तपाईंले चाहनुभएको व्यवहार यो हो कि तपाईं कुनै पनि समयमा कुनै पनि बोटबिरुवा ड्र्याग गर्न सक्नुहुन्छ र स्क्रिनमा जहाँ पनि राख्न सक्नुहुन्छ। यो इन्टरफेस धेरै अन-अपिनियनड छ (उदाहरणका लागि ड्रप जोन छैन) ताकि तपाईं आफ्नो टेरारियमलाई पूर्ण रूपमा आफ्नो इच्छाअनुसार डिजाइन गर्न सक्नुहुन्छ। ### कार्य `elementDrag` फङ्सनलाई `pointerDrag` को बन्द कर्ली ब्र्याकेटको ठीक पछि थप्नुहोस्: ```javascript function elementDrag(e) { pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; console.log(pos1, pos2, pos3, pos4); terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px'; terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px'; } ``` यस फङ्सनमा, तपाईंले प्रारम्भिक पोजिसनहरू १-४ लाई धेरै सम्पादन गर्नुहुन्छ जुन तपाईंले बाहिरी फङ्सनमा स्थानीय भेरिएबलको रूपमा सेट गर्नुभएको थियो। यहाँ के भइरहेको छ? जब तपाईं ड्र्याग गर्नुहुन्छ, तपाईंले `pos1` लाई `pos3` (जुन तपाईंले पहिले `e.clientX` को रूपमा सेट गर्नुभएको थियो) बराबर बनाउनुहुन्छ र हालको `e.clientX` मान घटाउनुहुन्छ। तपाईंले `pos2` मा पनि यस्तै अपरेशन गर्नुहुन्छ। त्यसपछि, तपाईंले `pos3` र `pos4` लाई तत्वको नयाँ X र Y कोर्डिनेटहरूमा रिसेट गर्नुहुन्छ। तपाईंले यी परिवर्तनहरू कन्सोलमा ड्र्याग गर्दा हेर्न सक्नुहुन्छ। त्यसपछि, तपाईंले बोटबिरुवाको CSS शैलीलाई म्यानिपुलेट गरेर यसको नयाँ पोजिसन सेट गर्नुहुन्छ, `pos1` र `pos2` को नयाँ पोजिसनहरूको आधारमा यसको शीर्ष र बायाँ X र Y कोर्डिनेटहरू गणना गर्दै। > `offsetTop` र `offsetLeft` CSS प्रोपर्टीहरू हुन् जसले कुनै तत्वको पोजिसनलाई यसको अभिभावकको आधारमा सेट गर्छ; यसको अभिभावक कुनै पनि तत्व हुन सक्छ जुन `static` पोजिसनमा छैन। पोजिसनको पुनःगणना गर्दा टेरारियम र यसको बोटबिरुवाहरूको व्यवहारलाई सूक्ष्म रूपमा ट्युन गर्न अनुमति दिन्छ। ### कार्य इन्टरफेस पूरा गर्न अन्तिम कार्य भनेको `stopElementDrag` फङ्सनलाई `elementDrag` को बन्द कर्ली ब्र्याकेटको ठीक पछि थप्नु हो: ```javascript function stopElementDrag() { document.onpointerup = null; document.onpointermove = null; } ``` यो सानो फङ्सनले `onpointerup` र `onpointermove` इभेन्टहरू रिसेट गर्छ ताकि तपाईं आफ्नो बोटबिरुवाको प्रगति पुनः सुरु गर्न सक्नुहुन्छ वा नयाँ बोटबिरुवा ड्र्याग गर्न सुरु गर्न सक्नुहुन्छ। ✅ यदि तपाईंले यी इभेन्टहरूलाई null मा सेट गर्नुभएन भने के हुन्छ? अब तपाईंले आफ्नो प्रोजेक्ट पूरा गर्नुभएको छ! 🥇बधाई छ! तपाईंले आफ्नो सुन्दर टेरारियम पूरा गर्नुभएको छ। ![समाप्त टेरारियम](../../../../translated_images/terrarium-final.0920f16e87c13a84cd2b553a5af9a3ad1cffbd41fbf8ce715d9e9c43809a5e2c.ne.png) --- ## 🚀चुनौती क्लोजरमा नयाँ इभेन्ट ह्यान्डलर थपेर बोटबिरुवाहरूमा थप केही गर्नुहोस्; उदाहरणका लागि, बोटबिरुवालाई अगाडि ल्याउन डबल-क्लिक गर्नुहोस्। सिर्जनात्मक बन्नुहोस्! ## पोस्ट-लेक्चर क्विज [पोस्ट-लेक्चर क्विज](https://ff-quizzes.netlify.app/web/quiz/20) ## समीक्षा र आत्म-अध्ययन स्क्रिनमा तत्वहरू ड्र्याग गर्नु सामान्य लाग्न सक्छ, तर यसलाई गर्न धेरै तरिकाहरू छन् र तपाईंले खोजेको प्रभावको आधारमा धेरै चुनौतीहरू छन्। वास्तवमा, एउटा सम्पूर्ण [ड्र्याग र ड्रप API](https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API) छ जुन तपाईं प्रयास गर्न सक्नुहुन्छ। हामीले यसलाई यस मोड्युलमा प्रयोग गरेका छैनौं किनकि हामीले चाहेको प्रभाव केही फरक थियो, तर यो API आफ्नो प्रोजेक्टमा प्रयास गर्नुहोस् र तपाईंले के हासिल गर्न सक्नुहुन्छ हेर्नुहोस्। प्वाइन्टर इभेन्टहरूको बारेमा थप जानकारी [W3C डक्स](https://www.w3.org/TR/pointerevents1/) र [MDN वेब डक्स](https://developer.mozilla.org/docs/Web/API/Pointer_events) मा पाउनुहोस्। सधैं ब्राउजर क्षमताहरू [CanIUse.com](https://caniuse.com/) प्रयोग गरेर जाँच गर्नुहोस्। ## असाइनमेन्ट [DOM सँग अझै काम गर्नुहोस्](assignment.md) --- **अस्वीकरण**: यो दस्तावेज़ AI अनुवाद सेवा [Co-op Translator](https://github.com/Azure/co-op-translator) प्रयोग गरेर अनुवाद गरिएको हो। हामी यथासम्भव शुद्धता सुनिश्चित गर्न प्रयास गर्छौं, तर कृपया ध्यान दिनुहोस् कि स्वचालित अनुवादमा त्रुटिहरू वा अशुद्धताहरू हुन सक्छ। यसको मूल भाषा मा रहेको मूल दस्तावेज़लाई आधिकारिक स्रोत मानिनुपर्छ। महत्वपूर्ण जानकारीको लागि, व्यावसायिक मानव अनुवाद सिफारिस गरिन्छ। यस अनुवादको प्रयोगबाट उत्पन्न हुने कुनै पनि गलतफहमी वा गलत व्याख्याको लागि हामी जिम्मेवार हुने छैनौं।