前端业务组件库怎么样做到极致?
#vue #unit-test #npm
jerrywu001
创建时间:2023-09-05 06:02:16
文章开始先介绍一下 react-toastify,一个不单单是toast的组件,它集成了很多交互细节和增强功能,着实惊艳到了我,不禁想一个toast组件竟然能卷到如此地址~~
处于好奇,参照它写了个vue3的版本(欢迎star,欢迎提bug):
项目采用我之前做的自动npm发包模板搭建
集成了很多功能,比如
- vitest单元测试(包含testing-library)
- 原生npm mono repo
- 支持esm/cjs打包
- github action workflow,自动跑test, eslint,...; npm publish、github create relase;..
- 内置vitepress
- 内置playground
- ....
更多详见文章
在线案例截图
在线文档截图
我为每个usage都配备了CodeSandpack,它是一个在线code playground,支持vue/react/angular/...
vitest ui截图
组件介绍
组件实现流程
其中绿色圆形区块表示组件
功能案例介绍(重要看点)
本文只挑几个展示一下:
- POSITION
<script> import { toast } from 'vue3-toastify'; import 'vue3-toastify/dist/index.css'; export default { name: "App", setup() { const notify = () => { toast("Default Notification !"); toast.success("Success Notification !", { position: toast.POSITION.TOP_CENTER, }); toast.error("Error Notification !", { position: toast.POSITION.TOP_LEFT, }); toast.warn("Warning Notification !", { position: toast.POSITION.BOTTOM_LEFT, }); toast.info("Info Notification !", { position: toast.POSITION.BOTTOM_CENTER, }); toast("Custom Style Notification with css class!", { position: toast.POSITION.BOTTOM_RIGHT, className: 'foo-bar', }); }; return { notify }; } }; </script> <template> <div> <button @click="notify">Notify !</button> </div> </template> <style> .foo-bar { color: #f00; } </style>
- theme & icon
<template> <button @click="notify">show toast</button> </template> <script> import { defineComponent } from 'vue'; import { toast } from 'vue3-toastify'; import 'vue3-toastify/dist/index.css'; export default defineComponent({ setup() { const notify = () => { toast("Default Notification !"); toast.success("AUTO, 跟随系统主题(light/dark)!", { theme: toast.THEME.AUTO, }); toast.info("light!", { theme: toast.THEME.LIGHT, position: toast.POSITION.BOTTOM_RIGHT, }); toast.warning("dark!", { theme: toast.THEME.DARK, position: toast.POSITION.TOP_LEFT, }); toast.error("Colored!", { theme: toast.THEME.COLORED, position: toast.POSITION.TOP_LEFT, }); }; return { notify, }; }, }); </script> <style> .count { color: red; } </style>
- toast.promise
<script> import { toast } from 'vue3-toastify'; import 'vue3-toastify/dist/index.css'; export default { name: "App", setup() { const displayPromise = () => { const resolveWithSomeData = new Promise((resolve, reject) => setTimeout(() => resolve({ message: 'world' }), 3000)); toast.promise( resolveWithSomeData, { pending: { render() { return "I'm loading"; }, // other options icon: false, }, success: { render(res) { return 'resolve with data: ' + res.data.message; }, // other options icon: '🟢', }, error: { render(err) { // When the promise reject, data will contains the error return h('div', 'Err: ' + err.data.message); // return 'Err: ' + err.data.message; }, // render: 'just text', // render: h('div', 'error'), }, }, { position: toast.POSITION.BOTTOM_RIGHT, } ); }; return { displayPromise }; } }; </script> <template> <div> <button @click="displayPromise">display promise</button> </div> </template>
- update toast
<template> <button @click="notify">show toast</button> <button @click="update">update icon</button> <button @click="updateContent">update content</button> <p>更多查看:https://vue3-toastify.js-bridge.com/usage/update-toast.html</p> </template> <script> import { defineComponent, ref, h } from 'vue'; import { toast } from 'vue3-toastify'; import 'vue3-toastify/dist/index.css'; export default defineComponent({ setup() { const toastId = ref(''); const notify = () => toastId.value = toast('Hello', { autoClose: false, position: toast.POSITION.BOTTOM_RIGHT, }); const update = () => toast.update(toastId.value, { type: toast.TYPE.INFO, autoClose: 5000, }); const updateContent = () => toast.update( toastId.value, { // render: 'New content', // render: SomeVNode, // ToastContent<T> render: (props) => { return h('div', 'new content'); }, // ToastContentProps<T> type: toast.TYPE.INFO, autoClose: 5000, }, // ToastOptions ); return { notify, update, updateContent, }; }, }); </script> <style> .count { color: red; } </style>
- Define a custom enter and exit animation
<template> <button @click="notify">show toast</button> </template> <script> import { defineComponent } from 'vue'; import { toast } from 'vue3-toastify'; import 'vue3-toastify/dist/index.css'; import 'animate.css'; export default defineComponent({ setup() { const customAnimation = { enter: "animate__animated animate__lightSpeedInRight", exit: "animate__animated animate__lightSpeedOutRight", // appendPosition: true, }; // as CSSTransitionProps // TIPS !!!!!!!!!!!!!!!! // if add prop --> appendPosition: true // - className to be: "animate__animated animate__lightSpeedInRight--top-right" // - enter or exit animation will not trigger, // - because there has no className "animate__lightSpeedInRight--top-right" const notify = () => { toast('Wow so easy !', { transition: customAnimation, }); }; return { notify, }; }, }); </script>
- Pause toast timer when the window loses focus
<template> <button @click="notify">show toast</button> <p>打开toast后,点击非“iframe”区域</p> </template> <script> import { defineComponent } from 'vue'; import { toast } from 'vue3-toastify'; import 'vue3-toastify/dist/index.css'; export default defineComponent({ setup() { const notify = () => { toast('default enable'); toast('disable pauseOnFocusLoss', { pauseOnFocusLoss: false, }); }; return { notify, }; }, }); </script> <style> .count { color: red; } </style>