我正在尝试ionic2 beta9,并尝试使用离子滑动创建自定义组件,但出现错误。

父组件

<ion-content class="home" padding>
  <ion-slides loop="true">
    <slide-item *ngFor="let image of [1,2,3,4,5]" [imgIdx]="image"></slide-item>
  </ion-slides>
</ion-content>

幻灯片项目自定义组件
<ion-slide>
        <div class="bcontent">
            <div class="bimg">
                <img data-src="images/slide{{imgIdx}}.jpeg">
            </div>
            <p class="info">My text</p>
        </div>
</ion-slide>

slide-item.ts
@Component({
  selector: 'slide-item',
  templateUrl: 'build/components/slide-item/slide-item.html',
  directives: [Slides, Slide]
})
export class SlideItem {

  @Input()
  imgIdx: number;

  constructor() {
    console.log("SlideItem::constructor...imgIdx="+this.imgIdx);
  }
}

我遇到以下错误:

zone.js:461
Unhandled Promise rejection: Template parse errors:
No provider for Slides ("
  for more info on Angular 2 Components.
-->
[ERROR ->]<ion-slide>
        <div class="bcontent">
            <div class="bimg">
"): SlideItem@6:0

;区域:角度;任务:Promise.then;值:
BaseException {message: "Template parse errors:↵No provider for Slides ("↵ …↵            <div class="bimg">↵"):
SlideItem@6:0", stack: "Error: Template parse errors:↵No provider for Slid…ndroid_asset/www/build/js/app.bundle.js:30622:41)"}message:
"Template parse errors:↵No provider for Slides ("↵  for more info on Angular 2 Components.↵-->↵[ERROR ->]<ion-slide>↵        <div class="bcontent">↵            <div class="bimg">↵"): SlideItem@6:0"

stack: "Error: Template parse errors:↵No provider for Slides ("↵  for more info on Angular 2 Components.↵-->↵[ERROR ->]<ion-slide>↵        <div class="bcontent">↵            <div class="bimg">↵"): SlideItem@6:0↵    at new BaseException (file:///android_asset/www/build/js/app.bundle.js:1760:23)↵    at TemplateParser.parse (file:///android_asset/www/build/js/app.bundle.js:16401:19)↵    at file:///android_asset/www/build/js/app.bundle.js:14643:64↵    at ZoneDelegate.invoke (file:///android_asset/www/build/js/zone.js:323:29)↵    at Object.onInvoke (file:///android_asset/www/build/js/app.bundle.js:30631:41)↵    at ZoneDelegate.invoke (file:///android_asset/www/build/js/zone.js:322:35)↵    at Zone.run (file:///android_asset/www/build/js/zone.js:216:44)↵    at file:///android_asset/www/build/js/zone.js:571:58↵    at ZoneDelegate.invokeTask (file:///android_asset/www/build/js/zone.js:356:38)↵    at Object.onInvokeTask (file:///android_asset/www/build/js/app.bundle.js:30622:41)"__proto__: ErrorconsoleError @ zone.js:461_loop_1 @ zone.js:490drainMicroTaskQueue @ zone.js:494ZoneTask.invoke @ zone.js:426

最佳答案

为什么不起作用

我认为使用Slide和Slides组件的当前设计是不可能的。 ion-slide必须是ion-slides元素的子元素,并且必须能够在同一模板中找到其父幻灯片。

来源:

@Component({
  selector: 'ion-slide',
  template: '<div class="slide-zoom"><ng-content></ng-content></div>',
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
})
export class Slide {

  ele: HTMLElement;

  @Input() zoom: any;

  constructor(
    elementRef: ElementRef,
    @Host() public slides: Slides
  ) {
    this.ele = elementRef.nativeElement;
    this.ele.classList.add('swiper-slide');

    slides.rapidUpdate();
  }

  ngOnDestroy() {
    this.slides.rapidUpdate();
  }
}

您会看到父Slides是必需的,以便当动态添加或销毁Slide时,它可以触发Slides更新。它仅限于使用@Host装饰器的当前模板。

当您尝试在自定义模板中使用ion-slide时,会收到模板错误,因为模板中没有要传递给SlidesSlide对象。

一种部分解决方案

我玩了这个,你可以像下面这样工作:
  • 删除对父slides对象的引用Slides,牺牲了在动态添加/删除幻灯片
  • 时自动更新Slides的能力
  • 将“slide-zoom”类添加到自定义幻灯片。

  • 修改后的slides.ts源:
    @Component({
      selector: 'ion-slide',
      template: '<div class="slide-zoom"><ng-content></ng-content></div>',
      changeDetection: ChangeDetectionStrategy.OnPush,
      encapsulation: ViewEncapsulation.None,
    })
    export class Slide {
    
      ele: HTMLElement;
    
      @Input() zoom: any;
    
      constructor(
        elementRef: ElementRef
      ) {
        this.ele = elementRef.nativeElement;
        this.ele.classList.add('swiper-slide');
      }
    }
    

    和您的幻灯片项目:
    @Component({
      selector: 'slide-item',
      templateUrl: 'slide-item.html',
    })
    export class SlideItem {
    
      @Input()
      imgIdx: number;
    
      constructor(elementRef: ElementRef) {
        console.log("SlideItem::constructor...imgIdx="+this.imgIdx);
        elementRef.nativeElement.classList.add('swiper-slide');
      }
    }
    

    我说这是一个局部解决方案,因为您必须修改离子源,并且因为现在您必须在添加/删除幻灯片时手动调用update Slides更新。

    我确实在进一步修改离子源方面保持了一些进展,以在添加/删除幻灯片(包括您自己的自定义幻灯片容器)上维持自动更新。但是与下面的选项相比,这并不值得。

    部分解决方案2
    Slide的代码非常简单。最好是直接定义自己的组件(而不是包装ion-slide):
    @Component({
      selector: 'slide-item',
      templateURL: 'slite-item.html',
      changeDetection: ChangeDetectionStrategy.OnPush,
      encapsulation: ViewEncapsulation.None,
    })
    export class SlideItem {
    
      ele: HTMLElement;
    
      @Input() zoom: any;
      @Input() imgIdx: number;
    
      constructor(
        elementRef: ElementRef
      ) {
        this.ele = elementRef.nativeElement;
        this.ele.classList.add('swiper-slide');
    
        console.log("SlideItem::constructor...imgIdx="+this.imgIdx)
      }
    }
    

    和模板
    <div class="slide-zoom bcontent">
      <div class="bimg">
        <img data-src="images/slide{{imgIdx}}.jpeg">
      </div>
      <p class="info">My text</p>
    </div>
    

    我称此为部分解决方案还因为您必须维护一些与Ionic镜像的额外源。如果离子载玻片的实现发生变化,则可能必须更新自定义载玻片。

    改进的解决方案

    Here is a SO answer about extending a component。我还没有使它起作用,因为到目前为止,它与Angular无关(ComponentMetaData不再存在),但是我认为这是一种更好的方法。您将使用此装饰器导入和扩展Slide组件。
    export function CustomComponent(annotation: any) {
      return function (target: Function) {
        var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
        var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);
    
        var parentAnnotation = parentAnnotations[0];
        Object.keys(parentAnnotation).forEach(key => {
          if (isPresent(parentAnnotation[key])) {
            annotation[key] = parentAnnotation[key];
          }
        });
        var metadata = new ComponentMetadata(annotation);
    
        Reflect.defineMetadata('annotations', [ metadata ], target);
      }
    }
    

    您的模板将与先前的解决方案相同,但该类将简化为以下内容。
    import { Slide } from 'ionic-angular';
    
    @CustomComponent({
      selector: 'slide-item',
      templateURL: 'slite-item.html'
    })
    export class SlideItem extends Slide {
      @Input() imgIdx: number;
    }
    

    关于ionic2 - 定制组件带 ionic 滑轨,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37979660/

    10-10 02:25