stenciljs 学习六 组件开发样式指南

组件不是动作,最好使用名词而不是动词,

文件结构

  • 每个文件一个组件。
  • 每个目录一个组件。虽然将类似的组件分组到同一目录中可能是有意义的,但我们发现当每个组件都有自己的目录时,更容易记录组件。
  • 实现(.tsx)和组件的样式应该位于同一目录中。

参考格式

├── card
│ ├── card.ios.scss
│ ├── card.md.scss
│ ├── card.scss
│ ├── card.tsx
│ └── test
│ └── basic
│ ├── e2e.js
│ └── index.html
├── card-content
│ ├── card-content.ios.scss
│ ├── card-content.md.scss
│ ├── card-content.scss
│ └── card-content.tsx
├── card-title
│ ├── card-title.ios.scss
│ ├── card-title.md.scss
│ ├── card-title.scss

命名

  • html 标签
    当创建要在不同项目中使用的组件集合(如@ ionic / core)时,前缀具有重要作用。Web组件没有作用域
    ,因为它们是在网页中全局声明的,这意味着需要“唯一”前缀来防止冲突。前缀还有助于快速识别组件的集合。
    此外,Web组件需要在标记名称中包含“ - ”短划线,因此使用第一部分命名组件是很自然的。
    不建议使用“stencil”作为前缀
  • 命名
    组件不是动作,它们在概念上是“事物”。最好使用名词而不是动词,例如“动画”而不是“动画”。
    “输入”,“制表符”,“导航”,“菜单”是一些例子。
  • 修饰符
    当几个组件相关和/或耦合时,最好共享名称,然后添加不同的修饰符,例如:
<ion-card>
<ion-card-header>
<ion-card-content>

组件(ts 类)

由于类是作用域的,因此组件的ES6类的名称应该没有前缀。没有碰撞的风险。

@Component({
  tag: 'ion-button'
})
export class Button { ... }

@Component({
  tag: 'ion-menu'
})
export class Menu { ... }

typescript

  • 遵循 tslint-ionic-rules
  • 应该内联变量装饰器。
@Prop() name: string;
@Element() el: HTMLElement;
  • 方法装饰器应该是多行的
@Listen('click')
onClick() {
  ...
}
  • 尽可能使用私有变量和方法。
  • 带有Method / Prop / Event / Component装饰器的代码应该有jsdocs

参考实例

@Component({
  tag: 'ion-something',
  styleUrl: 'something.scss',
  styleUrls: {
    ios: 'something.ios.scss',
    md: 'something.md.scss',
    wp: 'something.wp.scss'
  },
  host: {
    theme: 'something'
  }
})
export class Something {

  /**
   * 1. Own Properties
   * Always set the type if a default value has not
   * been set. If a default value is being set, then type
   * is already inferred. List the own properties in
   * alphabetical order. Note that because these properties
   * do not have the @Prop() decorator, they will not be exposed
   * publicly on the host element, but only used internally.
   */
  num: number;
  someText = 'default';

  /**
   * 2. Reference to host HTML element.
   * Inlined decorator
   */
  @Element() el: HTMLElement;

  /**
   * 3. State() variables
   * Inlined decorator, alphabetical order.
   */
  @State() isValidated: boolean;
  @State() status = 0;

  /**
   * 4. Internal props (context and connect)
   * Inlined decorator, alphabetical order.
   */
  @Prop({ context: 'config' }) config: Config;
  @Prop({ connect: 'ion-menu-controller' }) lazyMenuCtrl: Lazy<MenuController>;

  /**
   * 5. Public Property API
   * Inlined decorator, alphabetical order. These are
   * different than "own properties" in that public props
   * are exposed as properties and attributes on the host element.
   * Requires JSDocs for public API documentation.
   */
  @Prop() content: string;
  @Prop() enabled: boolean;
  @Prop() menuId: string;
  @Prop() type = 'overlay';

  /**
   * Prop lifecycle events SHOULD go just behind the Prop they listen to.
   * This makes sense since both statements are strongly connected.
   * - If renaming the instance variable name you must also update the name in @Watch()
   * - Code is easier to follow and maintain.
   */
  @Prop() swipeEnabled = true;

  @Watch('swipeEnabled')
  swipeEnabledChanged(newSwipeEnabled: boolean, oldSwipeEnabled: boolean) {
    this.updateState();
  }

  /**
   * 6. Events section
   * Inlined decorator, alphabetical order.
   * Requires JSDocs for public API documentation.
   */
  @Event() ionClose: EventEmitter;
  @Event() ionDrag: EventEmitter;
  @Event() ionOpen: EventEmitter;

  /**
   * 7. Component lifecycle events
   * Ordered by their natural call order, for example
   * WillLoad should go before DidLoad.
   */
  componentWillLoad() {}
  componentDidLoad() {}
  componentWillEnter() {}
  componentDidEnter() {}
  componentWillLeave() {}
  componentDidLeave() {}
  componentDidUnload() {}

  /**
   * 8. Listeners
   * It is ok to place them in a different location
   * if makes more sense in the context. Recommend
   * starting a listener method with "on".
   * Always use two lines.
   */
  @Listen('click', { enabled: false })
  onClick(ev: UIEvent) {
    console.log('hi!')
  }

  /**
   * 9. Public methods API
   * These methods are exposed on the host element.
   * Always use two lines.
   * Requires JSDocs for public API documentation.
   */
  @Method()
  open() {
    ...
  }

  @Method()
  close() {
    ...
  }

  /**
   * 10. Local methods
   * Internal business logic. These methods cannot be
   * called from the host element.
   */
  prepareAnimation(): Promise<void> {
    ...
  }

  updateState() {
    ...
  }

  /**
   * 11. hostData() function
   * Used to dynamically set host element attributes.
   * Should be placed directly above render()
   */
  hostData() {
    return {
      attribute: 'navigation',
      side: this.isRightSide ? 'right' : 'left',
      type: this.type,
      class: {
        'something-is-animating': this.isAnimating
      }
    };
  }

  /**
   * 12. render() function
   * Always the last one in the class.
   */
  render() {
    return (
      <div class='menu-inner page-inner'>
        <slot></slot>
      </div>
    );
  }
}

参考资料

https://stenciljs.com/docs/style-guide

posted on 2018-09-26 23:21  荣锋亮  阅读(523)  评论(0编辑  收藏  举报

导航