基于vue-cli4的ui组件库,上篇:如何做一个初步的组件。下篇:编写说明文档及页面优化。接上篇,开工。
GitHub源码地址:https://github.com/sq-github/sq-ui
GitHub预览地址:https://sq-github.github.io/sq-ui/dist
五、添加markdown说明文本
1、删除app.vue原有的app.vue内容,及其他一些项目创建时引用的不需要的组件。修改后app.vue如下:
<template>
<div id="app">
<router-view />
</div>
</template>

2、因为文档是用markdown写的,需要项目能识别markdown组件。

npm i vue-markdown-loader -D
3、修改vue.config.js 需要能识别md文件。
const path = require('path')
module.exports = {
// 修改 pages 入口
pages: {
index: {
entry: 'examples/main.js', // 入口
template: 'public/index.html', // 模板
filename: 'index.html' // 输出文件
}
},
parallel: false,
// 扩展 webpack 配置
chainWebpack: config => {
// @ 默认指向 src 目录,这里要改成 examples
// 另外也可以新增一个 ~ 指向 packages
config.resolve.alias
.set('@', path.resolve('examples'))
.set('~', path.resolve('packages')) // 把 packages 和 examples 加入编译,因为新增的文件默认是不被 webpack 处理的
config.module
.rule('js')
.include.add(/packages/)
.end()
.include.add(/examples/)
.end()
.use('babel')
.loader('babel-loader')
.tap(options => {
// 修改它的选项...
return options
})
config.module
.rule('md')
.test(/\.md/)
.use('vue-loader')
.loader('vue-loader')
.end()
.use('vue-markdown-loader')
.loader('vue-markdown-loader/lib/markdown-compiler')
.options({
raw: true
})
}
}

4、创建文档的目录及文件。

在 examples 目录下创建 docs 文件夹,在docs文件夹下创建 test1.md,文件内容如下

## tip

:::tip
这是一个 tip。这是一个 tip。这是一个 tip。这是一个 tip。这是一个 tip。这是一个 tip。
::: ## warning :::warning
这是一个 warning,**这是一个 warning,**。
这是一个 warning。
这是一个 warning,这是一个 warning,这是一个 warning,这是一个 warning。
::: ## demo :::demo 这是一个 demo。这是一个 demo。这是一个 demo。这是一个 demo。这是一个 demo。这是一个 demo。这是一个 demo。这是一个 demo。 ```html
<sq-button></sq-button>
``` :::

将 test1.md 添加进路由进行测试

在router/index.js中添加

 {
path: '/test1',
name: 'test1',
component: () => import(/* webpackChunkName: "about" */ '../docs/test1.md')
}

重新运行测试:如果没有报错,页面能正确显示 test1.md 内的文本,这一步就算成功了。

5、接下来安装其他的markdown插件
mpm i markdown-it markdown-it-container -S
6、再次修改vue.config.js文件
const path = require('path')
const md = require('markdown-it')() // 引入markdown-it
module.exports = {
// 修改 pages 入口
pages: {
index: {
entry: 'examples/main.js', // 入口
template: 'public/index.html', // 模板
filename: 'index.html' // 输出文件
}
},
parallel: false,
// 扩展 webpack 配置
chainWebpack: config => {
// @ 默认指向 src 目录,这里要改成 examples
// 另外也可以新增一个 ~ 指向 packages
config.resolve.alias
.set('@', path.resolve('examples'))
.set('~', path.resolve('packages')) // 把 packages 和 examples 加入编译,因为新增的文件默认是不被 webpack 处理的
config.module
.rule('js')
.include.add(/packages/)
.end()
.include.add(/examples/)
.end()
.use('babel')
.loader('babel-loader')
.tap(options => {
// 修改它的选项...
return options
})
config.module
.rule('md')
.test(/\.md/)
.use('vue-loader')
.loader('vue-loader')
.end()
.use('vue-markdown-loader')
.loader('vue-markdown-loader/lib/markdown-compiler')
.options({
raw: true,
preventExtract: true, // 这个加载器将自动从html令牌内容中提取脚本和样式标签
// 定义处理规则
preprocess: (MarkdownIt, source) => {
// 对于代码块去除v - pre, 添加高亮样式;
const defaultRender = md.renderer.rules.fence
MarkdownIt.renderer.rules.fence = (
tokens,
idx,
options,
env,
self
) => {
const token = tokens[idx]
// 判断该 fence 是否在 :::demo 内
const prevToken = tokens[idx - 1]
const isInDemoContainer =
prevToken &&
prevToken.nesting === 1 &&
prevToken.info.trim().match(/^demo\s*(.*)$/)
if (token.info === 'html' && isInDemoContainer) {
return `<template slot="highlight"><pre v-pre><code class="html">${md.utils.escapeHtml(
token.content
)}</code></pre></template>`
}
return defaultRender(tokens, idx, options, env, self)
}
return source
},
use: [
// :::demo ****
//
// :::
// 匹配:::后面的内容 nesting == 1,说明:::demo 后面有内容
// m为数组,m[1]表示 ****
[
require('markdown-it-container'),
'demo',
{
validate: function(params) {
return params.trim().match(/^demo\s*(.*)$/)
}, render: function(tokens, idx) {
const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/)
if (tokens[idx].nesting === 1) {
//
const description = m && m.length > 1 ? m[1] : '' // 获取正则捕获组中的描述内容,即::: demo xxx中的xxx
const content =
tokens[idx + 1].type === 'fence'
? tokens[idx + 1].content
: '' return `<demo-block>
<div slot="source">${content}</div>
${description ? `<div>${md.render(description)}</div>` : ''}
`
}
return '</demo-block>'
}
}
],
[require('markdown-it-container'), 'tip'],
[require('markdown-it-container'), 'warning']
]
})
}
}
7、重新运行 会有一个报错 说没有<demo-block>组件,接下来只需要添加这个组件即可。在 examples/components 下添加 DemoBlock.vue,内容如下:
<template>
<div class="demo-block" :class="blockClass">
<!-- 源码运行 -->
<div class="source">
<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"
:class="{ 'is-fixed': fixedControl }"
@click="isExpanded = !isExpanded"
>
<transition name="text-slide">
<span>{{ controlText }}</span>
</transition>
</div>
</div>
</template>
<script>
export default {
data() {
return {
isExpanded: false,
fixedControl: false,
scrollParent: null
}
}, computed: {
lang() {
return this.$route.path.split('/')[1]
}, blockClass() {
return `demo-${this.lang} demo-${this.$router.currentRoute.path
.split('/')
.pop()}`
},
controlText() {
return this.isExpanded ? '隐藏代码' : '显示代码'
},
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'
console.log(this.$el.getElementsByClassName('description').length)
console.log(this.$el.getElementsByClassName('highlight'))
console.log(this.codeAreaHeight)
if (!val) {
this.fixedControl = false
this.$refs.control.style.left = '0'
}
}
}
}
</script>
<style lang="scss">
.demo-block {
width: 60%;
padding: 8px 16px;
margin: auto;
margin-top: 10px;
border-left: solid 5px#fc297f;
background-color: #f8d1db;
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);
}
.meta {
margin-top: 10px;
background-color: #fafafa;
border-radius: 8px;
overflow: hidden;
height: 0;
transition: height 0.2s;
} .description {
box-sizing: border-box;
border-radius: 3px;
font-size: 14px;
line-height: 22px;
color: #666;
word-break: break-word;
margin: 10px;
background-color: #fff;
p {
width: 100%;
}
}
.demo-block-control {
border-top: solid 1px #eaeefb;
height: 44px;
box-sizing: border-box;
background-color: #fff;
border-radius: 8px;
text-align: center;
margin-top: 10px;
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: #fc297f;
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>
然后在main.js中引用组件
import DemoBlock from './components/DemoBlock.vue'
Vue.component('DemoBlock', DemoBlock)
8、现在应该能看到demo组件的效果了,后面接下来需要添加tip和warning的样式
添加一个公共scss文件,在assets下新建common.scss文件
html,
body {
margin: 0;
padding: 0;
height: 100%;
background-color: #17171d;
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB',
'Microsoft YaHei', SimSun, sans-serif;
font-weight: 400;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent; &.is-component {
overflow: hidden;
}
} #app {
height: 100%;
&.is-component {
overflow-y: hidden;
.main-cnt {
padding: 0;
margin-top: 0;
height: 100%;
min-height: auto;
}
.headerWrapper {
position: fixed;
width: 100%;
left: 0;
top: 0;
z-index: 1500;
.container {
padding: 0;
}
}
}
} a {
color: #409eff;
text-decoration: none;
} code {
padding: 0 4px;
border: 1px solid #eaeefb;
border-radius: 4px;
} button,
input,
select,
textarea {
font-family: inherit;
font-size: inherit;
line-height: inherit;
color: inherit;
} .hljs {
line-height: 20px;
font-family: Menlo, Monaco, Consolas, Courier, monospace;
font-size: 12px;
padding: 10px 24px 18px 24px;
border: solid 1px #eaeefb;
border-radius: 4px;
-webkit-font-smoothing: auto;
} .main-cnt {
margin-top: -80px;
padding: 80px 0 340px;
box-sizing: border-box;
min-height: 100%;
} #app {
h2 {
font-size: 28px;
color: #fc297f;
margin: 0;
}
h3 {
font-size: 22px;
}
h2,
h3,
h4,
h5 {
width: 60%;
margin: auto;
margin-top: 10px;
font-weight: normal;
color: #fc297f;
a {
display: none;
}
&:hover a {
opacity: 0.4;
}
} p {
width: 60%;
margin: auto;
padding: 10px;
font-size: 16px;
color: #d3aec2;
line-height: 30px;
} .tip {
width: 60%;
margin: auto;
margin-top: 10px;
padding: 8px 16px;
background-color: #ecf8ff;
border-radius: 4px;
border-left: #1b9ae4 5px solid;
p {
width: 100%;
}
code {
background-color: rgb(255, 255, 255);
color: #445368;
}
} .warning {
width: 60%;
margin: auto;
margin-top: 10px;
padding: 8px 16px;
background-color: #fff6f7;
border-radius: 4px;
border-left: rgb(252, 122, 2) 5px solid;
p {
width: 100%;
}
code {
background-color: rgba(255, 255, 255, 0.7);
color: #445368;
}
}
}
@media (max-width: 1140px) {
.container,
.page-container {
width: 100%;
}
} @media (max-width: 768px) {
.container,
.page-container {
padding: 0 20px;
} #app.is-component .headerWrapper .container {
padding: 0 12px;
}
}
在main.js引入
import './assets/common.scss' // 公共样式
9、现在效果应该都出来了,可以给代码添加高亮,使其更漂亮。
npm i highlight.js -S
再在main.js中添加如下配置,然后代码就能语法高亮了,perfact!
import hljs from 'highlight.js'
import 'highlight.js/styles/monokai-sublime.css' router.afterEach(() => {
Vue.nextTick(() => {
const blocks = document.querySelectorAll('pre code:not(.hljs)')
Array.prototype.forEach.call(blocks, hljs.highlightBlock)
})
})
10、最后有个小问题,如果有eslint检查的话,在md文件中添加vue模板文件时会报错,比如下面这种:
:::demo 这里贴出的是源码,刷新可重播。

```html
<template>
<div>
<div>测试</div>
</div>
</template> <script></script>
<style></style>
``` :::
解决方法是:在跟目录添加一个.eslintignore文件,目录和内容如下:

*.sh
node_modules
lib
coverage
*.md
*.scss
*.woff
*.ttf
aui-web
build
六、现在说明文件格式已经弄好了,类似下面这种效果,最后一步就是将路由和左侧的导航菜单弄好。

1、添加路由配置文件routerCon.json

[
{
"name": "test",
"groups": [
{
"groupName": "测试组件",
"list": [
{
"path": "/test1",
"title": "测试1"
},
{
"path": "/test2",
"title": "测试2"
}
]
}
]
}
]
2、修改路由的index.js文件,倒数第二行的路由重定向 redirect ,可以自己定义。

// export default router
import Vue from 'vue'
import Router from 'vue-router' import navConfig from './routerCon' Vue.use(Router)
const docsRoutefun = navConfig => {
const route = []
navConfig.forEach(item => {
if (item.groups) {
item.groups.forEach(group => {
group.list.forEach(nav => {
route.push({
path: nav.path,
name: nav.name,
component: r =>
require.ensure([], () => r(require(`@/docs${nav.path}.md`)))
})
})
})
} else {
route.push({
path: item.path,
name: item.name,
component: r =>
require.ensure([], () => r(require(`@/docs${item.path}.md`)))
})
}
})
return route
}
const docsRoute = docsRoutefun(navConfig)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [{ path: '/', redirect: '/test1' }, ...docsRoute]
})
3、添加左侧菜单组件menuCom.vue

<template>
<div id="app">
<div class="main">
<!-- sidebar -->
<div class="sidebar">
<menuCom :data="navsData"></menuCom>
</div>
<div class="view page-container">
<router-view></router-view>
</div>
</div>
</div>
</template>
<script>
import menuCom from './components/menuCom'
import navsData from './router/routerCon.json'
export default {
components: {
menuCom
},
data() {
return {
navsData
}
}
}
</script>
<style lang="scss">
html,
body {
margin: 0;
height: 100%;
background-color: #17171d;
}
.header {
top: 0;
height: 60px;
background-color: #121217;
}
.footer {
position: absolute;
height: 60px;
background-color: antiquewhite;
width: 100%;
}
.footer {
bottom: 0;
}
.main {
background-color: #17171d;
position: absolute;
bottom: 0;
top: 60px;
width: 100%;
overflow: hidden;
}
.sidebar,
.view {
overflow: auto;
}
.sidebar {
float: left;
height: 100%;
width: 200px;
padding: 10px 0 10px 0;
border-right: #000000 3px solid;
}
.view {
padding: 0 0 80px 0;
float: left;
height: calc(100% - 50px);
width: calc(100% - 203px);
overflow: auto;
}
</style>
最后:赶紧npm run lib 加 npm publish,引用看看效果吧,别忘了修改发布版本哟。
总算码完了,期间看了一些博文和源码,有些文章不太完整,踩了一些坑。现在自己从头总结,感觉算是尽力在这篇中将详细的步骤和源码贴出来了,主要是想分享交流,互相避坑,如有不足,希望大家交流指正。
如果需要完成开头图片那种效果,页头布局、logo以及其他的组件都放在github的源码里面了。如果觉得还有趣,不妨star一下,十分感谢。
参考项目链接:
https://github.com/xiaolannuoyi/yuan-ui
https://segmentfault.com/a/1190000018310478
https://blog.csdn.net/qq_31126175/article/details/100527322?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158788190919725247652639%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.57644%2522%257D&request_id=158788190919725247652639&biz_id=0&utm_source=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-7

手把手做一个基于vue-cli的组件库(下篇)的更多相关文章

  1. 手把手做一个基于vue-cli的组件库(上篇)

    基于vue-cli4的ui组件库,先贴个最终效果吧,步骤有点多,准备分上下篇,上篇:如何做一个初步的组件.下篇:编写说明文档及页面优化.开工. GitHub源码地址:https://github.co ...

  2. 基于Vue的npm组件库

    前言(*❦ω❦) 思维导图可能有点高糊,有点太大了,项目和导图文件放到github或giteee上,这个思维导图也是我文章的架构,思维导图是用FeHelper插件生成的,这个是一款开源chrome插件 ...

  3. 使用webpack4搭建一个基于Vue的组件库

    组内负责的几个项目都有一些一样的公共组件,所以就着手搭建了个公共组件开发脚手架,第一次开发 library,所以是参考着 iview 的配置来搭建的.记录如何使用webpack4搭建一个library ...

  4. 新建一个基于vue.js+Mint UI的项目

    上篇文章里面讲到如何新建一个基于vue,js的项目(详细文章请戳用Vue创建一个新的项目). 该项目如果需要组件等都需要自己去写,今天就学习一下如何新建一个基于vue.js+Mint UI的项目,直接 ...

  5. 一个基于vue的时钟

    前两天写了一个基于vue的小钟表,给大家分享一下. 其中时针和分针使用的是图片,结合transform制作:表盘刻度是通过transform和transformOrigin配合画的:外面的弧形框框,啊 ...

  6. 基于vue项目的组件中导入mui框架初始化滑动等效果时需移除严格模式的问题

    基于vue项目的组件中导入mui框架初始化滑动等效果时,控制台报错:Uncaught TypeError: 'caller', 'callee', and 'arguments' properties ...

  7. 扩展一个boot的插件—tooltip&做一个基于boot的表达验证

    在线演示 本地下载 (代码太多请查看原文) 加班,加班加班,我爱加班··· 我已经疯了,哦也. 这次发一个刚接触boot的时候用boot做的表单验证,我们扩展一下tooltip的插件,让他可以换颜色. ...

  8. 一个基于vue的仪表盘demo

    最近写了一个基于vue的仪表盘,其中 主要是和 transform 相关的 css 用的比较多.给大家分享一下,喜欢的话点个赞呗?嘿嘿 截图如下: 实际效果查看地址:https://jhcan333. ...

  9. 一个基于swoole的作业调度组件,已经实现了redis和rabitmq队列消息存储。

    https://github.com/kcloze/swoole-jobs 一个基于swoole的作业调度组件,已经实现了redis和rabitmq队列消息存储.参考资料:swoole https:/ ...

随机推荐

  1. 你真的理解了java单例模式吗?讲别人都忽略的细节!

    前言:老刘这篇文章敢做保证,java的单例模式讲的比大多数的技术博客都要好,讲述别人技术博客都没有的细节!!! 1 java单例模式 直接讲实现单例模式的两种方法:懒汉式和饿汉式,单例模式的概念自己上 ...

  2. 多个table表不同数据切换 easyui中

    未处理  有效   无效  切换显示 1.加载页面时将 未处理 ,无效  有效的数据分别查到,给对应的table赋值 <%--easyui 的 tab标签栏--%><div id=& ...

  3. mysql多个TimeStamp设置

    mysql多个TimeStamp设置 2012-11-02 12:58  轩脉刃  阅读(39590)  评论(3)  编辑  收藏 timestamp设置默认值是Default CURRENT_TI ...

  4. 设计模式——从HttpServletRequestWrapper了解装饰者模式

    从一个业务开始 最近项目上紧急需要,为了应付一个不知道啥的安全检测,我们要给系统追加防XSS注入的功能,这里有经验的JavaWeb开发就会想到,用过滤器或者基于项目框架的拦截器来做,但是顺着这个思路下 ...

  5. QPushButton

    QPushButton 什么是QPushButton? 构造函数 常用属性和方法 QPushButton 什么是QPushButton? QPushButton是一个按键类. class Q_GUI_ ...

  6. [新手教程]申请https泛域名解析

    前置准备 教程开始,我们默认相信小伙伴们对基本的域名购买及解析有了一定的认识和实践 一个正常的域名 一台公网服务器 域名解析操作 如:现在我们要设置frps的泛域名解析 设置二级域名 frp.xx.c ...

  7. 关于c语言的知识点不足的地方

    在最近的一次c语言考试之前,自己根据老师说的会出原题的卷子的总结 关于代码的自动对齐,dev c++ CTRL+shift+A/a 关于运算顺序的csdn上有,常考的有/ %等 上地址 https:/ ...

  8. idea多模块启动

    2018版本的idea 原文链接http://zhhll.icu/2020/04/07/idea/idea%E4%B9%8B%E5%A4%9A%E6%A8%A1%E5%9D%97%E5%90%AF%E ...

  9. MATLAB在读取excel文件是发生错误,怎么解决?

    转载:https://blog.csdn.net/qq_38712026/article/details/78783422?utm_source=blogxgwz4

  10. 【剑指 Offer】05.替换空格

    题目描述 请实现一个函数,把字符串 s 中的每个空格替换成"%20". 示例 1: 输入:s = "We are happy." 输出:"We%20a ...