前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Angular 工具篇之Storybook

Angular 工具篇之Storybook

作者头像
阿宝哥
发布2019-11-05 15:50:59
1.9K0
发布2019-11-05 15:50:59
举报
文章被收录于专栏:全栈修仙之路全栈修仙之路

Storybook 是一个 UI 组件的开发环境。它允许你能够浏览一个组件库,查看每个组件的不同状态,以及支持交互式的方式开发和测试组件。

Storybook 在你的应用程序之外运行。这允许你能够独立的开发 UI 组件,你可以提高组件的可重用性、可测试性和开发速度。你可以快速构建,而无需担心应用程序特定的依赖项。

这里有一些可以参考的特色示例,可以了解 Storybook 的工作原理。Storybook 这款工具很强大,它支持很多流行的框架,比如:

  • React
  • React Native
  • Vue
  • Angular
  • Polymer
  • Riot

接下来我们来介绍一下在 Angular 项目中如何使用 storybook。现在我们使用 Angular CLI 来创建一个新的演示项目:

代码语言:javascript
复制
$ ng new angular-storybook-demo
$ cd angular-storybook-demo

这里需要注意的是,本文使用的 CLI 版本为:

代码语言:javascript
复制
     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/

Angular CLI: 6.1.5
Node: 9.11.0
OS: darwin x64
Angular: 6.1.6

接下来安装 @storybook/cli

代码语言:javascript
复制
$ npm i -g @storybook/cli

成功安装以上依赖后,在命令行运行 getstorybook 命令初始化 storybook,该命令会为我们自动生成以下两个 npm script 命令:

代码语言:javascript
复制
"scripts": {
   "storybook": "start-storybook -p 6006",
   "build-storybook": "build-storybook"
}

上面的 storybook 命令,通过 -p 参数用于指定 storybook 的端口。对于基础的 Storybook 配置文件,我们只需简单地告诉 Storybook 从哪里获取 stories。

getstorybook 命令运行后,会自动为我们创建一个 .storybook 目录。然后在该目录下分别创建两个文件:config.js 和 addons.js 文件。顾名思义 config.js 文件就是配置文件,该文件包含以下内容:

代码语言:javascript
复制
import { configure } from '@storybook/angular';

// automatically import all files ending in *.stories.ts
const req = require.context('../src/stories', true, /.stories.ts$/);
function loadStories() {
  req.keys().forEach(filename => req(filename));
}

configure(loadStories, module);

上面的代码支持从 ../src/stories 目录下自动导入以 *.stories.ts 结尾的文件。当然你也可以指定从其它目录加载。通过上面的两个步骤,我们已经完成 Storybook 的初始化工作。此外 getstorybook 命令还会在 src/stories 目录下创建一个 index.stories.ts 文件:

代码语言:javascript
复制
import { storiesOf } from '@storybook/angular';
import { withNotes } from '@storybook/addon-notes';
import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';

import { Welcome, Button } from '@storybook/angular/demo';

storiesOf('Welcome', module).add('to Storybook', () => ({
  component: Welcome,
  props: {},
}));

storiesOf('Button', module)
  .add('with text', () => ({
    component: Button,
    props: {
      text: 'Hello Button',
    },
  }))
  .add(
    'with some emoji',
    withNotes({ text: 'My notes on a button with emojis' })(() => ({
      component: Button,
      props: {
        text: '? ? ? ?',
      },
    }))
  )
  .add(
    'with some emoji and action',
    withNotes({ text: 'My notes on a button with emojis' })(() => ({
      component: Button,
      props: {
        text: '? ? ? ?',
        onClick: action('This was clicked OMG'),
      },
    }))
  );

storiesOf('Another Button', module).add('button with link to another story', () => ({
  component: Button,
  props: {
    text: 'Go to Welcome Story',
    onClick: linkTo('Welcome'),
  },
}));

在上面的示例中,我们通过调用 storiesOf() 方法后返回的对象的 add() 方法来创建故事。其中 add() 方法支持以下参数:

  • storyName: string —— 故事的名称;
  • getStory: IGetStory —— 一个函数对象,调用后返回一个配置对象,包含 component、props 等属性。这里 IGetStory 类型的定义如下:
代码语言:javascript
复制
export type IGetStory = () => {
  props?: ICollection;
  moduleMetadata?: Partial<NgModuleMetadata>;
  component?: any;
  template?: string;
};

通过 @storybook/addon-actions 库中导入的 action 方法,我们能够方便地记录用户触发的自定义事件。此外利用 @storybook/addon-notes 这个库导入的 withNotes() 方法,我们还可以为每个故事添加一个备注信息。

好的,这时一切看起来很顺利,但当我们运行 npm run storybook 命令时,控制台会抛出异常信息。

通过查看 Github 上 Storybook 项目中的 issue,我们发现了异常的原因。即对于 Angular CLI 6 创建的项目需要安装 @storybook/angular@storybook/addons 这两个库 4.0 以上的版本,实际测试发现还得手动安装 @babel/core 这个依赖库。

代码语言:javascript
复制
$ npm i @storybook/angular@4.0.0-alpha.20 @storybook/addons@4.0.0-alpha.20 --save-dev
$ npm i @babel/core@7.0.0 --save-dev

在成功安装完以上依赖后,我们再次运行 npm run storybook 命令,这时打开 http://localhost:6006/ 地址,你将会看到以下内容:

ng-storybook-demo
ng-storybook-demo

以上截图中所演示的 Button 组件的定义如下:

代码语言:javascript
复制
import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'storybook-button-component',
  template: `
      <button (click)="onClick.emit($event);">{{ text }}</button>
  `,
  styles: [
    `
      button {
        border: 1px solid #eee;
        border-radius: 3px;
        background-color: #ffffff;
        cursor: pointer;
        font-size: 15px;
        padding: 3px 10px;
        margin: 10px;
      }
    `,
  ],
})
export default class ButtonComponent {
  @Input() text = '';
  @Output() onClick = new EventEmitter<any>();
}

上面的 ButtonComponent 组件很简单,而在实际的项目中我们的组件可能需要使用 Angular 内置的指令(如 ngIf 或 ngFor)或第三方库的组件。针对这种情况,我们就可以利用配置对象的 moduleMetadata 属性:

代码语言:javascript
复制
import { CommonModule } from '@angular/common';
import { storiesOf } from '@storybook/angular';
import { MyButtonComponent } from '../app/my-button/my-button.component';
import { MyPanelComponent } from '../app/my-panel/my-panel.component';
import { MyDataService } from '../app/my-data/my-data.service';

storiesOf('My Panel', module)
  .add('Default', () => ({
    component: MyPanelComponent,
    moduleMetadata: {
      imports: [CommonModule],
      schemas: [],
      declarations: [MyButtonComponent],
      providers: [MyDataService],
    }
  }));

上面示例中,我们为每个 story 单独设置 moduleMetadata 属性。若每个 story 都使用同样的 Metadata 信息,我们就可以通过 addDecorator() 方法,统一设置 moduleMetadata 属性:

代码语言:javascript
复制
import { CommonModule } from '@angular/common';
import { storiesOf, moduleMetadata } from '@storybook/angular';
import { MyButtonComponent } from '../app/my-button/my-button.component';
import { MyPanelComponent } from '../app/my-panel/my-panel.component';
import { MyDataService } from '../app/my-data/my-data.service';

storiesOf('My Panel', module)
  .addDecorator(
    moduleMetadata({
      imports: [CommonModule],
      schemas: [],
      declarations: [MyButtonComponent],
      providers: [MyDataService],
    })
  )
  .add('Default', () => ({
    component: MyPanelComponent
  }))
  .add('with a title', () => ({
    component: MyPanelComponent,
    props: {
      title: 'Foo',
    }
  }));

以上关于 moduleMetadata 的使用示例来源于 Storybook 官方的 guide-angular 文档,感兴趣的同学可以阅读一下该文档。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018/09/03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档