侧边栏壁纸
博主头像
神奇的程序员

今天的努力只为未来

  • 累计撰写 154 篇文章
  • 累计创建 25 个标签
  • 累计收到 78 条评论

目 录CONTENT

文章目录

Vue实现一个全屏加载插件并发布至npm仓库

神奇的程序员
2020-01-31 / 0 评论 / 9 点赞 / 119 阅读 / 4,618 字 正在检测是否收录...

谁经历的苦难多,谁懂得的东西也就多。

前言

在做头像上传功能时,为了防止用户多次点击,通常会在上传时添加一个遮罩,提示用户:图片正在上传中,上传完毕后,关闭这个遮罩层,本来想找个UI框架引入进来,使用框架提供的弹层,找了很多没找到满意的,干脆自己做一个吧😂。接下来就跟大家分享下如何制作一个插件,先跟大家展示下最终实现的效果:

实现思路

涉及到的知识点: Vue 构造器实例挂载

  • 编写加载层业务代码,实现全局加载层的相关效果
  • 在插件包的index.js中进行相关封装
  • 定义插件对象,实现install方法
  • 使用Vue.extend构造器,将加载层业务代码作为构造器的参数创建子类
  • 实例化创建的构造器,挂载到HTMLElement实例上
  • 将构造器中的dom元素插入到body中
  • 添加实例方法,挂载至Vue原型
  • 实现显示和隐藏方法
  • 插件开发完毕

实现过程

  • 搭建插件开发环境

    • 如图所示:在一个Vue项目的src目录下创建lib文件夹,用于存放各种插件
    • 在lib文件夹下创建我们的插件文件夹(FullScreenLoading)
    • 在插件文件夹下分别创建lib文件夹和index.js文件
    • 插件文件夹下的lib文件夹用于存放插件需要用到的资源文件
    • index.js文件用于实现这个插件的所有逻辑
  • 插件业务代码(FullScreenLoading.vue)

<template>
    <div id="loadingPanel" v-if="show">
        <div class="container-panel">
            <div class="arc"></div>
            <h1><span>{{tips}}</span></h1>
        </div>
    </div>
</template>

<script>
    export default {
        name: "FullScreenLoading",
        data(){
            return{
                tips:"加载中",
                show:false
            }
        }
    }
</script>

<style src="./css/FullScreenLoading.css">

</style>
  • 插件样式代码(FullScreenLoading.css)
body {
    font-family: 'Inconsolata', monospace;
    overflow: hidden;
}
/*全屏遮罩层*/
#loadingPanel{
    width: 100%;
    height: 100%;
    background: rgba(11,11,20,.6);
    position: fixed;
    top: 0;
    left: 0;
    z-index: 9999;
    display: flex;
    justify-content: center;
    align-items: center;
}
#loadingPanel .container-panel{
    width: 200px;
    height: 200px;
    display: flex;
    justify-content: center;
    align-items: center;
}
#loadingPanel .container-panel .arc {
    width: 100px;
    height: 100px;
    border-radius: 50%;
    border-top: 2px solid #ffea29;
    border-left: 1px solid transparent;
    border-right: 1px solid transparent;
    animation: ring 2s infinite linear;
}
#loadingPanel .container-panel .arc::before {
    position: absolute;
    margin: auto;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 70px;
    height: 70px;
    border-radius: 50%;
    border-top: 2px solid #8d29ff;
    border-left: 1px solid transparent;
    border-right: 1px solid transparent;
    animation: ring 4s infinite linear reverse;
    content: "";
}
#loadingPanel .container-panel .arc::after {
    position: absolute;
    margin: auto;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 0;
    height: 0;
    border-radius: 50%;
    border-top: initial;
    border-left: initial;
    border-right: initial;
    animation: solidCircle 1s infinite;
    content: "";
    background: snow;
}

#loadingPanel .container-panel h1 {
    position: absolute;
    height: 40px;
    margin: auto;
    top: 200px;
    left: 0;
    right: 0;
    bottom: 0;
    text-transform: uppercase;
    text-align: center;
    letter-spacing: 0.1em;
    font-size: 14px;
    font-weight: bold;
    color: white;
}


/*动画定义*/
@keyframes ring {
    100% {
        transform: rotate(360deg);
    }
}
@keyframes solidCircle {
    0% {
        width: 0;
        height: 0;
    }
    75% {
        width: 40px;
        height: 40px;
    }
    100% {
        width: 0;
        height: 0;
    }
}


  • 插件逻辑文件(index.js)
// 引入对应的组件
import loading from "./lib/FullScreenLoading";

// 定义对象:开发插件对象
const LoadPlugin = {
    // 插件包含install方法
    install(Vue,options){
        // 使用Vue.extend构造器,创建一个子类,参数为引入的FullScreenLoading组件
        const loadingSubclass = Vue.extend(loading);
        // 实例化loadingSubclass,挂载到HTMLElement实例上
        const Profile = new loadingSubclass({
            el: document.createElement('div')
        });
        // 插入到body中,FullScreenLoading.vue中的template模板内容将会替换挂载的元素,Profile.el中到内容最终为模版到内容
        document.body.appendChild(Profile.$el);
        // 判断是否有传参数:替换组件内的默认显示数据
        if(options){
            if(options.tips){
                Profile.tips = options.tips;
            }
        }
        // 添加实例方法,挂载至Vue原型
        Vue.prototype.$fullScreenLoading = {
            // 定义显示隐藏的方法
            show(tips) {
                Profile.show = true;
                if (tips) {
                    // 替换组件的默认数据
                    Profile.tips = tips;
                }
            },
            hide() {
                Profile.show = false;
            }
        };
    }
};

// 导出对象
export default LoadPlugin;

至此,插件开发完毕。本文开头实现的效果,项目地址:chat-system

插件发布

  • 在终端进入到FullScreenLoading文件夹内
  • 创建README.md编写插件描述以及使用方法
  • 终端执行npm init命令,生成package.json文件
 npm init
 # 应用包名,要先去https://www.npmjs.com/官网查一下是否与你的包重复
 package name: (@likaia/vue-fullscreenloading)
 # 版本号
 version: (1.0.0)
 # 包描述
 description: 全屏加载层插件,提升用户体验,防止用户误操作。
 # 入口文件
 entry point: (index.js)
 # 测试命令,直接回车即可
 test command: 
 # 项目git仓库地址
 git repository: https://github.com/likaia/chat-system.git
 # 关键词:用户在npm官网搜索包时所用的关键词
 keywords: vue-loading FullScreenLoading
 # 作者
 author: likaia
 # 开源协议,直接回车即可
 license: (ISC) 

  • 发布到npm仓库
# 登录,没有账号的需要先去官网注册:https://www.npmjs.com/
npm login

# 发布至npm
npm publish --access public 

登录成功

发布成功

  • 在npm官网搜索刚才发布的包

使用插件

  • 终端执行: yarn add @likaia/vue-fullscreenloading

  • 在main.js中进行引用

import FullScreenLoading from '@likaia/vue-fullscreenloading'
Vue.use(FullScreenLoading);
  • 在业务中使用
uploadAvatar:function (e) {
  console.log("上传点击了");
  // 显示全局加载层
  this.$fullScreenLoading.show("上传中");
  let file = e.target.files[0];
  // 构造form对象
  let formData = new FormData();
  // 后台取值字段 | blob文件数据 | 文件名称
  formData.append("file",file,file.name);
  // 调用上传api
  this.$api.fileManageAPI.baseFileUpload(formData).then((res)=>{
    console.log(res);
    const fileName = `${base.lkBaseURL}/uploads/${res.fileName}`;
    // 更改默认头像状态
    this.isDefaultAvatar = false;
    // 头像赋值
    this.avatarSrc = fileName;
    // 隐藏全局加载层
    this.$fullScreenLoading.hide();
  });
  console.log(e);
}

写在最后

  • 文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注😊
  • 本文首发于掘金,如需转载请评论区留言💌
9

评论区