एक्सप्रेस, जेड और History.js का उपयोग करके रिबूट किए बिना नेविगेशन

मैंने अपने काम में पहले कभी इस तरह के एचटीएमएल 5 फीचर को हिस्ट्री एपीआई के रूप में इस्तेमाल नहीं किया है। और फिर वह समय आ गया है, इसका पता लगाने और एक छोटा सा प्रयोग करने का। मैंने इस प्रयोग का परिणाम आपके साथ साझा करने का निर्णय लिया।

और इसलिए हम क्या चाहते हैं:
- इतिहास एपीआई का उपयोग करके साइट नेविगेशन
- सर्वर से डेटा को एक json ऑब्जेक्ट के रूप में प्राप्त करें, इसके बाद क्लाइंट पर रेंडर करें
- सीधे संक्रमण के साथ, सर्वर पर रेंडरिंग होना चाहिए
- यह सब कुछ आसान और सरल होगा

हमने कई जरूरतों पर निर्णय लिया है, अब हम प्रौद्योगिकियों पर निर्णय लेंगे:
- एक्सप्रेसजेज नोडज के तहत सर्वर पर काम करेगा
- जेड टेम्पलेट इंजन के रूप में
- क्लाइंट के लिए History.js

सर्वर

उन लोगों के लिए जिन्होंने कभी नोड्ज के साथ काम नहीं किया है, आपको पहले इसे स्थापित करना चाहिए। आप देख सकते हैं कि इसे उबंटू के तहत कैसे करें । प्रोजेक्ट के लिए एक फ़ोल्डर बनाएं और उस पर जाएं। अगला, आवश्यक मॉड्यूल स्थापित करें:
npm i एक्सप्रेस जेड

और दो निर्देशिकाएँ बनाएँ:
- देखें - टेम्प्लेट यहां झूठ होंगे
- सार्वजनिक - स्थिर सामग्री होगी

अगला, हम एक सर्वर लिखेंगे और केवल मुख्य बिंदुओं पर ध्यान केंद्रित करेंगे।
पहली बात जो मैं अपने जीवन को आसान बनाना चाहता था, वह यह सोचना नहीं था कि अजाक्स का अनुरोध हमारे लिए कैसे आया या नहीं। ऐसा करने के लिए, हम मानक res.render को इंटरसेप्ट करेंगे
कोड
app.all('*', function replaceRender(req, res, next) { var render = res.render, view = req.path.length > 1 ? req.path.substr(1).split('/'): []; res.render = function(v, o) { var data; res.render = render; //         //  if ('string' === typeof v) { if (/^\/.+/.test(v)) { view = v.substr(1).split('/'); } else { view = view.concat(v.split('/')); } data = o; } else { data = v; } // res.locals      //    s (res.locals.title) data = merge(data || {}, res.locals); if (req.xhr) { //     json res.json({ data: data, view: view.join('.') }); } else { //   ,    // (   history api) data.state = JSON.stringify({ data: data, view: view.join('.') }); //    .       . view[view.length - 1] = '_' + view[view.length - 1]; //   res.render(view.join('/'), data); } }; next(); }); 



res.render अतिभारित है, अब हम अपने नियंत्रकों में res.render (डेटा) या res.render ('दृश्य नाम', डेटा) को सुरक्षित रूप से कॉल कर सकते हैं, और सर्वर स्वयं अनुरोध को टाइप के आधार पर या तो क्लाइंट को रेंडर करेगा या वापस लौटाएगा।

आइए फिर से कोड को देखें, और मैं यह समझाने की कोशिश करूंगा कि "सर्वर पर रेंडरिंग" के मामले में टेम्प्लेट में '_' की आवश्यकता क्यों है।
समस्या इस प्रकार है। जेड में कोई लेआउट नहीं हैं, उनके बजाय ब्लॉक का उपयोग किया जाता है, ब्लॉक एक-दूसरे का विस्तार, प्रतिस्थापन या पूरक कर सकते हैं (यह सब प्रलेखन में अच्छी तरह से वर्णित है)।

एक उदाहरण पर विचार करें।
मान लीजिए कि हमारे पास यह मानचित्रण संरचना है:
विकल्प a
layout.jade
 !!! 5 html head title Page title body #content block content 


index.jade
 extends layout block content hello world 


यदि हम अब index.jade को रेंडर करते हैं, तो यह layout.jade के साथ मिलकर रेंडर करेगा। जब तक हम index.jade को क्लाइंट को निर्यात करना चाहते हैं और इसे वहां रेंडर करना चाहते हैं, तब तक समस्या नहीं होती है, लेकिन बिना लेआउट के ।jade। इसलिए, मैंने एक और टेम्पलेट जोड़ने का फैसला किया जो इसे आसानी से और सरलता से करने की अनुमति देगा।

विकल्प बी
layout.jade
 !!! 5 html head title Page title body #content block content 


_index.jade
 extends layout block content include index 


index.jade
 hello world 


अब यदि हम लेआउट के साथ ब्लॉक को रेंडर करना चाहते हैं, तो हम _index.jade फ़ाइल को रेंडर करेंगे, अगर हमें लेआउट की आवश्यकता नहीं है, तो index.jade को प्रस्तुत किया जाएगा। यह तरीका मुझे सबसे सरल और समझ में आता था। यदि आप नियम का पालन करते हैं कि केवल उपसर्ग "_" के साथ टेम्पलेट लेआउट का विस्तार करते हैं। जेड तो आप सुरक्षित रूप से क्लाइंट को बाकी सब कुछ निर्यात कर सकते हैं। (ऐसा करने के निस्संदेह अन्य तरीके हैं, आप टिप्पणियों में उनके बारे में बता सकते हैं, यह जानना दिलचस्प होगा)

अगला बिंदु जिस पर मैं ध्यान केंद्रित करूंगा वह है क्लाइंट को टेम्प्लेट्स का निर्यात। ऐसा करने के लिए, हम एक फ़ंक्शन लिखते हैं जो इनपुट के रूप में व्यूअर के सापेक्ष टेम्पलेट को पथ प्राप्त करेगा, और आउटपुट के लिए संकलित फ़ंक्शन कास्ट को आउटपुट पर वापस कर देगा।
कोड
 function loadTemplate(viewpath) { var fpath = app.get('views') + viewpath, str = fs.readFileSync(fpath, 'utf8'); viewOptions.filename = fpath; viewOptions.client = true; return jade.compile(str, viewOptions).toString(); } 


अब हम एक नियंत्रक लिखते हैं जो टेम्पलेट के साथ एक जावास्क्रिप्ट फ़ाइल एकत्र करेगा।
कोड
(कृपया इस तथ्य पर ध्यान न दें कि आपके हाथों से सब कुछ, यह सिर्फ एक प्रयोग है, निश्चित रूप से, वास्तविक परियोजना में यह करने योग्य नहीं है)
 app.get('/templates', function(req, res) { var str = 'var views = { ' + '"index": (function(){ return ' + loadTemplate('/index.jade') + ' }()),' + '"users.index": (function(){ return ' + loadTemplate('/users/index.jade') + ' }()),' + '"users.profile": (function(){ return ' + loadTemplate('/users/profile.jade') + ' }()),' + '"errors.error": (function(){ return ' + loadTemplate('/errors/error.jade') + ' }()),' + '"errors.notfound": (function(){ return ' + loadTemplate('/errors/notfound.jade') + ' }())' + '};' res.set({ 'Content-type': 'text/javascript' }).send(str); }); 


अब जब ग्राहक अनुरोध / टेम्पलेट के जवाब में, वह निम्नलिखित वस्तु प्राप्त करेगा:
 var view = { ' ': <> }; 

और वांछित टेम्पलेट को रेंडर करने के लिए क्लाइंट पर, यह देखने के लिए पर्याप्त होगा ['टेम्पलेट नाम'] (डेटा);

सर्वर पक्ष पर विचार समाप्त करें, क्योंकि बाकी सब कुछ विशेष रूप से प्रासंगिक नहीं है और सीधे हमारे कार्य से संबंधित नहीं है। इसके अलावा, कोड यहां पाया जा सकता है

ग्राहक

चूंकि हम क्लाइंट को पहले से संकलित टेम्प्लेट निर्यात करते हैं, इसलिए हमें स्वयं टेम्प्लेट इंजन को कनेक्ट करने की आवश्यकता नहीं है, बस इसे रनटाइम से कनेक्ट करें और हमारे टेम्पलेट को एक नियमित जावास्क्रिप्ट फ़ाइल के रूप में कनेक्ट करके लोड करना न भूलें।

सूची से अगला पुस्तकालय History.js है , जिसका नाम स्वयं के लिए बोलता है। मैंने केवल HTML5 ब्राउज़रों के लिए संस्करण चुना, ये सभी आधुनिक ब्राउज़र हैं, हालाँकि लाइब्रेरी पुराने ब्राउज़र में हैश यूआरएल के माध्यम से काम कर सकती है।

बहुत कम क्लाइंट कोड बचा है।
सबसे पहले, हम रेंडर () फ़ंक्शन लिखते हैं। यह काफी सरल है और कंटेंट ब्लॉक में दिए गए टेम्प्लेट को प्रस्तुत करता है।
 var render = (function () { return function (view, data) { $('#content').html(views[view](data)); } }()); 


अब History.js के साथ काम को शुरू करने वाला कोड
कोड
 $(function () { var initState; if (History.enabled) { $('a').live('click', function () { var el = $(this), href = el.attr('href'); $.get(href, function(result) { History.pushState(result, result.data.title, href); }, 'json'); return false; }); History.Adapter.bind(window,'statechange', function() { var state = History.getState(), obj = state.data; render(obj.view, obj.data); }); //init initState = $('body').data('init'); History.replaceState(initState, initState.data.title, location.pathname + location.search); } }); 


कोड काफी सरल है। पहली चीज़ जो हम करते हैं वह यह देखने के लिए कि क्या ब्राउज़र इतिहास एपीआई का समर्थन करता है। यदि नहीं, तो कुछ भी न बदलें और ग्राहक पुराने ढंग से काम करे।
और अगर यह समर्थन करता है, तो हम सभी क्लिकों को एक सर्वर पर एक अजाक्स अनुरोध भेजते हैं।

"स्टेटचेंज" इवेंट हैंडलर को लटका देना न भूलें, इस समय हमें अपने कंटेंट ब्लॉक को फिर से शुरू करने और प्रारंभिक स्थिति के प्रारंभ को जोड़ने की आवश्यकता है, मैंने इसे बॉडी टैग, डेटा-इनिट विशेषता में संग्रहीत करने का निर्णय लिया, यहां सर्वर पर रेंडर करते समय प्रारंभिक मान लिखे गए हैं।
लाइन data.state = JSON.stringify ({डेटा: डेटा, दृश्य: view.join ('' ')}); बदली समारोह में

बस इतना ही।

एक काम का उदाहरण यहाँ है (यदि वह मर जाता है, तो हैबरोफेक्ट ने उसे कवर किया है :))
यहां कोड पाया जा सकता है।

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


All Articles