前言
这几天在学习 Vue 3,通过实操一个 UI 组件库项目来学习 Vue 3,使用了全新的 Vite 2 进行构建,使用 TypeScript
编写,用到了 Vue 3 的 script setup
语法糖、Composition API
、WatchEffect
等等。
最后通过将组件库发布到 npm,顺便学习了发布和管理 npm 包的流程,目前项目阶段性完成,对过程中遇到的有些东西进行一个总结。
可以点击 Desn-UI 官网 进行预览。项目仓库
搭建项目
Vite 2 的速度
体验了 Vite 以提供原生 ESM 方式启动开发服务器,速度堪称闪电,怪不得 Logo 带了一个闪电图标。启动一个开发服务器从来没有超过过 2 秒,修改的视图更新也几乎同时响应在页面里,大大提高了开发体验。
搭建项目
使用 yarn create vite 项目名 --template vue-ts
或 npm create vite@latest 项目名 --template vue-ts
,等待几秒就完成了模版下载。
这时候进入创建的目录,yarn install
安装依赖包,安装完成就可以运行 yarn dev
启动开发服务器了。
得到一个地址,浏览器打开它。会得到一个全新的欢迎页 Hello Vue 3 + TypeScript + Vite
,这时候就可以进行开发了。
Vite 2 + Vue 3 项目结构
|
|
相比 Vue 2,这个目录结构是简洁了太多了,对于我这种强迫症,目录清晰简洁真的太舒服了。这时候就可以开始开发自己的项目了。
script setup
不得不说,Vue 3 这个语法糖真的好用。写起来简洁,在模版使用不用 return,组件引入就能使用,大大节省了重复的 export default
和 return
。并且 <script setup>
中的代码会在 每次组件实例被创建的时候执行。
简单示例
不过这里使用 script setup
的话,有些东西的写法就会和写在 setup
函数不同了。
props 和 emits
不使用语法糖的话,props
是写在 export default
里面,而 emits
写在 setup
函数里,需要从 context
使用,并且最后需要 return
出来才可以在模版中使用。
而使用 script setup 语法糖的话,就特别简单了。
可以看到,代码行数少了不少,括号也少了不少,整体看起来会清晰很多。
ref
响应式状态需要明确使用响应式 APIs 来创建。和从 setup()
函数中返回值一样,ref
值在模板中使用的时候会自动解包,以下示例中模版会随着 count
的变化而更新。
useSlots 和 useAttrs
在 <script setup>
使用 slots
和 attrs
,可以分别用 useSlots
和 useAttrs
两个辅助函数:
useSlots
和 useAttrs
是真实的运行时函数,它会返回与 setupContext.slots
和 setupContext.attrs
等价的值,同样也能在普通的组合式 API 中使用。
生命周期钩子
在 <script setup>
中使用生命周期钩子,需要稍稍修改一下:
除了 create
系列的钩子不能使用之外(下面会说),其余的钩子使用方法相同。需要先从 vue
引入,然后在前面添加 on
并且改为 Camel-Case 命名,传入一个 callback
,就会在对应生命周期执行 callback
。
script setup 总结
setup
执行时尚未创建组件实例,所以在setup
中不能使用this
- 由于
setup
是围绕beforeCreate
和created
生命周期钩子运行的,因此无需显式定义它们。换句话说,应该在这些钩子中编写的任何代码都应直接在setup
函数中编写。
Teleport
这可是个好东西,以前在做各种 DOM 操作,CSS 样式的时候,不可避免的会遇到某些冲突,查来查去发现需要改一大堆东西才行,但是由于别的原因可能不能去改。
那可得试试 Teleport 这个组件了。简单的来说他就是一个传送门,可以把它包裹的内容传送到指定的 DOM 节点下,看下面示例:
这个 .Dialog
节点,最终渲染的时候会出现在 body
下面,也就是 to
属性指定的 DOM 节点内。
实用场景一般会是在弹窗组件中。或者有些嵌套的组件被外层影响,并且是临时展示之类的,就可以使用这个传送门来解决。
将 markdown 文件 .md
展示在页面中并且高亮
在搭建组件库官网的过程中,因为需要将 markdown 转换为 html,并且提供代码块高亮展示,这时候就遇到了一些问题。
- 因为不能把每个想用 markdown 写的文档页面单独写为组件,那样太不程序员了。
- 但如果只用一个模版展示,其他的用
slot
插槽呢?这又有一个问题,必须得用 html 来编写文档,这样也太不程序员了。
如果我可以用 markdown 来写文档,用单个 vue 组件来读取这些
.md
文件,那就太棒了!于是我就跳进了这个坑里。
期间尝试各种插件,各种高亮引入等等,失败了一天多,这个过程就不赘述了,大抵就是从早到晚搜搜搜,试试试,最后也没弄出来的难过心情。
然后在翻看 Vite 2 文档时,看到了这个:静态资源处理
这里 Vite 官方为静态资源提供了多种导入形式,其中有一项: 将资源引入为字符串,那这个就是我想要的了,于是就开始了尝试。
实现思路
在组件内,将 markdown.md 引入为字符串。打印出来会发现,它把 markdown.md 里面的 markdown 格式内容完全打印了出来。
拿到了 markdown 字符串之后就可以把它转换为 html 字符串进行渲染了,然后添加高亮等等都可以。
最终实现
尝试完了之后发现其实还是有点麻烦,最终我采用了动态组件的实现方式,用到了 vite-plugin-md
这个插件,并且通过 Vue Router
实现了单个展示组件展示任意 markdown 文档。
首先创建一个用来展示 markdown 的页面组件。这个组件里面有一个动态组件 <component :is="" />
。
is 什么呢?那就在 script 里面引入 .md 文件,下面是完整的实现。
- router.ts
|
|
- components/markdown.vue
|
|
这样就可以实现用户在访问
/doc/*
的路径时,自动展示src/markdown
内名字为*.md
的 markdown 文件内容。不需要一个文件一个组件,也不需要新建 markdown 就要去别的地方加一点东西了。
主要原理就是:
- 在 router.ts 注册路由为
/doc/*
的所有路由都展示 Markdown 组件,这个路由添加了一个动态参数,可以将/doc/
后面的参数传给 Markdown 组件。 - 在 Markdown 组件使用
watchEffect
对全局路由变化进行监听,当匹配到路由前缀为/doc/
的路由变化时,动态 importsrc/markdown
内的同名.md
的内容。 - 由于我安装了
vite-plugin-md
插件,它会自动把.md
引入为 vue 组件,这时就可以使用 vue 的动态组件来动态展示内容了。
这里有几个点需要注意:
- 组件内匹配到路由前缀后,如未找到对应文件,则需要跳转到 404 页面;
- 动态组件必须有一个不会重复的
:key
,否则视图可能不会正确地更新;
代码高亮
至于代码部分高亮,我使用了 highlight.js
, 在 main.ts
内注册了一个全局指令 highlight
,之后在我需要高亮的代码容器添加一个 v-highlight
即可实现代码高亮。
- highlight.js 这里我使用了单语言引入,你可以查看官方文档进行其他方式引入
|
|
- main.ts
- Markdown.vue 刚才的例子里,直接添加一个指令即可
总结
通过这次小项目实践,大概熟悉了 Vite + Vue 3 开发的基本流程,在写代码的过程中进行了多次封装,对于封装的时机和封装的思路、熟练度都有了提高,对于一份代码,优化也不会毫无头绪了。
实操使用了 Vite 2.7.2
、Vue 3.2.25
、包括其他 typescript
等等依赖也都用了最新的,还有代码高亮和 markdown 展示的实现逻辑,包括 npm 发包等等过程中,自己研究、查资料填平了不少的坑,技能提升和成就感还是蛮高的。
可以点击 Desn-UI 官网 进行预览。项目仓库
继续加油!
(完)