写点什么

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
用户头像

实时交互,万物互联! 2020.08.10 加入

实时交互,万物互联,全球实时互动云服务商领跑者!

评论

发布
暂无评论
web技术分享| 基于vue3实现自己的组件库,第一章:Message组件_前端_anyRTC开发者_InfoQ写作社区