为啥文档为空?

Posted

技术标签:

【中文标题】为啥文档为空?【英文标题】:Why is document null?为什么文档为空? 【发布时间】:2018-01-07 08:35:34 【问题描述】:

**已更新**,解决方案接近工作:

我正在尝试让我的“跳转到内容”链接跳转到“#content-start”之后的第一个可聚焦元素。

登录-base.component.ts:

import  Component, OnInit  from '@angular/core';
import  Inject, Injectable  from '@angular/core';
import  DOCUMENT  from '@angular/platform-browser';

@Component(
    selector: 'app-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.scss']
)

export class BaseLoginComponent implements OnInit 

    constructor(
        @Inject(DOCUMENT) private document: any
        ) 
    


    skip() 
        console.log(document);
        console.log(document.querySelector);
        var content = document.querySelector(`#content-start`); // ?? document is null!!
        if (content) 
            var control = content.querySelector('input, button, a');
            console.log(control);
            //if (control) 
            //    control.focus(); // first only
            //
        
    ;

    ngOnInit() 
        this.document.getElementById('skipLink').onclick = this.skip;
        this.document.getElementById('skipLink').onkeypress = function (e) 
            if (e.keyCode == 13) 
                this.skip();
            
        

    

login.component.html:

<div class="login-page">
    <section class="main container" id="content-start">
        <input type="text"/>

这确实有效,因为 console.log(control) 返回

<input _ngcontent-c4="" id="username" name="username">

这实际上是正确的控制。

但我不能只设置 .focus(),因为我拥有的是 HTML sn-p,而不是带有方法的对象,例如 .focus();

呃,有 jQuery 的 $(control) 的 Angular 等价物吗?

【问题讨论】:

离题。 @Component 扩展自 @Injectable,无需使用 @Injectable 注释您的组件 ***.com/questions/37521298/… 也许这将有助于假设您的文档注入不起作用 【参考方案1】:

这是因为 DOM 尚未加载到 ngOnInit 中。更新你的代码看起来像这样,实现AfterViewInit:

export class AppComponent implements AfterViewInit
constructor(
    @Inject(DOCUMENT) private document: any
)  


ngAfterViewInit() 

    this.document.getElementById('skipLink').onclick = skipLink;
    this.document.getElementById('skipLink').onkeypress = function (e) 
        if (e.keyCode == 13) 
            skipLink();
        
    

    function skipLink() 
        let content: HTMLElement = this.document.querySelector("#content-start"); // ?? document is null!!
        if (content) 
            let control: HTMLElement = this.document.querySelector('input, button, a');
            console.log(control);
            if (control) 
                // control.focus(); // first only
            
        
    

ngAfterViewInit 就像它听起来的那样;它仅在最初加载视图后运行。

根据您的问题进行编辑:您正在寻找angular.element。这方面的文档真的很有帮助,并且是在 Angular 中操作元素的更好的编程实践。

【讨论】:

这没什么区别。相同的“未定义”错误。我已将代码从 app.component 移到 login-base-component 以确保我没有任何跨组件问题。 (开篇已更新)。现在我没有收到任何错误,但仍然无法访问控件来聚焦它。 有趣。您是否尝试过angular.element(具体是.find() 函数)? (作为说明,即使它没有任何区别,我还是建议使用ngAfterViewInit 作为更好的编程习惯) 编辑:错误:“找不到名称 'angular'”(这是 Ang2) 你有 Jquery 吗?无论哪种方式,这里都解释了另一个(甚至可能更好)的解决方案:Using ViewChild in Angular to Access a Child Component, Directive or DOM Element 不知道如何实现它。此外,仅访问 DOM 元素似乎非常困难。让我觉得我只关注一个元素是错误的。【参考方案2】:

正如您所发现的,skipLink 应该是您的组件类的一个方法。为了在skipLink 内部保持正确的this,您可以使用addEventListener 和箭头函数设置事件处理程序:

public ngOnInit() 
    this.document.getElementById('skipLink').addEventListener("click", () =>  
      this.skipLink(); 
    );
    this.document.getElementById('skipLink').addEventListener("keypress", (e) => 
        if (e.keyCode == 13) 
            this.skipLink();
        
    


private skipLink() 
    let control: HTMLElement = this.document.querySelector('input, button, a');
    if (control) 
        control.focus();
    

您可以在this plunker 中查看代码。


正如Kevin 所述,使用ViewChild 是一种更标准的方式来引用组件中的元素。您可以在目标元素上定义一个模板引用变量(例如下面组件模板中的#firstButton),使用ViewChild 获取对它的引用,并使用nativeElement 属性获取HTML 元素本身。至于事件处理程序,您可以使用 Angular 绑定来设置它们(例如(click)="skipLink()")。

该方法显示在this plunker:

import  Component, NgModule, Inject, ElementRef, ViewChild  from '@angular/core';
...

@Component(
    selector: 'my-app',
    template: `
        <button #firstButton>Focusable Button</button>
        <br/>
        <button (click)="skipLink()">Click here to set focus on first button</button>
    `,
    ...
)
export class App 

    @ViewChild("firstButton") private firstButton: ElementRef;

    private skipLink() 
        this.firstButton.nativeElement.focus();
    
   

【讨论】:

很好的解释,我忘记了箭头函数。【参考方案3】:

这与最初的实现相差甚远;如果我更新开头的帖子,那么 cmets 将毫无意义。

按照 Kevin 的建议按照 Using ViewChild in Angular to Access a Child Component, Directive or DOM Element 实施,(除非我有误解):

import  Component, ViewChild, AfterViewInit, ElementRef    from '@angular/core';

export class AppComponent 

    @ViewChild('firstControl') firstControl: ElementRef;

    skipLink() 
        console.log(this.firstControl);
        //if (this.firstControl)  this.firstControl.focus(); 
    ;

.

<a href="#content-start" id="skipLink" (click)="skipLink()">Skip to main content</a>

不幸的是,这也好不到哪里去。 this.firstControl 未定义

【讨论】:

你可以看看my answer。它显示了一个代码示例,以及一个您可以尝试的工作 plunker(相关代码在文件 src/app.ts 中)。

以上是关于为啥文档为空?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 Service Worker 的推送事件数据/有效负载为空?

为啥指数推送令牌为空

为啥我的 response.body 为空,而我的后端设备令牌为空?

为啥 FusedLocationApi.getLastLocation 为空

我想知道为啥 request.form 为空

为啥字符串可以为空? [复制]