Angular 5 和 jQuery 插件覆盖 DOM
Angular 5 and jQuery plugin overwriting the DOM
我正在 Angular 中集成一个 jQuery 插件并遇到一些问题
笨蛋:https://next.plnkr.co/edit/pNCmYOo4vizJuj9V
请注意滑块幻灯片显示正确然后 plunker 首先加载,单击 "toggle" 按钮更改幻灯片并注意现在滑块已永久损坏。
解决此问题的最佳方法是什么?
import {
Component,
OnInit,
EventEmitter,
ChangeDetectorRef,
Input,
ElementRef,
AfterViewInit,
Output,
} from '@angular/core';
export interface FlexSliderSlide {
id: string;
name: string;
image: string;
}
@Component({
selector: 'flexslider',
template: `
<div class="clearfix">
<div class="clearfix" *ngIf="_slides">
<div flexslider class="flexslider carousel">
<ul class="slides">
<li [ngClass]="{ selected: selectedSlide?.id === slide.id }" *ngFor="let slide of _slides" (click)="onSlideSelected(slide)">
<div class="title">
{{ slide.name }}
</div>
<div class="img">
<img class="img-responsive" [src]="slide.image" [attr.alt]="slide.name" />
</div>
</li>
</ul>
</div>
</div>
</div>
`,
styles: [`
.carousel {
margin: 0;
border: solid 1px #ccc;
padding: 20px;
}
.slides > li .img {
cursor: pointer;
border: solid 1px #ccc;
}
.slides > li:hover .img {
box-shadow: 0 0 8px rgba(0, 0, 0, .2);
}
.slides > li.selected .img {
box-shadow: 0 0 8px rgba(0, 0, 0, .2);
border: solid 2px #00ccb0;
}
.title {
color: #4A4A4A;
font-size: 17px;
font-weight: bold;
line-height: 16px;
margin-bottom: 16px;
}
::ng-deep .flex-control-nav.flex-control-paging {
display: none;
}
::ng-deep .flexslider ul.flex-direction-nav {
position: static !important;
}
::ng-deep .flexslider ul.flex-direction-nav a {
width: 20px;
height: 20px;
margin: -10px 0 0;
}
::ng-deep .flexslider ul.flex-direction-nav a:before {
font-size: 18px;
}
`]
})
export class FlexSliderComponent implements AfterViewInit {
private _slides: FlexSliderSlide[];
// Most magic happens below...!
@Input() set slides(v: FlexSliderSlide[]) {
if (v && (JSON.stringify(v) !== JSON.stringify(this._slides))) {
// ^-- Checks whether the model has somehow changed.
console.log('triggering change');
$(this.el.nativeElement.querySelector('.flexslider')).removeData("flexslider");
// ^-- remove existing data...
this._slides = v;
this.cd.detectChanges();
// ^-- Force a redraw..
this.ngAfterViewInit();
// ^ -- Reinit the jQuery element.
}
}
@Output() onSelected = new EventEmitter();
selectedSlide: FlexSliderSlide;
constructor(
private cd: ChangeDetectorRef,
private el: ElementRef
) { }
ngAfterViewInit(): void {
$(this.el.nativeElement.querySelector('.flexslider')).flexslider({
animation: 'slide',
animationLoop: false,
slideshow: false,
controlNav: false,
itemWidth: 250,
itemMargin: 54
});
}
onSlideSelected(selected: FlexSliderSlide) {
this.selectedSlide = selected;
this.onSelected.emit(selected);
this.cd.detectChanges();
}
}
基本上,这似乎与 flexSlider 本身有关,您可以在这里阅读更多相关信息:
由于不可刷新,每次源更改时都必须重新绘制整个jQuery元素,因此需要检查源是否已更改。为了做到这一点,我只是做了一个字符串化检查,你可以实现一个更聪明的方法来检查项目是否改变了(也许 id 检查就足够了?)。
也就是说,替换完slide后,需要触发changed detection refresh,让组件重绘,然后再调用ngAfterInit重新初始化slider,这样就很漂亮了。
我正在 Angular 中集成一个 jQuery 插件并遇到一些问题
笨蛋:https://next.plnkr.co/edit/pNCmYOo4vizJuj9V
请注意滑块幻灯片显示正确然后 plunker 首先加载,单击 "toggle" 按钮更改幻灯片并注意现在滑块已永久损坏。
解决此问题的最佳方法是什么?
import {
Component,
OnInit,
EventEmitter,
ChangeDetectorRef,
Input,
ElementRef,
AfterViewInit,
Output,
} from '@angular/core';
export interface FlexSliderSlide {
id: string;
name: string;
image: string;
}
@Component({
selector: 'flexslider',
template: `
<div class="clearfix">
<div class="clearfix" *ngIf="_slides">
<div flexslider class="flexslider carousel">
<ul class="slides">
<li [ngClass]="{ selected: selectedSlide?.id === slide.id }" *ngFor="let slide of _slides" (click)="onSlideSelected(slide)">
<div class="title">
{{ slide.name }}
</div>
<div class="img">
<img class="img-responsive" [src]="slide.image" [attr.alt]="slide.name" />
</div>
</li>
</ul>
</div>
</div>
</div>
`,
styles: [`
.carousel {
margin: 0;
border: solid 1px #ccc;
padding: 20px;
}
.slides > li .img {
cursor: pointer;
border: solid 1px #ccc;
}
.slides > li:hover .img {
box-shadow: 0 0 8px rgba(0, 0, 0, .2);
}
.slides > li.selected .img {
box-shadow: 0 0 8px rgba(0, 0, 0, .2);
border: solid 2px #00ccb0;
}
.title {
color: #4A4A4A;
font-size: 17px;
font-weight: bold;
line-height: 16px;
margin-bottom: 16px;
}
::ng-deep .flex-control-nav.flex-control-paging {
display: none;
}
::ng-deep .flexslider ul.flex-direction-nav {
position: static !important;
}
::ng-deep .flexslider ul.flex-direction-nav a {
width: 20px;
height: 20px;
margin: -10px 0 0;
}
::ng-deep .flexslider ul.flex-direction-nav a:before {
font-size: 18px;
}
`]
})
export class FlexSliderComponent implements AfterViewInit {
private _slides: FlexSliderSlide[];
// Most magic happens below...!
@Input() set slides(v: FlexSliderSlide[]) {
if (v && (JSON.stringify(v) !== JSON.stringify(this._slides))) {
// ^-- Checks whether the model has somehow changed.
console.log('triggering change');
$(this.el.nativeElement.querySelector('.flexslider')).removeData("flexslider");
// ^-- remove existing data...
this._slides = v;
this.cd.detectChanges();
// ^-- Force a redraw..
this.ngAfterViewInit();
// ^ -- Reinit the jQuery element.
}
}
@Output() onSelected = new EventEmitter();
selectedSlide: FlexSliderSlide;
constructor(
private cd: ChangeDetectorRef,
private el: ElementRef
) { }
ngAfterViewInit(): void {
$(this.el.nativeElement.querySelector('.flexslider')).flexslider({
animation: 'slide',
animationLoop: false,
slideshow: false,
controlNav: false,
itemWidth: 250,
itemMargin: 54
});
}
onSlideSelected(selected: FlexSliderSlide) {
this.selectedSlide = selected;
this.onSelected.emit(selected);
this.cd.detectChanges();
}
}
基本上,这似乎与 flexSlider 本身有关,您可以在这里阅读更多相关信息:
由于不可刷新,每次源更改时都必须重新绘制整个jQuery元素,因此需要检查源是否已更改。为了做到这一点,我只是做了一个字符串化检查,你可以实现一个更聪明的方法来检查项目是否改变了(也许 id 检查就足够了?)。 也就是说,替换完slide后,需要触发changed detection refresh,让组件重绘,然后再调用ngAfterInit重新初始化slider,这样就很漂亮了。