vue组件库和组件文档生成
公司现役组件库项目,公共资源或者新老项目切换仓库调整 src 目录结构|--src|-- App.vue|-- main.js|-- packages // 新建此文件夹用来存放组件|-- index.js// 组件入口|-- button.vue// 新增一个button组件,记得带上name|-- icon// 新增一个icon组件,记得带上namepackages/index.js// 所有
公司现役组件库项目,公共资源或者新老项目切换仓库
调整 src 目录结构
|--src
|-- App.vue
|-- main.js
|-- packages // 新建此文件夹用来存放组件
|-- index.js // 组件入口
|-- button.vue // 新增一个button组件,记得带上name
|-- icon // 新增一个icon组件,记得带上name
packages/index.js
// 所有组件的入口
import Button from './button.vue'
import Icon from './icon.vue'
// 全局注册
const install = Vue => {
Vue.component(Button.name, Button)
Vue.component(Icon.name, Icon)
}
// 防止使用者直接以<script></script>方式引入
if (typeof window.Vue !== 'undefined') {
install(Vue) // 直接通过script方式引入组件
}
export default {
install
}
测试组件
import okrUi from './packages/index'
Vue.use(okrUi)
app.vue 直接使用
<okr-icon></okr-icon>
<okt-btn></okt-btn>
接下来就简单了,只要在 packages 中新增组件就可以,在 index.js 中注册即可
关于发布
okr-ui 目录下新建.npmignore
src // 源码不发
public // 公用资源不发
test // 测试代码不发
package.json
"private": false, // 私有的改成false
"version": "0.1.0", // 版本必须每次不一样
测试组件
https://vue-test-utils.vuejs.org/zh/installation/testing-single-file-components-with-karma.html
Karma 是一个启动浏览器运行测试并生成报告的测试运行器。 Mocha 框架撰写测试,同时用 chai 作为断言库。
- 安装依赖
npm install --save-dev @vue/test-utils karma karma-chrome-launcher karma-mocha karma-sourcemap-loader karma-spec-reporter karma-webpack mocha
- 安装 chai
npm install --save-dev karma-chai
官方的配置案例
var webpackConfig = require('./webpack.config.js')
module.exports = function(config) {
config.set({
frameworks: ['mocha'],
files: ['test/**/*.spec.js'], // 匹配所有的spec文件
preprocessors: {
'**/*.spec.js': ['webpack', 'sourcemap']
},
webpack: webpackConfig,
reporters: ['spec'],
browsers: ['ChromeHeadless'] // 打开一个无头的浏览器, 单纯用Chrome会闪动
})
}
组件打包
package.json 新增命令
"lib":"vue-cli-service build --target lib -name okr-ui ./src/packages/index.js"
添加引用入口 package.json 根
- 打包后所有的组件都在 umd.min.js 中
"main":"./dist/okr-ui.umd.min.js"
生成组件文档
使用 vuepress
- 根目录下新建 doc 文件夹
初始化
npm init -y
安装 vuepress
npm i vuepress -D
配置 packages.json 新增 script
"docs:dev":"vuepress dev docs",
"docs:build":"vuepress build docs"
安装依赖工具
cnpm install element-ui highlight.js node-sass sass-loader --save
配置 vue-press
- doc 根目录下新建 docs(固定)
- docs 下新建 README.md(固定)
- docs 下新建 components 用于存放组件描述文件(固定)
- components 下新建 button.md(此处以 button 组件为例)
README.md(内容格式固定)
---
home: true
actionText: 欢迎 →
actionLink: /components/button // 以button为例
features:
- title: okr组件库 // 名称
details: okr组件库,用公共组件存放,新老项目过度组件存放 // 组件库描述
---
button.md
## 按钮组件
运行命令
npm run docs:dev
跑起来的内容是不是很熟悉???但是比较丑是不是?
美化组件库文档界面
- 在 docs 下新建文件夹.vuepress
- 在.vuepress 中新增配置文件 config.js
module.exports = {
title: 'okr-ui', // 网站标题
description: 'okr公共组件库', // 网站描述
dest: './build', // 设置输出目录
port: '8088', // 端口
themeConfig: {
// 主题配置
nav: [
{
text: '主页',
link: '/'
} // 导航条
],
sidebar: {
// 侧边栏配置
'/components/': [
{
collapsable: true, // 默认折叠
children: ['button']
}
]
}
}
}
- 在.vuepress 文件里新建 styles 文件夹,并在 styles 中新建文件 palette.styl(固定)
$codeBgColor
=
#fafafa
$accentColor=#3eaf7c
$textColor=#2c3e50
$borderColor=#eaecef
$arrowBgColor=#ccc
$badgeTipColor=#42b983
$badgeWarningColor=darken(#ffe564,35%)
$badgeErrorColor=#da5961
.content
pre {
margin: 0 !important;
}
.theme-default-content:not(.custom) {
max-width: 1000px !important;
}
- .vuepress 目录下新建 enhanceApp.js(固定)入口定义文件
enhanceApp.js
import Vue from 'vue'
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import hljs from 'highlight.js'
import 'highlight.js/styles/googlecode.css'
// 自定义指令
Vue.directive('highlight', function (el) {
let blocks = el.querySelectorAll('pre code')
blocks.forEach(block => {
hljs.highlightBlock(block)
})
})
export default ({ Vue, options, router, siteData }) => {
Vue.use(Element)
// 变更20210310,解决build异常问题提
Vue.mixin({
mounted() {
import('okr-ui')
.then(function (m) {
Vue.use(m.default)
})
.then(() => {
import('okr-ui/dist/okr-ui.css') // 组件库样式
})
}
})
}
- okr-ui 没有安装怎么引用?
- 去 okr-ui 根目录执行
npm link
此命令是将该项目链接到全局 - 然后在 docs 的文件中
npm link okr-ui
此命令是将全局注册的 okr-ui 拉进来进行使用 - 经过以上两步就能免发布使用了
- 去 okr-ui 根目录执行
测试
- .vuepress 下新建 components,此文件加下皆为全局组件
- 新建 button 文件夹/button 文件夹/test.vue
- 在 docs 根目录下的 conponents 的 button.md 进行测试
button.md
<button-test></button-test>
这样就会去.vuepress 组件中找到 button/test.vue 组件(固定写法)
运行命令 npm run docs:dev
- corejs 丢失 npm i core-js@2
- okr-ui 找不到???注意你的组件库中 package.json 中 main 属性有没有指定文件?
测试真实组件库中的组件
- 还记得刚才在 doc 文档库中已经引入了 okr-ui 了对吧,已经引用了吧?直接测试组件吧
- 比如我们在 okr-ui 中写了 okr-btn 这个按钮组件吧?
docs/.vuepress/components/button/test.vue
<okt-btn></okt-btn>
看页面是不是有了?
<template>
<div>
<okt-btn></okt-btn>
</div>
</template>
实现类似于 element-ui 组件库的文档体验
在 .vuepress 下 components 中新建组件文档展示模板 demo-block.vue
<template>
<div
class="demo-block"
:class="[blockClass, { hover: hovering }]"
@mouseenter="hovering = true"
@mouseleave="hovering = false"
ref="demoBlockContainer"
>
<div style="padding:24px">
<slot name="source"></slot>
</div>
<div class="meta" ref="meta">
<div class="description" v-if="$slots.default">
<slot></slot>
</div>
<div class="highlight">
<slot name="highlight"></slot>
</div>
</div>
<div class="demo-block-control" ref="control" @click="isExpanded = !isExpanded">
<transition name="arrow-slide">
<i :class="[iconClass, { hovering: hovering }]"></i>
</transition>
<transition name="text-slide">
<span v-show="hovering">{{ controlText }}</span>
</transition>
</div>
</div>
</template>
<style lang="scss">
.demo-block {
border: solid 1px dashed;
border-radius: 3px;
transition: 0.2s;
&.hover {
box-shadow: 0 0 8px 0 rgba(232, 237, 250, 0.6), 0 2px 4px 0 rgba(232, 237, 250, 0.5);
}
code {
font-family: Menlo, Monaco, Consolas, Courier, monospace;
}
.demo-button {
float: right;
}
.source {
padding: 24px;
}
.meta {
background-color: #fafafa;
border-top: solid 1px #eaeefb;
overflow: hidden;
height: 0;
transition: height 0.2s;
}
.description {
padding: 20px;
box-sizing: border-box;
border: solid 1px #ebebeb;
border-radius: 3px;
font-size: 14px;
line-height: 22px;
color: #666;
word-break: break-word;
margin: 10px;
background-color: #fff;
}
p {
margin: 0;
line-height: 26px;
}
::v-deep code {
color: #5e6d82;
background-color: #e6effb;
margin: 0 4px;
display: inline-block;
padding: 1px 5px;
font-size: 12px;
border-radius: 3px;
height: 18px;
line-height: 18px;
}
}
.highlight {
pre {
margin: 0;
code {
color: black !important;
}
}
code.hljs {
margin: 0;
border: none;
max-height: none;
border-radius: 0;
line-height: 1.8;
color: black;
&::before {
content: none;
}
}
}
.demo-block-control {
border-top: solid 1px #eaeefb;
height: 44px;
box-sizing: border-box;
background-color: #fff;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
text-align: center;
margin-top: -1px;
color: #d3dce6;
cursor: pointer;
&.is-fixed {
position: fixed;
bottom: 0;
width: 868px;
}
i {
font-size: 16px;
line-height: 44px;
transition: 0.3s;
&.hovering {
transform: translate(-40px);
}
}
> span {
position: absolute;
transform: translate(-30px);
font-size: 14px;
line-height: 44px;
transition: 0.3s;
display: inline-block;
}
&:hover {
color: #409eff;
background-color: #f9fafc;
}
& .text-slide-enter,
& .text-slide-leave-active {
opacity: 0;
transform: translate(10px);
}
.control-button {
line-height: 26px;
position: absolute;
top: 0;
right: 0;
font-size: 14px;
padding-left: 5px;
padding-right: 25px;
}
}
</style>
<script type="text/babel">
export default {
name: 'DemoBlock',
data() {
return {
hovering: false,
isExpanded: false,
fixedControl: false,
scrollParent: null,
langConfig: {
'hide-text': '隐藏代码',
'show-text': '显示代码',
'button-text': '在线运行',
'tooltip-text': '前往jsfiddle.net 运行此示例'
}
}
},
props: {
jsfiddle: Object,
default() {
return {}
}
},
methods: {
scrollHandler() {
const { top, bottom, left } = this.$refs.meta.getBoundingClientRect()
this.fixedControl =
bottom > document.documentElement.clientHeight && top + 44 <= document.documentElement.clientHeight
},
removeScrollHandler() {
this.scrollParent && this.scrollParent.removeEventListener('scroll', this.scrollHandler)
}
},
computed: {
lang() {
return this.$route.path.split('/')[1]
},
blockClass() {
return `demo-${this.lang} demo-${this.$router.currentRoute.path.split('/').pop()}`
},
iconClass() {
return this.isExpanded ? 'el-icon-caret-top' : 'el-icon-caret-bottom'
},
controlText() {
return this.isExpanded ? this.langConfig['hide-text'] : this.langConfig['show-text']
},
codeArea() {
return this.$refs['demoBlockContainer'].getElementsByClassName('meta')[0]
},
codeAreaHeight() {
if (this.$refs['demoBlockContainer'].getElementsByClassName('description').length > 0) {
return (
this.$refs['demoBlockContainer'].getElementsByClassName('description')[0].clientHeight +
this.$refs['demoBlockContainer'].getElementsByClassName('highlight')[0].clientHeight +
20
)
}
return this.$refs['demoBlockContainer'].getElementsByClassName('highlight')[0].clientHeight
}
},
watch: {
isExpanded(val) {
this.codeArea.style.height = val ? `${this.codeAreaHeight + 1}px` : '0'
if (!val) {
this.fixedControl = false
this.$refs.control.style.left = '0'
this.removeScrollHandler()
return
}
setTimeout(() => {
this.scrollParent = document.querySelector('.page-component__scroll > .el-scrollbar__warp')
this.scrollParent && this.scrollParent.addEventListener('scroll', this.scrollHandler)
this.scrollHandler()
}, 200)
}
},
mounted() {
console.log(this.$refs.demoBlockContainer)
this.$nextTick(() => {
console.log(this.$refs['demoBlockContainer'])
let highlight = this.$refs['demoBlockContainer'].getElementsByClassName('highlight')[0]
if (this.$refs['demoBlockContainer'].getElementsByClassName('description').lenght === 0) {
highlight.style.width = '100%'
highlight.borderRight = 'none'
}
})
},
beforeDestroy() {
this.removeScrollHandler()
}
}
</script>
在 docs/components 下
使用模板/插槽
重新运行代码,是不是体验很棒??
代码地址
git@github.com:sunhailiang/publish-ui.git
更多推荐
所有评论(0)