0%

color-ui笔记(二)

完善和部署项目

编写文档首页

程序员不懂设计,直接从一些设计网站上获取素材。比如 dribbble

主要做了以下内容

  • 使用 cssgradient.io 这个网站制作了渐变背景和标题字的镂空渐变效果
  • 使用 iconfont 引入必要的 svg icon
  • 使用 clip-path 画圆弧
  • 使用媒体查询实现响应式页面

实现的效果如下

image-20210521163115666

使用 markdown 编写文档内容

自制 Vite 插件

首先需要支持 import markdown 文件,新建 vite.config.ts

1
2
3
4
5
6
import { md } from './plugins/md'
import fs from 'fs'
import { baseParse } from '@vue/compiler-core'
export default {
plugins: [md()]
}

新建 plugins 目录和 md.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import path from 'path'
import fs from 'fs'
import marked from 'marked'
const mdToJs = str => {
const content = JSON.stringify(marked(str))
return `export default ${content}`
}

export function md() {
return {
configureServer: [ // 用于开发
async ({ app }) => {
app.use(async (ctx, next) => { // koa
if (ctx.path.endsWith('.md')) {
ctx.type = 'js'
const filePath = path.join(process.cwd(), ctx.path)
ctx.body = mdToJs(fs.readFileSync(filePath).toString())
} else {
await next()
}
})
},
],
transforms: [{ // 用于 rollup // 插件
test: context => context.path.endsWith('.md'),
transform: ({ code }) => mdToJs(code)
}]
}
}

引入 github-markdown-css 渲染 markdown 解析后的样式,然后在需要用的地方加上类名 markdown-body

创建 Demo 组件

使用 vue-loader 的 Custom Blocks 获取源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// vite.config.ts
export default {
...
vueCustomBlockTransforms: {
demo: (options) => {
const { path } = options
const file = fs.readFileSync(path).toString()
const parsed = baseParse(file).children.find(n => n.tag === 'demo')
const title = parsed.children[0].content
const main = file.split(parsed.loc.source).join('').trim()
return `export default function (Component) {
Component.__sourceCode = ${
JSON.stringify(main)
}
Component.__sourceCodeTitle = ${JSON.stringify(title)}
}`.trim()
}
}
};

支持代码高亮

首先安装 prismjs,然后选择一个喜欢的配色

1
2
3
import 'prismjs';
import 'prismjs/themes/prism-tomorrow.css';
const Prism = (window as any).Prism;

代码部分

1
<pre class="language-html" v-html="html" />

这里的 html 通过计算获得

1
2
3
4
5
6
7
const html = computed(() => {
return Prism.highlight(
props.component.__sourceCode,
Prism.languages.html,
"html"
);
});

支持代码展开折叠的动画

给代码部分套上一层 div ,根据折叠与否来选择赋予这层 div demo-code的高度

1
2
3
4
5
<div class="demo-code-wrapper" :style="{height:computedHeight + 'px'}">
<div class="demo-code" ref="demoCode">
<pre class="language-html" v-html="html"/>
</div>
</div>

并设置样式

1
2
3
4
.demo-code-wrapper {
transition: all .2s;
overflow: hidden;
}

TS部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let codeHeight = 0;
const codeVisible = ref(false);
const computedHeight = ref(0);
const toggleCode = () => {
codeVisible.value = !codeVisible.value;
computedHeight.value = codeVisible.value ? codeHeight : 0;
};

onMounted(() => watchEffect(() => {
if (demoCode.value) {
const {
height
} = demoCode.value.getBoundingClientRect();
codeHeight = height;
}
}));

解决部署 GitHub 失败的问题

在 vite.config.ts 中设置

1
2
3
4
export default {
base:'./',
assetsDir:'assets' //默认目录为_assets,github 不支持
}

rollup 编译库文件

新建 src/lib/index.ts

1
2
3
4
5
import "./color.scss";
export {default as Switch} from './Switch';
export {default as Button} from './Button';
export {default as Tabs} from './Tabs';
export {default as Dialog} from './Dialog';

根目录创建 rollup.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import esbuild from 'rollup-plugin-esbuild';
import vue from 'rollup-plugin-vue';
import less from 'rollup-plugin-scss';
import dartSass from 'sass';
import {terser} from 'rollup-plugin-terser';
export default {
input: 'src/lib/index.ts',
output: [
{
globals: {
vue: 'Vue',
},
name: 'color-ui',
file: 'package/lib/color-ui.js',
format: 'umd',
plugins: [terser()],
}],
plugins: [
less({include: /\.scss$/, less: dartSass}),
esbuild({
include: /\.[jt]s$/,
minify: process.env.NODE_ENV === 'production',
target: 'es2015',
}),
vue({
include: /\.vue$/,
}),
],
};

rollup 编译

1
rollup -c 

npm 发布

切换到 npm 源

1
yrm use npm 

更新 package.json

1
2
3
4
5
6
{
"name": "@lichen404/color-ui",
"version": "0.0.1",
"files": ["package/lib/*"],
"main": "package/lib/color-ui.js"
}

执行 npm publish

完善项目

添加路由切换过渡效果

vue-router 4 版本对路由过渡的动效写法做了更新,旧的写法是不能生效的

1
2
3
4
5
<router-view v-slot="{Component}">
<transition name="router-switch" appear mode="out-in">
<component :is="Component"/>
</transition>
</router-view>

完善侧边导航栏组件

侧边导航栏在移动端自动隐藏并添加过渡动画

1
2
3
4
5
6
7
8
9
.sidebar-wrapper {
@media (max-width: 720px) {
position: fixed;
top: 54px;
left: 0;
transition:transform .2s;
transform: translateX(-100%);
}
}

参照 Vue 文档实现移动端展开侧边栏后,添加全局的遮罩,点击遮罩后关闭侧边栏

1
2
3
4
5
6
7
8
9
10
.aside-open {
> .aside-mask {
display:block;
width:100vw;
height:100vh;
position:fixed;
top:0;
left:0;
}
}
1
2
3
4
<div class="sidebar-wrapper" :class="{'aside-open':menuVisible}">
<div class="aside-mask" @click="closeMenu"/>
...
</div>

同时在路由切换时也会将菜单关闭

1
2
3
4
5
6
7
8
// App.vue
setup() {
const menuVisible = ref(false);
provide('menuVisible', menuVisible);
router.afterEach(() => {
menuVisible.value = false;
});
}

组件支持配置主题色

组件库改为使用 Vue.use 的方式引入,这样的话我们可以写一个 install 的方法。引入组件的同时设置全局的 css 变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default {
install: (app, options) => {
app.component('Tabs', Tabs);
app.component('Tab', Tab);
app.component('Dialog', Dialog);
app.component('Button', Button);
app.component('Switch', Switch);
app.config.globalProperties.$dialog = openDialog;
const {colors} = options;
if (colors) {
for (const color in colors) {
if (colors.hasOwnProperty(color)) {
document.documentElement.style.setProperty(`--color-${color}`, colors[color]);
}
}
}
}
};

使用

1
2
3
4
5
6
7
8
9
10
app.use(colorUI, {
colors: {
// 配置不同主题的 rgb 色值,支持以下五种属性
primary: '25,128,255',
danger: '255,71,87',
success: '70,201,58',
dark: '30,30,30',
warning: '255,186,0'
}
})
1
2
3
4
<Button color="success">Success</Button>
<Button color="danger">Danger</Button>
<Button color="warning">Warning</Button>
<Button color="dark">Dark</Button>

然后在每个组件中定义好每个颜色的样式,SCSS 可以减少很多重复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
&.filled {
@mixin style($color){
background: rgb(var($color));
&:hover {
box-shadow: 0 8px 24px -8px rgb(var($color));
}
}
&.color-primary {
@include style(--color-primary)
}
&.color-danger {
@include style(--color-danger)
}
&.color-success {
@include style(--color-success)
}
&.color-dark {
@include style(--color-dark)
}
&.color-light {
@include style(--color-light)
}
&.color-warning {
@include style(--color-warning)
}
}

添加 Dialog 组件的弹出关闭动画

Dialog 组件的弹出关闭的动画要设置在 v-if 元素的子元素上

1
2
3
4
5
6
7
8
9
10
<transition name="dialog">
<div v-if="visible">
<div class="color-dialog-overlay" @click="onClickOverlay"></div>
<div class="color-dialog-wrapper">
<div class="color-dialog">
...
</div>
</div>
</div>
</transition>

样式要写成下面这样,否则过渡效果不生效或者关闭的时候没有过渡效果,很玄学。

1
2
3
4
5
6
7
8
9
10
11
.dialog-enter-from .color-dialog, .dialog-leave-to .color-dialog {
transform: scale(.8);
opacity: 0;
}
// 如果写成 .dialog-leave-active .color-dialog,.dialog-enter-active .color-dialog,则样式不生效
.dialog-leave-active, .dialog-enter-active {
transition: all .2s;
}
.color-dialog {
transition:all .2s;
}