Javascript 根据请求动态注入HTML和CSS
所以我一直在研究如何从服务器加载CSS和HTML 我想要实现的是请求显示某个模板,该模板将HTML和CSS发送到网站,并将其与一些用户定义的样式(如颜色)一起加载 到目前为止,我能够使用以下方法注入HTML:Javascript 根据请求动态注入HTML和CSS,javascript,html,css,angular,Javascript,Html,Css,Angular,所以我一直在研究如何从服务器加载CSS和HTML 我想要实现的是请求显示某个模板,该模板将HTML和CSS发送到网站,并将其与一些用户定义的样式(如颜色)一起加载 到目前为止,我能够使用以下方法注入HTML: <div [innerHTML]="template | sanitizeHtml"></div> 我在不同的帖子和博客上看到过(谢谢你) 我一直在构建的HTML非常有魅力: this.template = "<div clas
<div [innerHTML]="template | sanitizeHtml"></div>
我在不同的帖子和博客上看到过(谢谢你)
我一直在构建的HTML非常有魅力:
this.template = "<div class='template' style='width: 1080px; height: 1920px; background-color: #212121;'><div class='clr-row' style='padding:45px 0px 10px 25px; position: relative; width: inherit;'><div class='clr-col-5'><div style='width: 230px; height: 60px; background-image: url(*LINK_TO_IMAGE*); background-repeat: no-repeat; float: left;'></div></div></div></div>"
(对于那些想知道的人)
编辑2:
因此,我一直在研究如何使用这些模板:
用户可以注册多个设备,以显示office 365中的预订。用户可以通过两种方式设置模板,但这并不重要。当用户想要显示特定设备的模板时,他们会转到/device/:deviceid/template/:templateid。
这样,组件将加载到该设备的模板中。
因此,首先我们加载设备设置,其中包含模板的用户样式。然后,我们从office365加载必须显示在模板中的数据,最后使用模板样式加载模板。
因此,将有3个对服务器的请求。
设备设置--数据办公室365--模板
到目前为止,我已经能够加载数据并将其放入模板中,但模板在本地可用,而不是从服务器上可用。
我希望从服务器请求模板的原因是,将有一个管理门户,在那里制作和管理这些模板。
这些模板将有一个名称、HTML和CSS。在经过清理的HTML中不使用
[ngStyle]
,而是只更改dom元素的类,其中插入了经过清理的HTML:
<div [ngClass]="templateClass" [innerHTML]="templateHtml"></div>
对于较大的模板差异,您可以使用Angular CDK Portal: 此处示例:更新日期:2020年10月14日: 以前的解决方案要求包含编译器,这样您就无法在生产模式下构建项目。由于Owen Kelvins的回答,现在可以添加动态html和css,同时仍在生产中构建,因为它不需要编译器: 要添加自定义CSS,您可以使用Owen Kelvins方法或在html末尾附加“”标记,并将自定义CSS与end标记一起添加 原始答复: 我已经找到了这个问题的解决办法。多亏了discord服务器“Thecodingden”中的某个人,他给我发了消息,并给我一个指向Github的链接。翻阅这篇长文章后,我找到了答案。这就是我如何使用它来创建一个组件,该组件可以通过服务器请求基于给定id显示不同的模板,我还添加了一些注释来解释它
import { Component, AfterViewInit, Compiler, NgModule, ViewChild, ViewContainerRef, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BookingService } from 'src/app/services/booking.service';
import { ApplicationModel } from 'src/app/models/application.model';
import { Booking } from 'src/app/models/vo/booking';
import { Subscription } from 'rxjs';
import { SplitStringPipe } from '../../utils/split-string.pipe';
import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { BrowserModule } from '@angular/platform-browser';
@Component({
selector: 'app-bookings-template',
templateUrl: './bookings-template.component.html',
styleUrls: ['./bookings-template.component.css']
})
export class BookingsTemplateComponent implements AfterViewInit {
public template: string;
public date: Date;
public locale: string;
public id: string;
@ViewChild('container', { read: ViewContainerRef, static: false }) container: ViewContainerRef;
constructor(private compiler: Compiler, private bs: BookingService, private apm: ApplicationModel) { }
ngAfterViewInit() {
// Must clear cache.
this.compiler.clearCache();
// fill in template from server request
this.template = "<div class="test">{{test}}</div>;
var styles = ".test{color:red}";
// Define the component using Component decorator.
const component = Component({
template: this.template + "<div>Hard Coded html for error checks and loading spinner</div>",
styles: [styles]
})(class implements OnInit {
//example properties
public date: Date;
public bookings: Array<Booking>;
public isLoading: boolean = true;
public hasError: boolean = false;
public errorMessage: string;
public errorMessageSub: Subscription;
public bs: BookingService;
public apm: ApplicationModel;
// Do not pass any parameters in the constructor or it will break!
// Instead pass it within the factory method down below as a property!
constructor() {
// refresh template every minute
setInterval(() => {
this.ngOnInit();
}, 60000);
// refresh date every second
setInterval(() => {
this.date = new Date();
}, 1000);
}
ngOnInit() {
// get data to fill in template
}
ngOnDestroy() {
//remove error subscription
this.errorMessageSub.unsubscribe();
}
});
// Define the module using NgModule decorator.
//Modules can be changed based on your needs
const module = NgModule({
imports: [
CommonModule,
BrowserAnimationsModule,
BrowserModule,
HttpClientModule],
declarations: [component, SplitStringPipe],
providers: [BookingService]
})(class { });
// Asynchronously (recommended) compile the module and the component.
this.compiler.compileModuleAndAllComponentsAsync(module)
.then(factories => {
// Get the component factory.
const componentFactory = factories.componentFactories[0];
// Create the component and add to the view.
const componentRef = this.container.createComponent(componentFactory);
// pass parameters that would go in the constructor as properties
// subscriptions should also work.
componentRef.instance.bs = this.bs;
componentRef.instance.apm = this.apm;
componentRef.instance.errorMessageSub = this.apm.getMessageError().subscribe(me => componentRef.instance.errorMessage = me);
});
}
}
警告:
其中最重要的因素是,您不能以生产模式构建项目。这是因为JIT编译不起作用,您将得到以下错误:
这是因为angular编译器不包括在生产环境中,即使您尝试手动添加它。仅为div添加类并使用scss/css文件添加样式不是更符合逻辑吗?当前模板不可读。此外,它还可以解决这个问题。您已经在使用style属性设置div的样式。同样的,你也使用了ngStyle。可能是因为这个,它没有被加载。@Billy Cottrell是的。我明白。但您可以只更改类名,并将所有样式代码存储在单独的css/scss文件中。它使代码更干净。而且拥有多个模板也没有问题。在这个项目中,我正在尝试的是现在有4个模板,但我可以很容易地添加新的模板。所以,我建议在您放入净化的InnerHtml的元素上使用NgClass。@Billy Cottrell如果仅基于用户设置,您只更改类,并且所有其他内容都存储在scss/css中,应用程序应该运行得很快。在这种情况下,您将拥有数百个特定于css的类。我将写一个我将如何做到这一点的答案。但是要知道模板也包含样式,还需要使用TrustStyles。不知道两者是否可以在同一个html上使用。但我认为不是。所以事情应该有所不同。好吧,我想我理解你的意思,但是ngClass在templateHtml变量中可以工作吗,我只是尝试在那里使用它,但似乎不起作用?因此在.ts文件中,如下所示:
this.templateHTML=“”代码>这就是我需要在templateHtml内部应用样式的问题,如果样式表是从api下载的,那么我应该如何应用它?@Billy Cottrell试着看一下这个问题答案:门户设置看起来非常有趣,可能是一条路要走,我肯定会进一步研究这个问题。你能更新stackblitz链接吗?因为它似乎不起作用。我总是收到一个无法获取/api/angular/v1
错误。谢谢你的帮助!如果我想使用门户,我需要为我想使用的每个模板制作一个组件。所以如果我有大约500个模板,我需要制作500个组件?那太疯狂了。我只希望像保存常规数据一样保存模板,并通过向服务器发出请求来获得某个模板。我猜Angular不支持从服务器请求加载模板。
@NgModule({
declarations: [
...,
SanitizeHtmlPipe
],
...
});
<div [ngClass]="templateClass" [innerHTML]="templateHtml"></div>
.template-class-1 {
background-color: #f44336;
}
.template-class-2 {
background-color: #4caf50;
}
import { Component, AfterViewInit, Compiler, NgModule, ViewChild, ViewContainerRef, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BookingService } from 'src/app/services/booking.service';
import { ApplicationModel } from 'src/app/models/application.model';
import { Booking } from 'src/app/models/vo/booking';
import { Subscription } from 'rxjs';
import { SplitStringPipe } from '../../utils/split-string.pipe';
import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { BrowserModule } from '@angular/platform-browser';
@Component({
selector: 'app-bookings-template',
templateUrl: './bookings-template.component.html',
styleUrls: ['./bookings-template.component.css']
})
export class BookingsTemplateComponent implements AfterViewInit {
public template: string;
public date: Date;
public locale: string;
public id: string;
@ViewChild('container', { read: ViewContainerRef, static: false }) container: ViewContainerRef;
constructor(private compiler: Compiler, private bs: BookingService, private apm: ApplicationModel) { }
ngAfterViewInit() {
// Must clear cache.
this.compiler.clearCache();
// fill in template from server request
this.template = "<div class="test">{{test}}</div>;
var styles = ".test{color:red}";
// Define the component using Component decorator.
const component = Component({
template: this.template + "<div>Hard Coded html for error checks and loading spinner</div>",
styles: [styles]
})(class implements OnInit {
//example properties
public date: Date;
public bookings: Array<Booking>;
public isLoading: boolean = true;
public hasError: boolean = false;
public errorMessage: string;
public errorMessageSub: Subscription;
public bs: BookingService;
public apm: ApplicationModel;
// Do not pass any parameters in the constructor or it will break!
// Instead pass it within the factory method down below as a property!
constructor() {
// refresh template every minute
setInterval(() => {
this.ngOnInit();
}, 60000);
// refresh date every second
setInterval(() => {
this.date = new Date();
}, 1000);
}
ngOnInit() {
// get data to fill in template
}
ngOnDestroy() {
//remove error subscription
this.errorMessageSub.unsubscribe();
}
});
// Define the module using NgModule decorator.
//Modules can be changed based on your needs
const module = NgModule({
imports: [
CommonModule,
BrowserAnimationsModule,
BrowserModule,
HttpClientModule],
declarations: [component, SplitStringPipe],
providers: [BookingService]
})(class { });
// Asynchronously (recommended) compile the module and the component.
this.compiler.compileModuleAndAllComponentsAsync(module)
.then(factories => {
// Get the component factory.
const componentFactory = factories.componentFactories[0];
// Create the component and add to the view.
const componentRef = this.container.createComponent(componentFactory);
// pass parameters that would go in the constructor as properties
// subscriptions should also work.
componentRef.instance.bs = this.bs;
componentRef.instance.apm = this.apm;
componentRef.instance.errorMessageSub = this.apm.getMessageError().subscribe(me => componentRef.instance.errorMessage = me);
});
}
}
import { NgModule, CompilerFactory, Compiler, COMPILER_OPTIONS } from '@angular/core';
import { JitCompilerFactory } from '@angular/platform-browser-dynamic';
import { CommonModule } from '@angular/common';
export function createCompiler(compilerFactory: CompilerFactory) {
return compilerFactory.createCompiler();
}
@NgModule({
declarations: [
// components and pipes
...
],
imports: [
CommonModule, // required
... //other modules
],
providers: [
// different services
...,
// these are need to add the compiler manually to the project
{ provide: COMPILER_OPTIONS, useValue: {}, multi: true },
{ provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS] },
{ provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory] }
],
bootstrap: [AppComponent]
})
export class AppModule { }