自定义指令

通常情况下,drunk开发应用时只需要考虑数据与页面状态的维护,而DOM的更新通过drunk内置的指令去操控。但是当我们开发一些组件需要对DOM进行一些个性化操作时,内置的指令未必能满足我们的需求,所以drunk提供了自定义指令的功能,来达到对DOM的控制和指令的封装。

注册指令

指令名称必须由小写字母,可使用'-'连接。

@drunk.binding('lazy-load')
class LazyLoad extends drunk.Binding {

  element: HTMLElement;
  viewModel: drunk.Component;

  init() {

  }
  update(newSrc: string, oldSrc: any) {

  }
  release() {

  }
}

声明一个LazyLoad的类,继承drunk.Binding类并使用drunk.binding装饰器注册一个lazy-load的指令名字,这样就可以在html里面使用drunk-lazy-load这个指令了(指令前缀需要根据drunk.config.prefix的值)。

继承drunk.Binding类后,可以访问element(绑定的元素)和viewModel(绑定的viewModel)两个成员属性,这样可以很方便的对两者进行操作。

生命周期

  • init() 初始化时会调用的方法
  • update(newValue, oldValue) 数据更新时调用的方法
  • release() 绑定销毁时调用的方法

这3个方法都不时必须的,可以根据业务逻辑来实现。

lazy-load指令示例

lazy-load是一个把页面中图片的加载方式设置成只有在可见的情况才去加载的逻辑功能指令,使用方法:

<img drunk-lazy-load="product.picture" />

初始化

// ....
  private currentSrc: string;
  private onScroll: Function;

  init() {
    this.onScroll = () => {
      this.visible = this.checkVisibleInPage();

      if (!this.visible || !this.currentSrc) {
        return;
      }

      this.element.src = this.currentSrc;
      window.removeEventListener('scroll', this.onScroll);
    };

    window.addEventListener('scroll', this.onScroll);
    this.onScroll(); // 第一次也要检测图片是否可见
  }

  private checkVisibleInPage(): boolean {
    // 在这检测图片是否可见
  }
// ...

初始化的时候,先注册一个scroll事件,页面滚动的时候检测图片是否在可见区域,如果可见,则取消scroll事件监听并设置图片的src。

数据更新

product.picture值更新时,更新currentSrc字段,并根据图片可见状态来控制是否显示。

// ...
  update(newSrc: string) {
    this.currentSrc = newSrc;
    if (this.visible) {
      this.element.src = this.currentSrc;
    }
  }
// ...

指令销毁

取消scroll事件监听,并对某些成员属性设置为空。

// ...
  release() {
    window.removeEventListener('scroll', this.onScroll);
    this.currentSrc = this.onScroll = this.visible = null;
  }
// ...

完整代码

// TypeScript
@drunk.binding('lazy-load')
class LazyLoad extends drunk.Binding {

  element: HTMLElement;
  viewModel: drunk.Component;

  private currentSrc: string;
  private onScroll: Function;

  init() {
    this.onScroll = () => {
      this.visible = this.checkVisibleInPage();

      if (!this.visible || !this.currentSrc) {
        return;
      }

      this.element.src = this.currentSrc;
      window.removeEventListener('scroll', this.onScroll);
    };

    window.addEventListener('scroll', this.onScroll);
    this.onScroll(); // 第一次也要检测图片是否可见
  }

  private checkVisibleInPage(): boolean {
    // 在这检测图片是否可见
  }

  update(newSrc: string, oldSrc: any) {
    this.currentSrc = newSrc;
    if (this.visible) {
      this.element.src = this.currentSrc;
    }
  }

  release() {
    window.removeEventListener('scroll', this.onScroll);
    this.currentSrc = this.onScroll = this.visible = null;
  }
}
// es5
drunk.Binding.register('lazy-load', {

  currentSrc: null,
  visible: false,

  init: function () {
    this.onScroll = function () {
      this.visible = this.checkVisibleInPage();

      if (!this.visible || !this.currentSrc) {
        return;
      }

      this.element.src = this.currentSrc;
      window.removeEventListener('scroll', this.onScroll);
    }.bind(this);

    window.addEventListener('scroll', this.onScroll);
    this.onScroll(); // 第一次也要检测图片是否可见
  },

  checkVisibleInPage: function () {
    // 在这检测图片是否可见
  },

  update: function (newSrc) {
    this.currentSrc = newSrc;
    if (this.visible) {
      this.element.src = this.currentSrc;
    }
  },

  release: function () {
    window.removeEventListener('scroll', this.onScroll);
    this.currentSrc = this.onScroll = this.visible = null;
  }
})

results matching ""

    No results matching ""