简体   繁体   中英

In page link reloads page

I'm building my first Angular 2 app and I've come quite far now with a nice Webpack build system, routing, services and components in place.

I tried adding a normal in page link ( [href^="#"] ) in one of my components, and as long as I'm on the home page ( / ) it works fine, but whenever I'm on a different URL the whole app reloads to the home page.

Apparently this is a known issue ( https://github.com/angular/angular/issues/6595 ) but I need this to work right now so I'm hoping someone can teach me how.

I'm not sure it'll help, but here's my Component's TS and HTML:

import { Component } from '@angular/core';
import { ROUTER_DIRECTIVES } from '@angular/router-deprecated';

@Component({
    selector: 'home',
    template: require('./home.component.html'),
    directives: [ROUTER_DIRECTIVES]
})
export class HomeComponent {

}

<section id="home" class="section section--full-height">

    <h2>Title of the home page</h2>

    <nav>
        <a [routerLink]="['Search']" class="button button--wide">Search</a>
        <a [routerLink]="['Search']">Quick try</a>
    </nav>

    <footer>
        <a href="#home-2" class="icon-down icon--below">Heres how it works</a>
    </footer>

</section>

<section id="home-2" class="section section--full-height">

    <h2>Lorem ipsum dolor</h2>

    <img src="http://placehold.it/200x300">

</section>

As you can see it's the link "here's how it works" (or any other in page link - I have more than this one in reality) that only works (scrolls down to the linked element) when you're on the home page ( / ). If on any other URL, the link will reload the app.

In case you don't want to modify anything: PLUNKER DEMO

Just put this Directive in your Component, and you're done.

@Directive({
  selector: 'a[href^=#]',
  inputs: ['href'],
  host: {
    "(click)": "linkClicked($event)"
  }
})
export class InPageLinks {
  href: string;

  linkClicked(e){ // handles click event, only prevents the links with a # in the beginning

      e.preventDefault();
      this.scrollToID(this.href);
  }

  scrollToID(id){ // scrolls to the given id
    let target = document.querySelector(id);

    document.body.scrollTop = target.offsetTop;  
    // current scroll-target is body, you can take another input if you want
  }
}

In the current release of the router - version 3.0.0-alpha.8 - there is a way to add hash fragments to your links. However, the angular team still has some work to do to make it function properly.

On your anchor element, add a fragment attribute with the hash value.

If you want to generate a local link, just use this notation:

<a [routerLink]="['./']" fragment="Test">Jump to 'Test' anchor </a>

If you were at the location

www.example.org/Comp1/Comp2

before, this will change the URL to

www.example.org/Comp1/Comp2#Test

This will also work when linking to another component:

<a [routerLink]="['Comp3']" fragment="Test">Jump to 'Test' anchor </a>

which will take you to

www.example.org/Comp1/Comp2/Comp3#Test

However...

There still seems to be a bug in angular's implementation. Although the link is generated and updated correctly in the address bar of the browser, the browser does not jump to the specified hash location. It only does that, when you move your cursor into the address bar and hit enter, which obviously does not help.

I commented again on the github post referenced by @powerbuoy and @Günter-Zöchbauer to give the Angular team a heads up on the issue.

Unfortunately, I've also learnt the hard way trying to develop a real-world app with angular2 before its release that you really should stay as far away from the current development as possible, especially in terms of the router(s).

The third iteration of the router is currently extremely alpha and I've run across so many issues that I've had to revert its implementation which as you likely know is quite a bit of work as the API has changed considerably.

As far as your issue is concerned though, I haven't actually found that any of the routers actually implement hashes correctly and I've had to get around this with a scroll component that looks something like the below:

@Directive({
  selector: '[scroll-to-target-on-event]'
})
export class ScrollToTargetOnEventDirective {

  @Input('scroll-to-target-on-event') configs:Array<{target:Element, event:string}>;

  constructor(private _element:ElementRef) {
  }

  ngOnInit() {

    for (let config of this.configs) {
      this._element.nativeElement.addEventListener(config.event, () => {
          // Get the position of the target relative to the entire page. getBoundingClientRect is relative to the
          // viewport so to get relative to the entire page we subtract the body (as we're looking to use scrollpos)
          var targetYPos = config.target.getBoundingClientRect().top - document.body.getBoundingClientRect().top;

          // If the target position is below the bottom of the viewport then scroll to it. (This should actually
          // check above as well, haven't implemented it though)
          if (targetYPos > (document.documentElement.scrollTop || document.body.scrollTop) + (document.documentElement.clientHeight|| window.innerHeight)) {
            window.scrollTo(0, config.target.getBoundingClientRect().top - document.body.getBoundingClientRect().top);
          }
      });
    }
  }
}

You can then add this directive to an element on the given page.

<a href="" [scroll-to-target-on-event]="[{target: '#id-of-target-element', event:'click'}]">Link</a>

I hope this helps you solve your issue for the time being!

https://github.com/angular/angular/issues/6595最近已修复,将包含在下一个版本中(可能今天)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM