1
web 技术分享| 基于 vue3 实现自己的组件库,第一章:Message 组件
作者:anyRTC开发者
- 2022 年 6 月 08 日
本文字数:4220 字
阅读完需:约 14 分钟
大家好今天将开始新的系列基于vue3实现自己的组件库,本文默认你会安装和创建 vue3 项目,如果不会请参考vue官网,废话不多说开始实现本章的目标 Message 组件;
创建组件库工程目录
vair是组件库的名字(名字大家随意)
安装项目依赖
npm install less -Dnpm install less-loader -D
复制代码
template
<template> <div class='v-message'> <div v-for='(config, index) in messageList' :key='config.id' :ref= 'el => { if (el) contentList[index] = el}' :class='["message-item", config.customClass, config.type, { center: config.center }]'> <i :class='[config.iconClass, "icon"]'></i> <p class='content'>{{ config.message }}</p> <i class='close iconfont icon-guanbi1' @click='close(config)' v-if='config.showClose'></i> </div> </div></template>
复制代码
script
import { ref, defineComponent } from 'vue';
export default defineComponent({ name: 'message', setup () { // 消息列表 const messageList = ref([]); // ref列表 const contentList = ref([]);
const message = (options) => { computedConfig(options); }
const success = (options) => { computedConfig(options, 'success'); }
const warning = (options) => { computedConfig(options, 'warning'); }
const error = (options) => { computedConfig(options, 'error'); }
const computedConfig = (options, type) => { var option = options || {}; type && (option.type = type); const config = { type: option.type || 'prompt', // 没传消息类型就是默认消息 message: option.message || '', iconClass: option.iconClass || computedIconClass(type || 'prompt'), customClass: option.customClass, duration: option.duration >= 0? option.duration : 3000, showClose: option.showClose, center: option.center, onClose: option.onClose, id: Math.floor(new Date()) }; messageList.value.push(config); // 如果延时不等于0,就要设置消失时间 if (config.duration !== 0) { setTimeout(() => { contentList.value[0].className += ' messageHide'; setTimeout(() => { messageList.value.splice(0, 1); }, 200); }, config.duration + messageList.value.length * 100); } };
const computedIconClass = (type) => { switch (type) { case 'prompt': return 'iconfont icon-tishi'; case 'success': return 'iconfont icon-success'; case 'warning': return 'iconfont icon-jinggao--'; case 'error': return 'iconfont icon-cuowu'; } };
const close = (config) => { const index = messageList.value.findIndex(item => item.id === config.id); if (index !== -1) { contentList.value[index].className += ' messageHide'; setTimeout(() => { messageList.value.splice(index, 1); config.onClose && config.onClose(config); }, 200); } }
return { messageList, contentList, close, message, success, warning, error } }});
复制代码
css
<style lang='less' scoped>@import url('../../assets/css/animation.css');.v-message { position: fixed; z-index: 99999; top: 50px; left: 0; right: 0; margin: auto; width: 380px; .message-item { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; box-sizing: border-box; border-radius: 6px; padding: 14px; overflow: hidden; border: 1px solid transparent; animation: messageShow .5s; animation-fill-mode: forwards; .content { font-size: 12px; line-height: 20px; flex: 1; } .close { cursor: pointer; &:hover { color: #6b6b6b; } } i { font-size: 18px; } .icon { margin-right: 14px; } } .center { justify-content: center; .content { flex: 0 1 auto; } } .messageHide { animation: messageHide .2s linear; animation-fill-mode: forwards; } .prompt { border: 1px solid #ebeef5; background-color: #edf2fc; .content, i { color: #909399; } } .success { background-color: #f0f9eb; border-color: #e1f3d8; .content, i { color: #67C23A; } } .warning { background-color: #fdf6ec; border-color: #faecd8; .content, i { color: #E6A23C; } } .error { background-color: #fef0f0; border-color: #fde2e2; .content, i { color: #F56C6C; } }}</style>
复制代码
animation.css
这个文件的功能就是定义组件所需的动画
@keyframes messageShow { 0% { transform: translateY(-50px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; }}
@keyframes messageHide { 0% { transform: translateY(0); opacity: 1; } 100% { transform: translateY(-50px); opacity: 0; }}
复制代码
编写 message.js
import Message from "./Message.vue";import { createApp } from "vue";
const createMessage = function () { const div = document.createElement("div"); div.id = "v-message"; document.body.appendChild(div); return createApp(Message).mount("#v-message");};
export default createMessage();
复制代码
编写 vair 出口 index.js
后续这个文件会引入很多组件
// Message 消息提示import Message from './components/Message/message.js';
const Vair = function(Vue) { // Message 消息提示 Vue.config.globalProperties.$message = Message;}
export default Vair;
复制代码
使用组件库
在main.js中引入
import { createApp } from 'vue';import App from './App.vue';import Vair from './libs/vair/index.js';
const app = createApp(App);app.use(Vair).mount('#app');
复制代码
App.vue 中调用
<template> <div class='message'> <p class='button' @click='addMsg("success")'>成功</p> <p class='button' @click='addMsg("warning")'>警告</p> <p class='button' @click='addMsg("error")'>错误</p> <p class='button' @click='addMsg("close")'>可关闭</p> <p class='button' @click='addMsg("center")'>文字居中</p> </div></template>
<script>import { getCurrentInstance, defineComponent } from 'vue';export default defineComponent({ setup () { const app = getCurrentInstance();
const addMsg = (type) => { if (type === 'success') { app.ctx.$message.success({ message: '这是一条成功消息' }); } if (type === 'warning') { app.ctx.$message.warning({ message: '这是一条警告消息' }); }
if (type === 'error') { app.ctx.$message.error({ message: '这是一条错误消息' }); }
if (type === 'close') { app.ctx.$message.success({ message: '这是一条可关闭的消息', showClose: true, onClose: (config) => { console.log(config) }, }); }
if (type === 'center') { app.ctx.$message.success({ message: '这是一条居中的消息', center: true }); } };
return { addMsg } }})</script>
<style lang='less' scoped>.message { width: 500px; display: flex; justify-content: space-between;}.button { width: 76px; line-height: 34px; border-radius: 4px; color: #fff; background-color: #1890FF; text-align: center; cursor: pointer; font-size: 12px;}</style>
复制代码
效果展示
划线
评论
复制
发布于: 刚刚阅读数: 7
版权声明: 本文为 InfoQ 作者【anyRTC开发者】的原创文章。
原文链接:【http://xie.infoq.cn/article/1ab917c3a48eb79e6499f5e60】。文章转载请联系作者。
anyRTC开发者
关注
实时交互,万物互联! 2020.08.10 加入
实时交互,万物互联,全球实时互动云服务商领跑者!










评论