इसका मेरा समाधान समाप्त होने से कुछ कम स्वचालित हो गया, लेकिन कम से कम यह लगातार है।
यह सहेजने और बहाल करने के लिए मेरा कोड था। यह कोड मेरे वास्तविक समाधान पर मेरे प्रयास से काफी अधिक था, जिसे इसे विभिन्न घटनाओं पर बुलाया गया था। "मुलायम" एक ध्वज है कि यह एक ब्राउज़र कार्रवाई (बैक, फॉरवर्ड, या हैश क्लिक) से आया है, जो राउटर.नाविगेट() को "हार्ड" कॉल के विपरीत है। एक नेविगेट() कॉल के दौरान मैं बस शीर्ष पर स्क्रॉल करना चाहता था।
restoreScrollPosition: function(route, soft) {
var pos = 0;
if (soft) {
if (this.routesToScrollPositions[route]) {
pos = this.routesToScrollPositions[route];
}
}
else {
delete this.routesToScrollPositions[route];
}
$(window).scrollTop(pos);
},
saveScrollPosition: function(route) {
var pos = $(window).scrollTop();
this.routesToScrollPositions[route] = pos;
}
मैं भी Backbone.History संशोधित ताकि हम (जो checkUrl कॉल) एक "सॉफ्ट" इतिहास परिवर्तन पर प्रतिक्रिया प्रोग्राम के रूप में एक "हार्ड" इतिहास परिवर्तन ट्रिगर बनाम के बीच अंतर बता सकते हैं। यह इस ध्वज को राउटर कॉलबैक में भेजता है।
_.extend(Backbone.History.prototype, {
// react to a back/forward button, or an href click. a "soft" route
checkUrl: function(e) {
var current = this.getFragment();
if (current == this.fragment && this.iframe)
current = this.getFragment(this.getHash(this.iframe));
if (current == this.fragment) return false;
if (this.iframe) this.navigate(current);
// CHANGE: tell loadUrl this is a soft route
this.loadUrl(undefined, true) || this.loadUrl(this.getHash(), true);
},
// this is called in the whether a soft route or a hard Router.navigate call
loadUrl: function(fragmentOverride, soft) {
var fragment = this.fragment = this.getFragment(fragmentOverride);
var matched = _.any(this.handlers, function(handler) {
if (handler.route.test(fragment)) {
// CHANGE: tell Router if this was a soft route
handler.callback(fragment, soft);
return true;
}
});
return matched;
},
});
मूल रूप से मैं स्क्रॉल बचत करने और पूरी तरह से हैशनल हैंडलर के दौरान बहाल करने की कोशिश कर रहा था। अधिक विशेष रूप से, राउटर के कॉलबैक रैपर के भीतर, अज्ञात फ़ंक्शन जो आपके वास्तविक मार्ग हैंडलर को आमंत्रित करता है।
route: function(route, name, callback) {
Backbone.history || (Backbone.history = new Backbone.History);
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
if (!callback) callback = this[name];
Backbone.history.route(route, _.bind(function(fragment, soft) {
// CHANGE: save scroll position of old route prior to invoking callback
// & changing DOM
displayManager.saveScrollPosition(foo.lastRoute);
var args = this._extractParameters(route, fragment);
callback && callback.apply(this, args);
this.trigger.apply(this, ['route:' + name].concat(args));
// CHANGE: restore scroll position of current route after DOM was changed
// in callback
displayManager.restoreScrollPosition(fragment, soft);
foo.lastRoute = fragment;
Backbone.history.trigger('route', this, name, args);
}, this));
return this;
},
मैं चीजों को इस तरह संभाल करना चाहता था, क्योंकि यह सभी मामलों में बचत की अनुमति देता है कि क्या एक href क्लिक करें, वापस बटन, आगे बटन, या नेविगेट() कॉल।
ब्राउज़र में एक "सुविधा" है जो हैशचेंज पर आपकी स्क्रॉल को याद रखने की कोशिश करती है, और हैश पर वापस जाने पर इसे स्थानांतरित करती है। आम तौर पर यह बहुत अच्छा होता, और मुझे इसे लागू करने की सभी परेशानी बचाता। समस्या यह है कि मेरा ऐप, कई लोगों की तरह, पृष्ठ से पृष्ठ पर डीओएम की ऊंचाई को बदलता है।
उदाहरण के लिए, मैं एक लंबा #list दृश्य पर हूं और नीचे स्क्रॉल किया है, फिर एक आइटम पर क्लिक करें और एक छोटी सी #detail व्यू पर जाएं जिसमें कोई स्क्रॉलबार नहीं है। जब मैं बैक बटन दबाता हूं, तो ब्राउज़र मुझे #list दृश्य के लिए अंतिम स्थिति तक स्क्रॉल करने का प्रयास करेगा। लेकिन दस्तावेज़ अभी तक लंबा नहीं है, इसलिए ऐसा करने में असमर्थ है। जब तक #list के लिए मेरा मार्ग बुलाया जाता है और मैं सूची को फिर से दिखाता हूं, स्क्रॉल स्थिति खो जाती है।
तो, ब्राउज़र की अंतर्निहित स्क्रॉल मेमोरी का उपयोग नहीं कर सका। जब तक मैंने दस्तावेज़ को एक निश्चित ऊंचाई नहीं बनाया या कुछ डोम चालबाजी नहीं की, जिसे मैं नहीं करना चाहता था।
इसके अलावा अंतर्निहित स्क्रॉल व्यवहार उपर्युक्त प्रयास को गड़बड़ कर देता है, क्योंकि सहेजने के लिए कॉल बहुत देर हो चुकी है - ब्राउजर ने तब तक स्क्रॉल स्थिति बदल दी है।
इसका समाधान, जो स्पष्ट होना चाहिए था, मार्ग कॉलबैक रैपर के बजाय राउटर.नाविगेट() से saveScrollPosition को कॉल कर रहा था। यह गारंटी देता है कि ब्राउजर हैशचेंज पर कुछ भी करने से पहले मैं स्क्रॉल स्थिति को सहेज रहा हूं।
route: function(route, name, callback) {
Backbone.history || (Backbone.history = new Backbone.History);
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
if (!callback) callback = this[name];
Backbone.history.route(route, _.bind(function(fragment, soft) {
// CHANGE: don't saveScrollPosition at this point, it's too late.
var args = this._extractParameters(route, fragment);
callback && callback.apply(this, args);
this.trigger.apply(this, ['route:' + name].concat(args));
// CHANGE: restore scroll position of current route after DOM was changed
// in callback
displayManager.restoreScrollPosition(fragment, soft);
foo.lastRoute = fragment;
Backbone.history.trigger('route', this, name, args);
}, this));
return this;
},
navigate: function(route, options) {
// CHANGE: save scroll position prior to triggering hash change
nationalcity.displayManager.saveScrollPosition(foo.lastRoute);
Backbone.Router.prototype.navigate.call(this, route, options);
},
दुर्भाग्य से यह भी मतलब है मैं हमेशा स्पष्ट रूप से, नेविगेट कॉल करने के लिए() अगर मैं स्क्रॉल स्थिति की बचत करने में रुचि है के रूप में बस अपना टेम्पलेट्स में href = "# myhash" का उपयोग करने का विरोध किया है।
ओह ठीक है। यह काम करता हैं। :-)
आप 'स्थिति() शीर्ष' का उपयोग करके मौके से नहीं हैं और आपके पास तत्वों को प्राप्त करने वाले माता-पिता तत्व हैं जो डोम लोड के बाद 'कुछ भी' हैं? – Ohgodwhy
नहीं, मैं स्क्रॉल स्थिति – schematic