Angular 11,js在角度路由后不起作用

Posted

技术标签:

【中文标题】Angular 11,js在角度路由后不起作用【英文标题】:Angular 11, js not working after routing in angular 【发布时间】:2021-07-13 03:55:38 【问题描述】:

我一直在对 Angular 中的一个错误进行研发(不是称其为错误)。但是在 SPA 中,js 在路由到不同的组件后失去了作用域。我已经阅读了互联网上几乎所有可用的答案。让我以更简单的方式说明问题所在。

    作用域在我们路由到不同的元素后结束(我们使用的是外部 js) 由于我的 js 是相互连接的,所以必须一次加载。所以通过 component.ts 方法加载特定的 js 是不可行的,因为它再次改变了 DOM 的范围并且其他功能停止工作。

所以如果有人遇到这样的问题,让我们在这里讨论。

更新的图像:

我的代码:Script-loader.ts

从 '@angular/core' 导入 Injectable ; @Injectable( providedIn: 'root' ) 导出类 ScriptLoaderService

private scripts: any = ;

load(...scripts: string[]) 
    this.scripts = scripts;
    let promises: any[] = [];
    scripts.forEach((script) => promises.push(this.loadScript(script)));
    return Promise.all(promises);


loadScript(name: string) 
    return new Promise((resolve, reject) => 
        let script = (document.createElement('script') as any);
        script.type = 'text/javascript';
        script.src = name;
        script.async = false;
        script.defer = false;
        


        if (script.readyState)   //IE
            script.onreadystatechange = () => 
                if (script.readyState === 'loaded' || script.readyState === 'complete') 
                    script.onreadystatechange = null;
                    resolve(script: name, loaded: true, status: 'Loaded');
                
            ;
         else   //Others
            script.onload = () => 
                resolve(script: name, loaded: true, status: 'Loaded');
            ;
        

        script.onerror = (error: any) => resolve(script: name, loaded: false, status: 'Loaded');
        document.getElementsByTagName('head')[0].appendChild(script);
    );

块引用

blogs.component.ts

从'@angular/core'导入组件,OnInit,AfterViewInit; 从'../script-loader.service'导入 ScriptLoaderService ; 声明 var $: any;

@Component( 选择器: 'app-blogs', templateUrl: './blogs.component.html', styleUrls: ['./blogs.component.css'] ) 导出类 BlogsComponent 实现 OnInit、AfterViewInit

构造函数(私有脚本加载器:ScriptLoaderService)

ngAfterViewInit(): 无效 this.scriptloader.load( '资产/js/app.js', '资产/数据/tipuedrop_content.js', '资产/js/global.js', 'assets/js/navbar-v1.js', '资产/js/main.js', 'assets/js/widgets.js',

  'assets/js/lightbox.js',
  'assets/js/feed.js',
  
);

   

ngOnInit(): 无效

博客.module.ts

从'@angular/core'导入 NgModule ;

从“@angular/router”导入 Routes, RouterModule ;进口 BlogsComponent 来自 './blogs.component';

常量路由:Routes = [ 小路: ””, 组件:博客组件];

@NgModule( 进口:[RouterModule.forChild(routes)],出口: [RouterModule] ) 导出类 BlogsModule

videos.component.ts

从'@angular/core'导入组件,OnInit,AfterViewInit; 从'../script-loader.service'导入 ScriptLoaderService ; 声明 var $: any; @Component( 选择器: 'app-videos', templateUrl: './videos.component.html', styleUrls: ['./videos.component.css'] ) 导出类 VideosComponent 实现 OnInit, AfterViewInit

构造函数(私有脚本加载器:ScriptLoaderService) ngAfterViewInit(): 无效 this.scriptloader.load( '资产/js/app.js', '资产/数据/tipuedrop_content.js', '资产/js/global.js', 'assets/js/navbar-v1.js', 'assets/js/main.js',

  'assets/js/widgets.js',
  
  'assets/js/lightbox.js',
  'assets/js/feed.js',
);

   

ngOnInit(): 无效

videos.module.ts

从'@angular/core'导入 NgModule ;

从“@angular/router”导入 Routes, RouterModule ;进口 VideosComponent 来自 './videos.component';

常量路由:Routes = [ 小路: ””, 组件:视频组件];

@NgModule( 进口:[RouterModule.forChild(routes)],出口: [RouterModule] ) 导出类 VideosModule

App-routing.module.ts

从'@angular/core'导入 NgModule ;进口路由器模块, 来自'@angular/router'的路线;导入 PreloadingStrategy, PreloadAllModules 来自“@angular/router”;导入 BlogsModule 来自'./blogs/blogs.module';导入 FeedModule 从 './feed/feed.module';导入 HangoutModule 从 './hangout/hangout.module';导入 HomeModule 从 './home/home.module';从导入 VideosModule './videos/videos.module';

常量路由:Routes = [

路径:“饲料”, loadChildren: "./feed/feed.module#FeedModule" , 路径:“阅读”, loadChildren: "./blogs/blogs.module#BlogsModule" , 路径:“观看”, loadChildren: "./videos/videos.module#VideosModule" , 路径:'家', loadChildren:"./home/home.module#HomeModule" , 路径:“环聊”, loadChildren:"./hangout/hangout.module#HangoutModule"

];

@NgModule( 导入:[RouterModule.forRoot(路由, preloadingStrategy: PreloadAllModules )], 出口: [RouterModule] ) 出口类 AppRoutingModule

现在当我从博客路由到视频时发生了什么。它再次添加了之前的所有js。我不知道这是否是一个好习惯。这是显示正在发生的事情的 DOM HEAD

附:没有适合您的确切解决方案。请在 component.ts 中编写您自己的 js。可以导入jquery,写qwery

【问题讨论】:

您是否想过将跨多个组件工作所需的任何 js 放入服务中,然后从服务中调用这些函数/变量? 我已经更新了代码。我使用了它,但它没有工作,我制作了一个 script.service.ts 文件并定义了函数,然后我使用 ngonit 调用它。那么由于js是相互关联的。这一切都必须一次加载。但它没有用。 嘿!我已经使用您的代码来实现和解决我的错误。它在一定程度上解决了它,但它再次在 DOM 中加载所有 js 文件。就像我在第一次刷新时有 3 个 js 文件(或 2 个脚本标签)一样。然后,如果我路由到另一个组件。它正在重新加载 js,但现在 HTML DOM 有 6 个脚本标签。如果你想让我分享代码,我会的。 它是这样显示的。只包含一个js文件。首次访问页面 。然后在路由到另一个组件时,它现在在字段中有 2 个相同的 js 【参考方案1】:

其他方式。

您可以在组件的ngOnInit()ngAfterViewInit() 上加载脚本,我更喜欢ngAfterViewInit(),但是如何:

首先,创建一个名为 "script-loader.service.ts".ts 文件或任何您想要的文件。 粘贴以下代码。

import  Injectable  from '@angular/core';
@Injectable()
export class ScriptLoaderService 

    private scripts: any = ;

    load(...scripts: string[]) 
        this.scripts = scripts;
        let promises: any[] = [];
        scripts.forEach((script) => promises.push(this.loadScript(script)));
        return Promise.all(promises);
    

    loadScript(name: string) 
        return new Promise((resolve, reject) => 
            let script = (document.createElement('script') as any);
            script.type = 'text/javascript';
            script.src = name;

            if (script.readyState)   //IE
                script.onreadystatechange = () => 
                    if (script.readyState === 'loaded' || script.readyState === 'complete') 
                        script.onreadystatechange = null;
                        resolve(script: name, loaded: true, status: 'Loaded');
                    
                ;
             else   //Others
                script.onload = () => 
                    resolve(script: name, loaded: true, status: 'Loaded');
                ;
            

            script.onerror = (error: any) => resolve(script: name, loaded: false, status: 'Loaded');
            document.getElementsByTagName('head')[0].appendChild(script);
        );
    


然后,在顶层模块中提供此服务,例如app.module.ts

import  NgModule  from '@angular/core';
import  ScriptLoaderService  from './script-loader.service';

@NgModule(
    imports: [
    ],
    providers: [
        ScriptLoaderService
    ],
    declarations: [
    ],
    exports: [
                ]
)
export class AppModule  

现在是时候使用这个服务了,假设你想在ngAfterViewInit()初始化方法中使用它,所以你必须在你的目标组件中实现AfterViewInit;例如:

import  Component, AfterViewInit  from '@angular/core';
import  ScriptLoaderService  from '@shared/utils/script-loader.service';

@Component(
    templateUrl: './your.component.html'
)

export class YourComponent implements AfterViewInit 

    constructor(
        private scriptLoader: ScriptLoaderService) 

    

    ngAfterViewInit() 
        this.scriptLoader.load(
            'assets/dist/jquery.min.js',
            'assets/ckeditor/ckeditor.js'
        );
    

通过这种方式,每当你的组件被 Angular 路由器延迟加载时,所需的脚本都会在不硬刷新页面的情况下初始化。

【讨论】:

我得试试这个方法。我只想问一件事。假设我有 5 个组件都是延迟加载的。一个附加到routerlink,例如:通过博客文章、视频文章、状态和其他组件进行路由的组件保持不变。所以每当我在刷新后将一个组件路由到另一个组件时。只有延迟加载的组件再次停止工作,它是 js。其他组件像以前一样继续工作,只是 js 在路由组件上无效。有什么办法解决这个问题? 从一个组件路由到另一个组件时,您是否会硬刷新任何页面?如果你这样做,我认为你必须改变你的方式,并且永远不要像 Angular 那样硬刷新 SPA。如果没有,请分享您的代码。 嘿!我已经使用您的代码来实现和解决我的错误。它在一定程度上解决了它,但它再次在 DOM 中加载所有 js 文件。就像我在第一次刷新时有 3 个 js 文件(或 2 个脚本标签)一样。然后,如果我路由到另一个组件。它正在重新加载 js,但现在 HTML DOM 有 6 个脚本标签。如果你想让我分享我会的代码。 —— 我已经添加了 DOM 图像。 嗨!我已经分享了上面的代码,请检查并提出建议。谢谢【参考方案2】:

您可以将您的 JS 库甚至您的 CSS 文件添加到 angular.json 文件中以用于更高范围的用途(全局):


  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": 
    "mehdi-daustany": 
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "architect": 
        "build": 
          "builder": "@angular-devkit/build-angular:browser",
            "assets": [
              "src/assets",
              "src/favicon.png"
            ],


            "styles": [
              "src/public-styles.css"
            ],

            "scripts": [
              "node_modules/jquery/dist/jquery.min.js",
              "node_modules/@microsoft/signalr/dist/browser/signalr.min.js",
              "src/assets/common/js/components/util.js"
            ]


           ...

将这些编译为文件的文件导入到您的 DOM 中,命名为:scripts.jsstyles.js。 因此,请按您的项目逻辑顺序导入它们。

【讨论】:

是的,我试过了。这是我做的第一件事。没有结果。它不应该以这种方式工作,但确实如此。每当通过路由链接发生路由时,路由组件就会失去其功能,然后我必须刷新页面以使其再次工作。但是,如果我必须使用刷新,则没有使用角度。 您可以在组件的 ngOnInit() 或 ngAfterViewInit() 上加载脚本,让我在另一篇文章中为您解释另一种方式。

以上是关于Angular 11,js在角度路由后不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Angular 11 路由在 AWS S3 和 Cloudfront 中不起作用

使用 Angular js 验证 jquery 下拉插件不起作用

Angular JS路由不起作用

当在浏览器中直接访问 URL 但单击到时,角度路由不起作用?

Angular 6.0.3 HTML 组件选择器不起作用

jquery datepicker在导航到另一个组件后不起作用