百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

web技术分享|基于vue3实现自己的组件库,第一章:Message组件

bigegpt 2024-08-05 11:49 2 浏览

大家好今天将开始新的系列基于vue3实现自己的组件库,本文默认你会安装和创建vue3项目,如果不会请参考vue官网,废话不多说开始实现本章的目标Message组件;

创建组件库工程目录

  • vair是组件库的名字(名字大家随意)

安装项目依赖

npm install less -D
npm 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>

效果展示

相关推荐

程序员请收好:10个非常有用的 Visual Studio Code 插件

一个插件列表,可以让你的程序员生活变得轻松许多。作者|Daan译者|Elle出品|CSDN(ID:CSDNnews)以下为译文:无论你是经验丰富的开发人员还是刚刚开始第一份工作的初级开发人...

PADS在WIN10系统中菜单显示不全的解决方法

决定由AD转PADS,打开发现菜单显示不正常,如下图所示:这个是由于系统的默认字体不合适导致,修改一下系统默认字体即可,修改方法如下:打开开始菜单-->所有程序-->Windows系统--...

一文讲解Web前端开发基础环境配置

先从基本的HTML语言开始学习。一个网页的所有内容都是基于HTML,为了学好HTML,不使用任何集成工具,而用一个文本编辑器,直接从最简单的HTML开始编写HTML。先在网上下载notepad++文...

TCP/IP协议栈在Linux内核中的运行时序分析

本文主要是讲解TCP/IP协议栈在Linux内核中的运行时序,文章较长,里面有配套的视频讲解,建议收藏观看。1Linux概述  1.1Linux操作系统架构简介Linux操作系统总体上由Linux...

从 Angular Route 中提前获取数据

#头条创作挑战赛#介绍提前获取意味着在数据呈现在屏幕之前获取到数据。本文中,你将学到,在路由更改前怎么获取到数据。通过本文,你将学会使用resolver,在AngularApp中应用re...

边做游戏边划水: 基于浅水方程的水面交互、河道交互模拟方法

以下文章来源于腾讯游戏学堂,作者Byreave篇一:基于浅水方程的水面交互本文主要介绍一种基于浅水方程的水体交互算法,在基本保持水体交互效果的前提下,实现了一种极简的水面模拟和物体交互方法。真实感的...

Nacos介绍及使用

一、Nacos介绍Nacos是SpringCloudAlibaba架构中最重要的组件。Nacos是一个更易于帮助构建云原生应用的动态服务发现、配置和服务管理平台,提供注册中心、配置中心和动态DNS...

Spring 中@Autowired,@Resource,@Inject 注解实现原理

使用案例前置条件:现在有一个Vehicle接口,它有两个实现类Bus和Car,现在还有一个类VehicleService需要注入一个Vehicle类型的Bean:publicinte...

一文带你搞懂Vue3 底层源码

作者:妹红大大转发链接:https://mp.weixin.qq.com/s/D_PRIMAD6i225Pn-a_lzPA前言vue3出来有一段时间了。今天正式开始记录一下梗vue3.0.0-be...

一线开发大牛带你深度解析探讨模板解释器,解释器的生成

解释器生成解释器的机器代码片段都是在TemplateInterpreterGenerator::generate_all()中生成的,下面将分小节详细展示该函数的具体细节,以及解释器某个组件的机器代码...

Nacos源码—9.Nacos升级gRPC分析五

大纲10.gRPC客户端初始化分析11.gRPC客户端的心跳机制(健康检查)12.gRPC服务端如何处理客户端的建立连接请求13.gRPC服务端如何映射各种请求与对应的Handler处理类14.gRP...

聊聊Spring AI的Tool Calling

序本文主要研究一下SpringAI的ToolCallingToolCallbackorg/springframework/ai/tool/ToolCallback.javapublicinter...

「云原生」Containerd ctr,crictl 和 nerdctl 命令介绍与实战操作

一、概述作为接替Docker运行时的Containerd在早在Kubernetes1.7时就能直接与Kubelet集成使用,只是大部分时候我们因熟悉Docker,在部署集群时采用了默认的dockers...

在MySQL登录时出现Access denied for user ~~ (using password: YES)

Windows~~~在MySQL登录时出现Accessdeniedforuser‘root‘@‘localhost‘(usingpassword:YES),并修改MySQL密码目录适用...

mysql 8.0多实例批量部署script

背景最近一个项目上,客户需要把阿里云的rdsformysql数据库同步至线下,用作数据的灾备,需要在线下的服务器上部署mysql8.0多实例,为了加快部署的速度,写了一个脚本。解决方案#!/bi...