UI工具之Storybook

Overview

今天科普一个有趣的前端开源工具——Stroybook,一个 UI 的可视化容器,可以视作组件库的 wiki。

Storybook is an open source tool for developing UI components in isolation for React, Vue, and Angular. It makes building stunning UIs organized and efficient.

效果如下所示:左侧组件导航;右侧是组件细节,还可以做一些可视化操作。

Story

基本用法

我这里以 VUE 项目为例,简单介绍一下如何在项目里集成 storybook。
官方给出了一个极简的集成方法,只要在根目录的命令行敲下如下一行就行了。(本文结束)

npx -p @storybook/cli sb init --type vue

如上自动化集成方式太过精简,让人不知所措,所以我还是介绍一下手工集成的方式。

添加依赖

先在 devDependencies 里添加@storybook

yarn add @storybook/vue -D

官方文档里还会要求我们添加许多额外的依赖,但是现代的 vue 项目基本是用 vue-cli 脚手架生成的,它已经添加了足够多的 dev 依赖。一般来说是 storybook 的服务已经可以直接启动了的,当然之后显示失败的话也会提示你缺少了某几个依赖,大家可以根据提示添加依赖。 babel-preset-vue是最高频的缺失,可能是这个库好多年没更新了,现在的脚手架已经把它忘了。如果确实没有,就照例添加即可。

yarn add babel-preset-vue -D

创建 config.js 文件

storybook 自然也有配置文件,我们在根目录里建一个.storybook/config.js文件。这里吐槽一下前端的配置文件,实在是太多太多了,根目录里基本全是这类东西了。多到我们组里开发了一年多的小朋友,还没认清所有。

然后在该配置文件里写上如下内容:

// .storybook/config.js
import { configure } from '@storybook/vue';

configure(require.context('../src/components', true, /\.stories\.js$/), module);

配置挺直白的,就是让 storybook 服务找到src/components文件夹下所有.stories.js结尾的文件。这里的每一个 story,都会指向一个 vue component,就把它当做该组件的说明即可。

写一个组件

我们在 src/components 下写一个自己的组件——MyButton.vue

<!- MyButton.vue ->
<template>
    <button class="button-style" @click="onClick">
        <slot></slot>
    </button>
</template>

<script>
export default {
    name: 'my-button',
    methods: {
    onClick() {
      console.log('Hello World!');
    },
  },
}
</script>

<style scoped>
.button-style {
    border-radius: 35% 10%;
    color: #FFF;
    background-color: #00bcd4;
    font-size: 2em;
    line-height: 1.2em;
    margin: 1em 1em;
    cursor: pointer;
}
</style>

组件很简单,就是封装了原生 button tag:加了点样式,并且当点击它时控制台能打出Hello World!

编写 stories

stories 其实可以随意放置,我这里就 follow 项目里 jest 的风格,把 stories 也放在了组件旁边。

src/components
 ├── MyButton.vue
 ├── MyButton.stories.js
 └── MyButton.spec.js

@story/vue,其实就是在 js 文件里写了个无状态的 vue 组件,写法也很简单:引用组件,注册组件,模版封装。结束!

// MyButton.stories.js
import MyButton from './MyButton.vue';

export default { title: 'My-Button' };

export const Component = () => ({
    components: { MyButton },
    template: '<my-button>my button</my-button>'
  });

运行 storybook

Storybook 的服务其实就是 webpack-dev-server,开发时可以热加载,很方便编写 stories 和 vue 组件本身。我们给服务设置个端口,比如 6006,开始运行:

yarn start-storybook -p 6006

不出意外的话,chrome 会自己打开localhost:6006。浏览器如下所示。左侧列出了组件导航,名字就是MyButton.stories.jstitle;右侧是真实组件的样式,点击后,@click事件触发,打印出Hello World!

My Button

如果你想打包成静态资源发布,也很容易:

yarn build-storybook

默认会在根目录会创建一个.out文件夹,里面就是所有静态资源了。

插件系统

主线剧情就到此为止了,但是 storybook 远不止于此,它自带一种叫 addon 的插件系统。(不要问我,addon 和 plugin 的区别)。

我们可以自己写一个简单的 addon, 比如显示组件父亲的 border。
还记得上面的.storybook/config.js文件吗?我们的 addon 就是在里面调用addDecorator,给所有的 story 包一层div,并显示 border:

//.storybook/config.js

import { configure, addDecorator } from '@storybook/vue';

configure(require.context('../src/components', true, /\.stories\.js$/), module);

addDecorator(() => ({
    template:`
      <div style="border:solid;">
        <story/>
      </div>`
  }))

看一下结果,border 显示出来了。

Parent Border

当然上面只是一个示例,现实意义不大,我自己组里开发的时候用到 vuetify,所以一般都会给所有控件包一层<v-app></v-app>,不然可能显现不出 v 组件效果来。

更多的时候,我们是直接集成社区里提供的 addon,比如@storybook/addon-knobs——用于调试 vue 的动态变量。

还是一步一步来,先装个依赖:

yarn add @storybook/addon-knobs -D

接着在.storybook文件夹下创建addons.js文件,并引入依赖

// .storybook/addons.js
import '@storybook/addon-knobs/register';

然后启动服务,看到没?下面多了个Knobs的 tab:

Knobs

之后把 knobs 添加到每一个 story 就可以了。我们稍许修改一下代码,通过storiesOf形式注册 story:

// MyButton.sotries.js
import { storiesOf } from '@storybook/vue';
import { withKnobs, text } from '@storybook/addon-knobs';

import MyButton from './MyButton.vue';

const components = () => ({
  components: { MyButton },
  props: {
    text: {
      default: text('Text', 'my button')
    }
  },
  template: `<MyButton>{{ text }}</MyButton>`
})

storiesOf('My-Button')
.add('components', components)
.addDecorator(withKnobs);

Knobs 根据 story 的 props 生成 mock 数据,并双向绑定对象组件的变量,效果如下:

Knobs Button

小结

这期科普了一个比较有趣的开发工具——Storybook,它可以很方便地帮助我们组织基础 UI 控件。不同的前端开发可以通过很直观的方式复用对方的组件,以期减少冗余代码。此外,我个人觉得编写 Story——可视化组件的最大意义还是在于可测试;我们组之前的组件业务侵入太重,组件本身很难编写单元测试,因此前端的测试覆盖率一直非常低。现在想想,可能是我们本身就写错组件了,组件并非页面,应该能独立展示,不该包含太多业务。我现在在项目里强制加入 Storybook 也是希望能改善之前的困局。

相关

文章同步发布于an-Onion的Github。码字不易,欢迎点赞。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • 安装vue脚手架: Node.js>=8.9没有vue-cli3的先安装一下: 安装完后查看版本: 创建项目: 选...
    helloyoucan阅读 10,686评论 0 7
  • 前言 最近掐指一算发现本月还有篇技术博文没写~,虽然随便拿一篇日常积累的文章,或者把最近重构的一些点拿出来讲都可以...
    临水照影233阅读 11,994评论 0 7
  • 基于Vue的一些资料 内容 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 element★...
    尝了又尝阅读 1,151评论 0 1
  • 原文链接对于一名前端开发者,必须面对的就是组件化开发。我做Angular开发已经有些日子了,也曾为自己的项目开发过...
    Laura_hu阅读 10,318评论 0 4
  • 目录 第一章 介绍第二章 设计机制第三章 JNI类型和数据结构第四章 JNI函数(1)第四章 JNI函数(2)第四...
    骆驼骑士阅读 6,934评论 0 58