组件库系列三:编写组件库文档
文章目录vuepress介绍创建文档工程配置运行指令vuepress浏览器自动更新下载插件和依赖npm/yarn linkdocs文件夹.vuepress文件夹可收缩代码块效果展示vuepress介绍Vue 驱动的静态网站生成器以 Markdown 为中心的项目结构,以最少的配置帮助你专注于写作。享受 Vue + webpack 的开发体验,可以在 Markdown 中使用 Vue 组件,又可以使
vuepress介绍
- Vue 驱动的静态网站生成器
- 以 Markdown 为中心的项目结构,以最少的配置帮助你专注于写作。
- 享受 Vue + webpack 的开发体验,可以在 Markdown 中使用 Vue 组件,又可以使用 Vue 来开发自定义主题。
- VuePress 会为每个页面预渲染生成静态的 HTML,同时,每个页面被加载的时候,将作为 SPA 运行。
创建文档工程
另起一个目录,创建por-ui-doc文件夹
yarn init -y // 创建package.json
yarn add vuepress -D // 安装vuepress框架
配置运行指令
在package.json中
"scripts":{
"dev": "vuepress dev docs",
"build": "vuepress build docs"
}
vuepress浏览器自动更新
本地开发模式运行Vuepress 1.x 时,浏览器不能自动更新
`"dev": "vuepress dev docs"`
改为
`"dev": "vuepress dev docs --temp .temp"`
下载插件和依赖
element-ui、highlight.js(代码高亮)、sass
element-ui、highlight.js 可以直接下载
yarn add element-ui highlight.js -D
node-sass和sass-loader直接下载会有版本过高问题,版本匹配:5.0.0配合10.1.1
yarn add sass-loader@10.1.1 -D
yarn add node-sass@5.0.0 -D
npm/yarn link
由于组件库项目和文档项目之间存在依赖,可以使用yarn link将一个项目链接到另一个项目。
项目A中需要使用项目B时,可以使用yarn link或npm link将B引入到A。
PS:link本身是软链接,yarn link是将资源存在yarn的内存中,相当于建立了一个通道。
# 进入B项目,创建链接对象
yarn link
# 进入A项目,建立B项目的链接
yarn link B
# 解除链接
yarn unlink B
注意:
-
A和B均为package.json文件中的“name”对应的值,一般为文件夹名称
-
项目B是我们自己开发封装的组件,引入前需要先完成打包
-
使用完成后使用unlink解除链接
docs文件夹
在根目录下创建docs文件夹
在该文件夹下,创建README.md文件,两个的名称都不能改
home: true // 是否首页
actionText: 欢迎 → // 首页文本
actionLink: /components/button
features:
- title: por-ui官方文档
details: por-ui官方文档
在该文件夹下,创建components文件夹
里面放每个组件都有一个md文件,例如button.md
注意文件中需要有标题,不然显示的是链接形式
# 按钮组件
或者设置title
---
title: Button
---
查看效果
运行yarn run dev
.vuepress文件夹
- 创建.vuepress文件夹
在docs文件夹下创建.vuepress文件夹,在里面创建config.js,用来配置导航等文档基本结构信息,修改后重启项目才生效
module.exports = {
title: 'por-ui', // 设置网站标题
description: 'ui 库', //描述
dest: './build', // 设置输出目录
port: 1234, //端口
markdown: {
anchor: { permalink: false },
},
themeConfig: { //主题配置
nav: [{
text: '主页',
link: '/'
}, // 导航条
],
// 为以下路由添加侧边栏
sidebar: [{
title: '介绍',
collapsable: true, // 可折叠
children: ["/introduce/"]
},
{
title: '组件',
collapsable: false,
children: [
// 按钮组件
"/components/button"
]
}
]
}
}
- 去掉默认样式
在.vuepress文件夹下创建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;
}
- enhanceApp.js入口文件
在页面里要用上自己的组件,要在.vuepress文件夹下创建一个enhanceApp.js文件作为入口(启动当前的vuepress,这个文件就是当前项目的一个入口),框架规定的,名字不能改
import Vue from 'vue';
import Element from 'element-ui'; // 引入elementUi,因为要用到elementui里的结构
import 'element-ui/lib/theme-chalk/index.css'
import hljs from 'highlight.js' //引入高亮js
import 'highlight.js/styles/googlecode.css' //引入高亮js样式文件
//正常情况引入porui要根据目录../../一层一层去引入的,
//这里为了方便在porui文件夹根目录下npm link一下,把porui添加到本地全局,
//注意要以package.json里的name名字为准
//然后在porui-doc文件夹下npm link por-ui一下,把本地全局的porui引入到文档项目下
//成功之后在porui-doc下的nodemodule下就能看到这个porui文件夹了(实际上是个链接,每次porui文件夹改动了,这里的也会改动)
//这样就可以以下面一行的方式引用了
import porUi from 'por-ui' // 要编写对应的文档的包
import 'por-ui/dist/por-ui.css'
// 写了一个高亮指令,可以去解析pre code里面的标签,添加高亮
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);
Vue.use(porUi) // 设置为全局组件
}
-
components文件夹
在.vuepress文件夹下,创建components文件夹,放置为引入的poly-ui写一些测试代码组件,只要是这个目录下的都是全局组件,例如:在里面创建button文件夹,里面放button1.vue,那么buton1.vue就是button的测试
// button1.vue <template> <div> <por-button>默认按钮</por-button> <por-button type='primary'>主要按钮</por-button> <por-button type='warning'>警告按钮</por-button> <por-button type='danger'>危险按钮</por-button> <por-button type='success'>成功按钮</por-button> <por-button type='info'>信息按钮</por-button> </div> </template> <script> export default {} </script>
然后button1.vue就可以在docs目录下的components内的所有.md文件内使用了
#按钮组件 //button是.vuepress内components下文件夹button的名字,-后面的button1是button文件夹下button1.vue的名字 //找到的就是button1.vue,它会把这个文件渲染到文档上 <button-button1></button-button1>。
-
core-js报错
如果遇到core-js报错,就yarn add core-js@2重新装一下
可收缩代码块
创建可收缩代码块
在.vuepress内components下文件夹下创建demo-block可收缩代码块,开发像elementui那种查看例子时,可以展开代码的功能
<template>
<!-- 主要用到了三个插槽 -->
<div
class="demo-block"
:class="[blockClass, { 'hover': hovering }]"
@mouseenter="hovering = true"
@mouseleave="hovering = false"
>
<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" v-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 #ebebeb;
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;
}
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.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;
position: relative;
&.is-fixed {
position: fixed;
bottom: 0;
width: 868px;
}
i {
font-size: 16px;
line-height: 44px;
transition: 0.3s;
&.hovering {
transform: translateX(-40px);
}
}
> span {
position: absolute;
transform: translateX(-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: translateX(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: 'demo-block',
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.$el.getElementsByClassName('meta')[0]
},
codeAreaHeight () {
if (this.$el.getElementsByClassName('description').length > 0) {
return this.$el.getElementsByClassName('description')[0].clientHeight +
this.$el.getElementsByClassName('highlight')[0].clientHeight + 20
}
return this.$el.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__wrap')
this.scrollParent && this.scrollParent.addEventListener('scroll', this.scrollHandler)
this.scrollHandler()
}, 200)
}
},
mounted () {
this.$nextTick(() => {
let highlight = this.$el.getElementsByClassName('highlight')[0]
if (this.$el.getElementsByClassName('description').length === 0) {
highlight.style.width = '100%'
highlight.borderRight = 'none'
}
})
},
beforeDestroy () {
this.removeScrollHandler()
}
};
</script>
在组件.md文件中使用
# Button组件
常用的操作按钮。
## 基础用法
基础的按钮用法。
<demo-block>
::: slot source
<button-button1></button-button1>
:::
使用type属性来定义 Button 的样式。
::: slot highlight
```html
<div>
<por-button>默认按钮</por-button>
<por-button type="primary">主要按钮</por-button>
<por-button type="success">成功按钮</por-button>
<por-button type="info">信息按钮</por-button>
<por-button type="warning">警告按钮</por-button>
<por-button type="danger">危险按钮</por-button>
</div>
```
:::
</demo-block>
到这里就基本上完成了一个文档的功能
效果展示
更多推荐
所有评论(0)