Якорная ссылка Ember.js
У меня есть окно входа на главную страницу, на которую мне нужно установить ссылку. В поле ввода есть id="login
"в html, и у меня есть ссылка на него, как на этом <li><a href="#login">Login</a></li>
, поэтому щелкните по нему, чтобы он переместил меня в этот логин для входа, но когда я нажму обновить или перейду непосредственно к ссылке с привязкой, я получаю Uncaught Error: No route matched the URL 'login'
У кого-нибудь есть идеи, как я могу выполнить эту простую задачу в Ember? Спасибо.
Обновление
Вот как выглядит мой код:
Навигация
<ul class="nav navbar-nav pull-right">
<li><a href="#login">Signup</a></li>
<li>{{#linkTo 'about'}}About{{/linkTo}}</li>
</ul>
и где-то ниже на странице у меня
<section id="login">
-- some content
</section>
Ответы
Ответ 1
Параметр запроса
Обновленный ответ на основе подхода Query Params (в настоящее время включен флаг с 21 декабря 2013 года)
Основываясь на alexspellers оригинальной JSFiddle, полную демо можно найти здесь: http://jsfiddle.net/E3xPh/
В вашем Router
добавьте поддержку параметров запроса
App.Router.map ->
@resource 'index', path: '/', queryParams: ['anchor']
Используя Route
по вашему выбору, настройте свойство для параметра запроса anchor
в методе setupController
.
App.IndexRoute = Em.Route.extend
setupController: (controller, context, queryParams) ->
controller.set 'anchorLocation', queryParams.anchor
Наконец, в Controller
сделайте наблюдателем свойство anchorLocation
.
App.IndexController = Em.ArrayController.extend
showAnchor: (->
$elem = $(@anchorLocation)
$scrollTo = $('body').scrollTop($elem.offset().top)
).observes 'anchorLocation'
Теперь вы можете использовать следующий код в своих шаблонах, чтобы прокрутить до якоря или указать браузеру /#/?anchor=#login
, например.
{{#linkTo anchor='#login'}}Show login{{/linkTo}}
Простой подход к действию
Возможный ответ, основанный на том, что вы написали в комментариях к первому ответу. Здесь взломали что-то простое.
http://jsbin.com/osEfokE/11
Нажав на ссылку "Индекс", вы перейдете в IndexRoute и прокрутите страницу входа в систему, однако URL-адрес не отражает это изменение, и ввод #login также не будет работать.
App.ApplicationRoute = Ember.Route.extend({
events: {
goToLink: function(item, anchor) {
var $elem = $(anchor);
var $scrollTo = $('body').scrollTop($elem.offset().top);
this.transitionToRoute(item.route).then($scrollTo); //.transitionTo is depricated
}
}
});
Вместо использования linkTo вы будете использовать goToLink в своем шаблоне, если хотите прокрутить до якоря.
<ul>
<li><a href="#/" {{action goToLink "index" "#login"}}>Index</a></li>
<li>{{#linkTo about}}About{{/linkTo}}</li>
<li>{{#linkTo contact}}Contact{{/linkTo}}</li>
</ul>
Ответ 2
Проблема заключается в том, что Ember использовал хэш-часть в URL-адресе для хранения текущего состояния вашего приложения. Спонтанно я вижу два возможных решения.
1 - * Не позволяйте Ember использовать хэш-часть ваших URL-адресов. * Поэтому используйте функцию размещения HTML5 history Ember. Это приведет к URL-адресам, таким как yourdomain.com/users/1/
без #
.
App.Router.reopen({
location: 'history'
});
2 - Не используйте эту технику. Вместо этого используйте jQuery, чтобы прокрутить соответствующую часть. Это может выглядеть так:
<ul class="nav navbar-nav pull-right">
<li><a {{action jumpToLogin}}>Signup</a></li>
<li>{{#linkTo 'about'}}About{{/linkTo}}</li>
</ul>
И в соответствующем представлении:
App.YourView = Ember.View.extend({
jumpToLogin : function(){
$('html, body').animate({
scrollTop: $("#login").offset().top
}, 2000);
}
});
Это может показаться большим количеством кода для этой небольшой функции, но я думаю, что это приятный пользовательский интерфейс? На самом деле вы можете улучшить этот подход, извлекая эту логику в mixin, поэтому вам не нужно повторять ее снова и снова:
App.ScrollToMixin = Ember.Mixin.create({
scrollDuration : 2000, //default
scrollTo : function(selector){
$('html, body').animate({
scrollTop: $(selector).offset().top
}, this.get("scrollDuration");
)
});
// mix it into your View
App.YourView = Ember.View.extend(App.ScrollToMixin, {});
И используйте его в своем шаблоне:
<ul class="nav navbar-nav pull-right">
<li><a {{action scrollTo "login"}}>Signup</a></li>
<li>{{#linkTo 'about'}}About{{/linkTo}}</li>
</ul>
PS: Я не тестировал код с помощью mixin. Я не совсем уверен, что строка "login" передается в обработчик действий точно так же. Поэтому вам нужно будет проверить: -)
Ответ 3
Я использую компонент, который также может быть расширен для поддержки параметров запроса посредством действия.
var ScrollToComponent = Ember.Component.extend({
tagName: 'a',
anchor: '',
scrollTo: function () {
var anchor = this.get('anchor'),
$el = Ember.$(anchor);
if ($el) {
Ember.$('body').scrollTop($el.offset().top);
}
}.on('click')
});
Вот как вы его используете:
{{#scroll-to anchor=anchor}}Jump To Anchor{{/scroll-to}}
Где anchor
есть #my-id
.
Edit
Здесь добавлен ember-cli addon, который делает это https://www.npmjs.com/package/ember-scroll-to
Ответ 4
Я получил эту работу в Ember с помощью простого действия из ответа kroovy.
Поскольку Ember изменил свой API, мне пришлось немного изменить подход kroovys.
Две вещи изменились:
- События в Ember.Route устарели и заменены действиями в Ember.Controller
- вместо перехода к вам нужно использовать transitionToRoute
Вот как я работал в Ember версии 1.7.0
Ember Handlebars-Template new.hbs
{{!-- Navigation --}}
<ul>
<li {{action 'goToLink' "new" "#part1"}}>Part 1</li>
<li {{action 'goToLink' "new" "#part2"}}>Part 2</li>
</ul>
{{!-- content --}}
<div id="part1" class="row">...</div>
<div id="part2" class="row">...</div>
Ember App.Controller NewController.js
App.NewController = Ember.ArrayController.extend({
actions: {
goToLink: function(item, anchor) {
console.log('NewController > goToLink');
var $elem = $(anchor);
var $scrollTo = $('body').scrollTop($elem.offset().top);
this.transitionToRoute(item.route).then( $scrollTo);
}
}
});
Ответ 5
Проблема с большинством предыдущих ответов заключается в том, что если маршрут не изменяется при нажатии на ссылку с "href hash/fragment/id", то в ember router не будут запускаться крючки, необходимые для выполнения большинство предыдущих решений.
Это видно на страницах с несколькими заголовками, в которых вы хотите разрешить пользователю перейти от "nav/index или list links" к соответствующему разделу страницы (например, на условиях обслуживания или о страницах),
В этих ситуациях ember требует, чтобы вы "переключились на полный переход", чтобы маршрутизатор загорелся, даже если маршрут не изменился, но параметры запроса имеют. Для получения дополнительной информации см. "выбор в полный переход" .
ПРИМЕЧАНИЕ. Единственный документированный, который будет запущен при использовании этого параметра "выбрать", - это крючок модели.
Я считаю, что этот "полный переход" был предназначен только для использования при обновлении моделей при изменении параметров запроса для таких вещей, как сортировка или фильтрация.
По общему признанию, это кажется немного взломанным, но вышеупомянутый "opt-in" можно использовать для прокрутки к нашему тегу div/anchor. В будущем возможность включения может также запустить другие более подходящие крючки (setupController специально будет приятным).
Также в случае, если кто-то еще отправляется в Google. Я также попытался использовать действия "willTransition" и "didTransition" на маршруте. Хотя они увольнялись при переходе с других маршрутов, к сожалению, они также не срабатывают при переходе от одного и того же маршрута к себе.
Наконец, некоторым должно быть очевидно (но не было для меня вначале), что для того, чтобы браузер перешел к указанному id, dom должен быть полностью загружен. Поэтому мы должны выполнить прокрутку внутри обратного вызова Ember.run.schedule('afterRender',
.
FYI Я использую последние данные ember-cli, ember.js и ember-data, доступные в настоящий момент:
- ember-cli: 1.13.7
- ember: 1.13.6
- ember-data: 1.13.7
приложение/router.js
this.route('about', {
queryParams: ['anchor']
});
маршруты/about.js
import Ember from 'ember';
export default Ember.Route.extend({
queryParams: {
anchor: {
refreshModel: true
}
},
model: function(params) {
var aboutController = this.controllerFor('about');
aboutController.set('anchorLocation', params.anchor);
}
});
приложение/контроллеры/about.js
import Ember from "ember";
export default Ember.Controller.extend({
queryParams: ['anchor'],
anchor: '',
showAnchor: function() {
var _this = this;
Ember.run.schedule('afterRender', function scrollToAnchor(){
var elem = Ember.$(_this.anchorLocation);
elem.get(0).scrollIntoView(true);
});
}.observes('anchorLocation'),
});
приложение/шаблоны/footer.js
<ul>
<li>
{{#link-to "about" (query-params anchor='#contact')}}Contact{{/link-to}}
</li>
<li>
{{#link-to "about" (query-params anchor='#support')}}Support{{/link-to}}
</li>
<li>
{{#link-to "about" (query-params anchor='#team')}}Team{{/link-to}}
</li>
</ul>
Ответ 6
Моя проблема заключалась в том, что если бы я нажал ссылку назначения с другой страницы, она пошла бы туда, но не прокрутила вниз до нужной части страницы. Через несколько часов я исправился:
Примечание: я использую ember-cli
и emblem
и ember 1.8
в моем navigation bar
(в application.emblem
)
li
a#concept-link click=jumpToConcept
| Le Concept
то, если я уже на странице, я просто прокручиваю вверх. Если я еще не на странице, я перехожу на эту страницу с параметрами запроса concept=true
action
в application controller
scrollToConcept: function() {
Ember.$(document).ready(
Ember.$('html, body').animate({
scrollTop: Ember.$("#concept").offset().top
}, 750)
)
},
//allow clicking of link with specific id to go to that part of page
jumpToConcept : function(){
if (this.get('currentPath') === 'index') {
this.send('scrollToConcept');
} else {
this.transitionToRoute('index', { queryParams: {concept: true}});
}
}
in index controller
Затем я добавляю concept query params
export default Ember.Controller.extend(
queryParams: ['concept'],
concept: null
}
Затем я добавляю событие scrollToConcept
в index view
(страница, на которую я только что перешел), который прослушивает загрузку страницы и проверяет concept queryParam
. Если concept=true
, я перейду к понятной части страницы.
index view
scrollToConcept: function() {
if (this.controller.get('concept') === 'true') {
Ember.$('html, body').animate({
scrollTop: Ember.$("#concept").offset().top
}, 750);
}
}.on('didInsertElement')
то для обычного index links
я добавляю действие, которое устанавливает concept=null
, чтобы concept query param
не отображался в URL-адресе.
ссылка в nav bar
a click=goToIndex
h3 id={logoClass} Happy Dining
тогда в application controller
я иду index route
, установите для concept query param
значение null (поэтому он не отображается в URL-адресе) и прокрутите вверх (только если он был ниже на странице)
actions: {
goToIndex: function() {
this.transitionToRoute('index', { queryParams: {concept: null}});
Ember.$(window).scrollTop(0);
}
}
Надеюсь, что это поможет людям в будущем!!!
Ответ 7
Если кто-то пытается решить эту проблему с Ember 3, у меня есть решение. Он использует тот же подход queryParams, что и другие, но я не смог заставить работать контроллер. Единственный подход, который я нашел сработавшим, заключался в использовании функции route + jQuery.ready.
// route/application.js
import Route from '@ember/routing/route';
import $ from 'jquery';
export default Route.extend({
queryParams: {
anchor: null
},
setupController: function(controller, context, params) {
let anchor = params.queryParams.anchor;
// On ready, find the anchor offset and go there
$().ready(function() {
let anchorOffset = $("#" + anchor).offset().top
window.scrollTo(0, anchorOffset);
});
}
});