问题
In an angular 5 component I have a table, and I need to create something like overlaying multiple divs above several td's. What's the best way to get the position of those td's in the table so I can position the other elements?
I'm currently trying to use something like
@ViewChild('table')
tableElement: ElementRef
ngAfterViewChecked() {
this.tableElement.nativeElement.getElementsByClassName('cell')
// ...
}
But I'm risking some weird infinite loops doing it this way. Is there a way to know that a specific element was "redrawn", for instance?
回答1:
The "infinite" loop is normal cause you run the function in the AfterViewChecked lifecycle hook.
By design : AfterViewChecked Lifecycle hook that is called after every check of a component's view.
I would use getBoundingClientRect
to get top, bottom, width, height etc. const domRect = element.getBoundingClientRect();
https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect, but I am not sure I understood which in which event you want to run the getElement. What do you mean by "redrawn" ? You can try to get the position after promise is been resolved if the data is coming dynamically.
回答2:
As far as I understand you want to position an html element (the td) relative to another (the div). This seems to be a plain html and css issue.
You could position both elements in a containing box with
position: relative;
And the div that you want to position above should have following properties so that they overlap with your td
position: absolute;
top: /*your top value*/;
left: /*your left value*/;
If you really want to get the exact position of your td then you need to extract the top, bottom, right and left position via Javascript.
this.tableElement.nativeElement.getElementsByClassName('cell').getBoundingClientRect();
回答3:
One way: merge a stream from resize events and a subject. Instead of a subject, if you're fetching the data with http you could use the same observable you already have from there, like http.get(...).pipe(share())
import {merge} from 'rxjs/observable/merge';
import {fromEvent} from 'rxjs/observable/fromEvent';
import {Subject} from 'rxjs/Subject};
// ...
tableChange$:Subject<void> = new Subject();
ngOnInit() {
merge(
fromEvent(window, 'resize'),
this.tableChange$
).subscribe(() => {
this.tableElement.nativeElement.getElementsByClassName('cell')...
}); // remember to unsubscribe this subscription at OnDestroy in real life
this.tableChange$.next();
}
Edit:
It might be a cleaner & simpler solution to move this concern to a component you'd use inside those TDs. You can use ng-content
to show whatever content inside the component, and get an elementRef by injecting it in the constructor. And if you still need to talk to the parent, use outputs.
来源:https://stackoverflow.com/questions/49636332/how-can-i-get-an-angular-5-component-elements-position