在 Angular 6 中使用 @ViewChild 创建粘性元素 - 无法获取元素的位置
Using @ViewChild in Angular 6 to create a sticky element- can't get element's position
我正在使用 Angular 6 尝试创建一个 HTML 元素 (table headers),该元素位于页面中间但会坚持当用户滚动到该点时页面顶部。我正在尝试使用 @ViewChild 获取该元素的位置,但无法检索它。可能缺少什么?
目前,始终应用 'sticky' class,但我只想在元素位置 <= 到 window.pageYOffset 时应用粘性 class。
我正在尝试实现与 THIS using THIS 教程类似的效果。
我的HTML:
<table id="tabletop" class="table" >
<thead >
<tr #stickyMenu [class.sticky] = "stickyMenu" >
<th scope="col" id="th0">Monitoring Point</th>
<th scope="col" id="th1">Network Health<br><small id="more_detail">(Click icon to see more detail)</small></th>
<th scope="col" id="th2">Active Alerts</th>
<th scope="col" id="th3">Velocity (ft/s)</th>
<th scope="col" id="th4">Water Temperature (°F)</th>
<th scope="col" id="th5">Depth Readings (m)</th>
</tr>
</thead>
</table>
css:
.sticky{
position: fixed;
top: 0;
/* overflow: hidden; */
z-index: 10;
background-color: #fff;
width:100%;
padding-right:20px!important;
}
我的组件:
import { Component, OnInit, ViewChild , ViewEncapsulation, HostListener, ElementRef, AfterViewInit} from '@angular/core';
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { AuthService } from '../../services/auth.service';
import { SiteService } from '../../services/site.service';
import { SiteModel } from '../../models/site-model';
import { BaseComponent } from '../base.component';
import { DomSanitizer } from '@angular/platform-browser';
import { DateTime } from 'luxon';
@Component({
selector: 'app-site',
templateUrl: './site.component.html',
styleUrls: ['./site.component.css','../../../vizuly/lib/styles/vizuly.css']
})
export class SiteComponent extends BaseComponent implements OnInit, AfterViewInit {
siteHid;
scute_data;
window_narrow;
scute_data_ready: Boolean;
sticky: boolean = false;
elementPosition: any;
constructor(public sanitizer: DomSanitizer, private route: ActivatedRoute, protected router: Router, private authService: AuthService, private siteService: SiteService) {
super();
}
@ViewChild("stickyMenu", {read: ElementRef}) tr: ElementRef;
ngOnInit() {
this.route.paramMap.subscribe((params: ParamMap) => {
this.siteHid = params.get('siteHid');
this.loadSite(this.siteHid);
});
}
ngAfterViewInit(){
console.log(this.tr)
this.elementPosition = this.tr.nativeElement
// this.elementPosition = this.stickyMenu.nativeElement.offsetTop;
console.log(this.elementPosition) //undefined
}
@HostListener('window:scroll', ['$event'])
handleScroll() {
console.log(this.sticky, window.pageYOffset, this.elementPosition)
this.sticky = (window.pageYOffset >= this.elementPosition) ? true : false;
console.log(this.sticky)
}
loadSite(siteHid){
}
}
你能否尝试重现你的问题blitzy我得到的是 offset top 0 而不是你提到的 undefined。
也直接用位置
console.log(this.tr)
//this.elementPosition = this.tr.nativeElement
console.log(this.tr.nativeElement);
console.log(this.tr.nativeElement.offsetTop);
您在此处绑定了错误的属性:
[class.sticky] = "stickyMenu"
应该是
[class.sticky] = "sticky"
我想你想取消注释 1 行并更改为:
ngAfterViewInit(){
this.elementPosition = this.tr.nativeElement.offsetTop;
console.log(this.elementPosition);
}
因为 stickyMenu 仅在 DOM 中命名。
所有其他答案都有拼图,但 IMO 缺少一件事,从 this.tr.nativeElement.offsetTop
中获取 this.elementPosition
返回的值太小。
正在查看MDN - HTMLElement.offsetTop
The HTMLElement.offsetTop read-only property returns the distance of the current element relative to the top of the offsetParent node.
但本例中的 offsetParent 是 <thead>
,而不是 window 的顶部,这正是需要与 handleScroll()
中的 window.scrollTop
进行比较的地方。
(Giovanni Chiodi 的粘性元素接近 window 顶部,因此 offsetTop
适合他)。
这个SO问题How to get an element's top position relative to the browser's viewport有更好的获取元素位置的方法,
var viewportOffset = el.getBoundingClientRect();
// these are relative to the viewport, i.e. the window
var top = viewportOffset.top;
所以我会将您的代码更改为:
模板
<table id="tabletop" class="table" >
<thead >
<tr #stickyMenu [class.sticky] = "sticky">
...
分量
@ViewChild("stickyMenu", { read: ElementRef }) tr: ElementRef;
ngAfterViewInit() {
this.elementPosition = this.tr.nativeElement.getBoundingClientRect().top;
}
@HostListener('window:scroll', ['$event'])
handleScroll() {
this.sticky = (window.pageYOffset >= this.elementPosition);
}
我正在使用 Angular 6 尝试创建一个 HTML 元素 (table headers),该元素位于页面中间但会坚持当用户滚动到该点时页面顶部。我正在尝试使用 @ViewChild 获取该元素的位置,但无法检索它。可能缺少什么?
目前,始终应用 'sticky' class,但我只想在元素位置 <= 到 window.pageYOffset 时应用粘性 class。
我正在尝试实现与 THIS using THIS 教程类似的效果。
我的HTML:
<table id="tabletop" class="table" >
<thead >
<tr #stickyMenu [class.sticky] = "stickyMenu" >
<th scope="col" id="th0">Monitoring Point</th>
<th scope="col" id="th1">Network Health<br><small id="more_detail">(Click icon to see more detail)</small></th>
<th scope="col" id="th2">Active Alerts</th>
<th scope="col" id="th3">Velocity (ft/s)</th>
<th scope="col" id="th4">Water Temperature (°F)</th>
<th scope="col" id="th5">Depth Readings (m)</th>
</tr>
</thead>
</table>
css:
.sticky{
position: fixed;
top: 0;
/* overflow: hidden; */
z-index: 10;
background-color: #fff;
width:100%;
padding-right:20px!important;
}
我的组件:
import { Component, OnInit, ViewChild , ViewEncapsulation, HostListener, ElementRef, AfterViewInit} from '@angular/core';
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { AuthService } from '../../services/auth.service';
import { SiteService } from '../../services/site.service';
import { SiteModel } from '../../models/site-model';
import { BaseComponent } from '../base.component';
import { DomSanitizer } from '@angular/platform-browser';
import { DateTime } from 'luxon';
@Component({
selector: 'app-site',
templateUrl: './site.component.html',
styleUrls: ['./site.component.css','../../../vizuly/lib/styles/vizuly.css']
})
export class SiteComponent extends BaseComponent implements OnInit, AfterViewInit {
siteHid;
scute_data;
window_narrow;
scute_data_ready: Boolean;
sticky: boolean = false;
elementPosition: any;
constructor(public sanitizer: DomSanitizer, private route: ActivatedRoute, protected router: Router, private authService: AuthService, private siteService: SiteService) {
super();
}
@ViewChild("stickyMenu", {read: ElementRef}) tr: ElementRef;
ngOnInit() {
this.route.paramMap.subscribe((params: ParamMap) => {
this.siteHid = params.get('siteHid');
this.loadSite(this.siteHid);
});
}
ngAfterViewInit(){
console.log(this.tr)
this.elementPosition = this.tr.nativeElement
// this.elementPosition = this.stickyMenu.nativeElement.offsetTop;
console.log(this.elementPosition) //undefined
}
@HostListener('window:scroll', ['$event'])
handleScroll() {
console.log(this.sticky, window.pageYOffset, this.elementPosition)
this.sticky = (window.pageYOffset >= this.elementPosition) ? true : false;
console.log(this.sticky)
}
loadSite(siteHid){
}
}
你能否尝试重现你的问题blitzy我得到的是 offset top 0 而不是你提到的 undefined。
也直接用位置
console.log(this.tr)
//this.elementPosition = this.tr.nativeElement
console.log(this.tr.nativeElement);
console.log(this.tr.nativeElement.offsetTop);
您在此处绑定了错误的属性:
[class.sticky] = "stickyMenu"
应该是
[class.sticky] = "sticky"
我想你想取消注释 1 行并更改为:
ngAfterViewInit(){
this.elementPosition = this.tr.nativeElement.offsetTop;
console.log(this.elementPosition);
}
因为 stickyMenu 仅在 DOM 中命名。
所有其他答案都有拼图,但 IMO 缺少一件事,从 this.tr.nativeElement.offsetTop
中获取 this.elementPosition
返回的值太小。
正在查看MDN - HTMLElement.offsetTop
The HTMLElement.offsetTop read-only property returns the distance of the current element relative to the top of the offsetParent node.
但本例中的 offsetParent 是 <thead>
,而不是 window 的顶部,这正是需要与 handleScroll()
中的 window.scrollTop
进行比较的地方。
(Giovanni Chiodi 的粘性元素接近 window 顶部,因此 offsetTop
适合他)。
这个SO问题How to get an element's top position relative to the browser's viewport有更好的获取元素位置的方法,
var viewportOffset = el.getBoundingClientRect();
// these are relative to the viewport, i.e. the window
var top = viewportOffset.top;
所以我会将您的代码更改为:
模板
<table id="tabletop" class="table" >
<thead >
<tr #stickyMenu [class.sticky] = "sticky">
...
分量
@ViewChild("stickyMenu", { read: ElementRef }) tr: ElementRef;
ngAfterViewInit() {
this.elementPosition = this.tr.nativeElement.getBoundingClientRect().top;
}
@HostListener('window:scroll', ['$event'])
handleScroll() {
this.sticky = (window.pageYOffset >= this.elementPosition);
}