मैं एक मोबाइल ऐप बनाना चाहता हूं, जो html / css और JavaScript से अधिक नहीं है। जबकि मेरे पास जावास्क्रिप्ट के साथ एक वेब ऐप बनाने का एक अच्छा ज्ञान है, मैंने सोचा कि मैं jquery-mobile जैसे ढांचे में देख सकता हूं।
सबसे पहले, मैंने सोचा था कि jquery-mobile कुछ और नहीं तो एक विजेट फ्रेमवर्क था जो मोबाइल ब्राउज़रों को लक्षित करता है। बहुत कुछ jquery-ui के समान है लेकिन मोबाइल दुनिया के लिए। लेकिन मैंने देखा कि jquery-mobile इससे कहीं अधिक है। यह आर्किटेक्चर के एक समूह के साथ आता है और चलो आप एक घोषणात्मक HTML सिंटैक्स के साथ ऐप बनाते हैं। तो सबसे आसान विचारशील ऐप के लिए, आपको अपने आप से जावास्क्रिप्ट की एक पंक्ति लिखने की आवश्यकता नहीं होगी (जो शांत है, क्योंकि हम सभी कम काम करना पसंद करते हैं, क्या हम नहीं?)
एक घोषणात्मक HTML सिंटैक्स का उपयोग करके ऐप्स बनाने के दृष्टिकोण का समर्थन करने के लिए, मुझे लगता है कि नॉकआउट के साथ jquery-mobile को संयोजित करना एक अच्छा है। नॉकआउटज क्लाइंट-साइड एमवीवीएम फ्रेमवर्क है जिसका उद्देश्य एमवीवीएम सुपर शक्तियों को WPF / सिल्वरलाइट से जावास्क्रिप्ट दुनिया में लाना है।
मेरे लिए MVVM एक नई दुनिया है। जबकि मैंने इसके बारे में पहले ही बहुत कुछ पढ़ा है, मैंने वास्तव में इसे पहले कभी खुद इस्तेमाल नहीं किया है।
तो यह पोस्टिंग यह है कि jquery-mobile और knockoutjs का उपयोग करके एक ऐप को कैसे आर्किटेक्चर किया जाए। मेरा विचार उस दृष्टिकोण को लिखना था जिसे मैं कई घंटों तक देखने के बाद आया था, और यह टिप्पणी करने के लिए कुछ jquery- मोबाइल / नॉकआउट योडा है, मुझे दिखा रहा है कि यह क्यों बेकार है और मुझे पहले प्रोग्रामिंग क्यों नहीं करनी चाहिए स्थान ;-)
एचटीएमएल
jquery-mobile पृष्ठों की एक बुनियादी संरचना मॉडल प्रदान करने के लिए एक अच्छा काम करता है। जबकि मुझे अच्छी तरह से पता है कि मैं अपने पेज को बाद में ajax के माध्यम से लोड कर सकता था, मैंने बस उन सभी को एक index.html फ़ाइल में रखने का निर्णय लिया। इस मूल परिदृश्य में हम दो पृष्ठों के बारे में बात कर रहे हैं ताकि चीजों के शीर्ष पर बने रहना कठिन न हो।
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<link rel="stylesheet" href="libs/jquery-mobile/jquery.mobile-1.0a4.1.css" />
<link rel="stylesheet" href="app/base/css/base.css" />
<script src="libs/jquery/jquery-1.5.0.min.js"></script>
<script src="libs/knockout/knockout-1.2.0.js"></script>
<script src="libs/knockout/knockout-bindings-jqm.js" type="text/javascript"></script>
<script src="libs/rx/rx.js" type="text/javascript"></script>
<script src="app/App.js"></script>
<script src="app/App.ViewModels.HomeScreenViewModel.js"></script>
<script src="app/App.MockedStatisticsService.js"></script>
<script src="libs/jquery-mobile/jquery.mobile-1.0a4.1.js"></script>
</head>
<body>
<!-- Start of first page -->
<div data-role="page" id="home">
<div data-role="header">
<h1>Demo App</h1>
</div><!-- /header -->
<div data-role="content">
<div class="ui-grid-a">
<div class="ui-block-a">
<div class="ui-bar" style="height:120px">
<h1>Tours today (please wait 10 seconds to see the effect)</h1>
<p><span data-bind="text: toursTotal"></span> total</p>
<p><span data-bind="text: toursRunning"></span> running</p>
<p><span data-bind="text: toursCompleted"></span> completed</p>
</div>
</div>
</div>
<fieldset class="ui-grid-a">
<div class="ui-block-a"><button data-bind="click: showTourList, jqmButtonEnabled: toursAvailable" data-theme="a">Tour List</button></div>
</fieldset>
</div><!-- /content -->
<div data-role="footer" data-position="fixed">
<h4>by Christoph Burgdorf</h4>
</div><!-- /header -->
</div><!-- /page -->
<!-- tourlist page -->
<div data-role="page" id="tourlist">
<div data-role="header">
<h1>Bar</h1>
</div><!-- /header -->
<div data-role="content">
<p><a href="#home">Back to home</a></p>
</div><!-- /content -->
<div data-role="footer" data-position="fixed">
<h4>by Christoph Burgdorf</h4>
</div><!-- /header -->
</div><!-- /page -->
</body>
</html>
जावास्क्रिप्ट
तो चलिए मज़ेदार हिस्से पर आते हैं - जावास्क्रिप्ट!
जब मैंने ऐप को लेयर करने के बारे में सोचना शुरू किया, तो मेरे मन में कई चीजें थीं (उदाहरण के लिए परीक्षण क्षमता, ढीली कपलिंग)। मैं आपको दिखाने जा रहा हूं कि मैंने अपनी फ़ाइलों को विभाजित करने का निर्णय लिया और चीजों पर टिप्पणी की जैसे कि मैंने जाते समय एक चीज को दूसरे पर क्यों चुना था ...
App.js
var App = window.App = {};
App.ViewModels = {};
$(document).bind('mobileinit', function(){
// while app is running use App.Service.mockStatistic({ToursCompleted: 45}); to fake backend data from the console
var service = App.Service = new App.MockedStatisticService();
$('#home').live('pagecreate', function(event, ui){
var viewModel = new App.ViewModels.HomeScreenViewModel(service);
ko.applyBindings(viewModel, this);
viewModel.startServicePolling();
});
});
App.js मेरे ऐप का प्रवेश बिंदु है। यह ऐप ऑब्जेक्ट बनाता है और व्यू मॉडल (जल्द ही आने वाले) के लिए एक नाम स्थान प्रदान करता है। यह मोबाइलिनिट घटना के लिए सुनता है जो jquery-mobile प्रदान करता है।
जैसा कि आप देख सकते हैं, मैं कुछ प्रकार की अजाक्स सेवा का एक उदाहरण बना रहा हूं (जिसे हम बाद में देखेंगे) और इसे "सेवा" चर में सहेजें।
मैं होम पेज के लिए पेजक्रिएट ईवेंट को भी हुक करता हूं जिसमें मैं एक उदाहरण बनाता हूं जो कि सर्विस इंस्टेंस को पास कर देता है। यह बिंदु मेरे लिए आवश्यक है। यदि कोई सोचता है, तो यह अलग तरह से किया जाना चाहिए, कृपया अपने विचार साझा करें!
मुद्दा यह है कि, दृश्य मॉडल को एक सेवा (गेटटॉर /, सेवटॉर आदि) पर संचालित करने की आवश्यकता है। लेकिन मैं नहीं चाहता कि ViewModel इसके बारे में और अधिक जाने। इसलिए, उदाहरण के लिए, हमारे मामले में, मैं अभी एक नकली अजाक्स सेवा में गुजर रहा हूं क्योंकि बैकएंड अभी तक विकसित नहीं हुआ है।
एक और बात जो मुझे बतानी चाहिए, वह यह है कि ViewModel को वास्तविक दृश्य के बारे में शून्य ज्ञान है। इसीलिए पेजक्रिएट हैंडलर के भीतर से मैं ko.applyBindings (viewModel, यह) कह रहा हूं । मैं दृश्य मॉडल को वास्तविक दृश्य से अलग रखना चाहता था ताकि इसे जांचना आसान हो सके।
App.ViewModels.HomeScreenViewModel.js
(function(App){
App.ViewModels.HomeScreenViewModel = function(service){
var self = {}, disposableServicePoller = Rx.Disposable.Empty;
self.toursTotal = ko.observable(0);
self.toursRunning = ko.observable(0);
self.toursCompleted = ko.observable(0);
self.toursAvailable = ko.dependentObservable(function(){ return this.toursTotal() > 0; }, self);
self.showTourList = function(){ $.mobile.changePage('#tourlist', 'pop', false, true); };
self.startServicePolling = function(){
disposableServicePoller = Rx.Observable
.Interval(10000)
.Select(service.getStatistics)
.Switch()
.Subscribe(function(statistics){
self.toursTotal(statistics.ToursTotal);
self.toursRunning(statistics.ToursRunning);
self.toursCompleted(statistics.ToursCompleted);
});
};
self.stopServicePolling = disposableServicePoller.Dispose;
return self;
};
})(App)
जब आप एक ऑब्जेक्ट शाब्दिक सिंटैक्स का उपयोग करते हुए अधिकांश नॉकआउट दृश्य मॉडल उदाहरण पाएंगे, तो मैं 'स्व' सहायक वस्तुओं के साथ पारंपरिक फ़ंक्शन सिंटैक्स का उपयोग कर रहा हूं। असल में, यह स्वाद की बात है। लेकिन जब आप एक दूसरे को संदर्भित करने के लिए एक देखने योग्य संपत्ति चाहते हैं, तो आप ऑब्जेक्ट शाब्दिक को एक बार में नहीं लिख सकते हैं जो इसे कम सममित बनाता है। यही कारण है कि मैं एक अलग वाक्यविन्यास चुन रहा हूं।
अगला कारण वह सेवा है जिसे मैं एक पैरामीटर के रूप में पारित कर सकता हूं जैसा मैंने पहले उल्लेख किया था।
इस दृश्य मॉडल के साथ एक और बात है जो मुझे यकीन नहीं है कि मैंने सही तरीका चुना है। मैं समय-समय पर सर्वर से परिणाम लाने के लिए अजाक्स सेवा का चुनाव करना चाहता हूं। तो, मैं startServicePolling / stopServicePolling विधियों को लागू करने के लिए चुना है । यह विचार पृष्ठशो पर मतदान शुरू करने के लिए है, और जब उपयोगकर्ता अलग-अलग पृष्ठ पर जाता है तो इसे रोक दें।
आप सिंटैक्स को अनदेखा कर सकते हैं जिसका उपयोग सेवा को प्रदूषित करने के लिए किया जाता है। यह RxJS जादू है। बस सुनिश्चित करें कि मैं इसे मतदान कर रहा हूं और लौटे परिणाम के साथ अवलोकन योग्य गुणों को अपडेट कर सकता हूं जैसा कि आप सदस्यता लें (फ़ंक्शन (आंकड़े) {..}) भाग में देख सकते हैं ।
App.MockedStatisticsService.js
ठीक है, आपको दिखाने के लिए सिर्फ एक चीज बची है। यह वास्तविक सेवा कार्यान्वयन है। मैं यहाँ विस्तार में नहीं जा रहा हूँ। यह सिर्फ एक मॉक है जो गेटस्टैटिस्टिक्स के कुछ नंबर लौटाता है है। एक अन्य विधि mockStatistics है, जिसका उपयोग मैं एप्लिकेशन के चलने के दौरान ब्राउज़र js कंसोल के माध्यम से नए मान सेट करने के लिए करता हूं।
(function(App){
App.MockedStatisticService = function(){
var self = {},
defaultStatistic = {
ToursTotal: 505,
ToursRunning: 110,
ToursCompleted: 115
},
currentStatistic = $.extend({}, defaultStatistic);;
self.mockStatistic = function(statistics){
currentStatistic = $.extend({}, defaultStatistic, statistics);
};
self.getStatistics = function(){
var asyncSubject = new Rx.AsyncSubject();
asyncSubject.OnNext(currentStatistic);
asyncSubject.OnCompleted();
return asyncSubject.AsObservable();
};
return self;
};
})(App)
ठीक है, मैंने और भी बहुत कुछ लिखा जैसा कि मैंने शुरू में लिखने की योजना बनाई थी। मेरी उंगली में चोट लगी है, मेरे कुत्ते मुझे टहलने के लिए ले जाने के लिए कह रहे हैं और मुझे थकावट महसूस हो रही है। मुझे यकीन है कि यहां बहुत सारी चीजें गायब हैं और यह कि मैं टाइपो और ग्रामर गलतियों का एक समूह हूं। मुझ पर चिल्लाओ अगर कुछ स्पष्ट नहीं है और मैं बाद में पोस्टिंग को अपडेट करूंगा।
पोस्टिंग एक प्रश्न के रूप में नहीं लग सकता है, लेकिन वास्तव में यह है! मैं चाहूंगा कि आप अपने दृष्टिकोण के बारे में अपने विचार साझा करें और यदि आपको लगता है कि यह अच्छा है या बुरा है या यदि मुझे चीजें याद आ रही हैं।
अपडेट करें
प्रमुख लोकप्रियता के कारण इस पोस्टिंग को फायदा हुआ और क्योंकि कई लोगों ने मुझसे ऐसा करने के लिए कहा, मैंने इस उदाहरण का कोड जीथब पर रखा है:
https://github.com/cburgdorf/stackoverflow-knockout-example
इसे गर्म होने पर प्राप्त करें!