前言

在项目中弹窗和加载模块必不可少,如果是大型项目首先会考虑使用哪些适用于自身的ui框架。但我们需要做一些自定义ui较多且项目小型时就需要自己封装modal弹窗和加载模块了,构建项目时,这也是开发最平常需要的共用模块封装。这里放上自己在项目开发中学习使用封装的jquery,vue项目弹窗和加载模块封装函数,让有需要的人可以快速直接使用学习。

使用jquery的传统开发项目

modal

  • js
function modal(param) {
    if($('#sysModal').length <= 0) {
        $('body').append('<div id="sysModal"></div>');
    }
    var timeStamp = new Date().getTime();
    var title = param.title || '我是标题',
                content = param.content || ‘我是内容’,
                yesText = param.yesText || '确定',
                noText = param.noText,
                yesFn = param.yesFn,
                noFn = param.noFn;
    var html =  '<div class="modal-mask" id="modal_' + timeStamp + '">'
                    + '<div class="modal-wraper">'
                    + '<div class="modal-container">';
    if (title) html += '<div class="modal-header">' + title + '</div>';
                html += '<div class="modal-body"><div>' + content + '</div></div>';
                html += '<div class="modal-btn">'
    if(noText) {
    html += '<input type="button" class="modal-btn-cancel"  value="' + noText + '" />';
    }
    html += '<input type="button" class="modal-btn-confirm"  value="' + yesText + '" />';
    html += '</div></div></div></div>';
               
    var modal = $(html).appendTo('#sysModal');
    modal.on("click", '.modal-btn-cancel', function () {
        noFn && $.isFunction(noFn) && noFn();
        $(modal).remove();
    });
    modal.on("click", '.modal-btn-confirm', function () {
        yesFn && $.isFunction(yesFn) && yesFn();
        $(modal).remove();
    });
}
  • css
.modal-mask {
    position: fixed;
    z-index: 9998;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0,0,0,.5);
    display: table;
    transition: opacity .3s ease;
    overflow: hidden
}

.modal-mask .modal-wraper {
    vertical-align: middle;
    display: table-cell
}

.modal-mask .modal-wraper .modal-container {
    margin: 0 35%;
    background-color: #fff;
    border-radius: .05rem;
    box-shadow: 0 .02rem .08rem rgba(0,0,0,.33);
    transition: all .3s ease;
    font-family: Arial,Microsoft YaHei
}

.modal-mask .modal-wraper .modal-container .modal-header {
    line-height: .56rem;
    font-size: .18rem;
    padding-top: .23rem;
    text-align: center;
    font-weight: bolder;
    color: #1e1e1e
}

.modal-mask .modal-wraper .modal-container .modal-body {
    padding: .12rem .8rem .3rem .8rem;
    font-size: .18rem;
    line-height: .4rem;
    text-align: center
}

.modal-mask .modal-wraper .modal-container .modal-btn {
    border-top: .01rem solid #e7e7e7;
    display: flex;
    width: 100%
}

.modal-mask .modal-wraper .modal-container .modal-btn .modal-btn-cancel,.modal-mask .modal-wraper .modal-container .modal-btn .modal-btn-confirm {
    flex: 1;
    line-height: 2;
    font-size: .18rem;
    border: none;
    background: none
}

.modal-mask .modal-wraper .modal-container .modal-btn .modal-btn-cancel {
    color: #dadada;
    border-right: .01rem solid #e7e7e7;
    border-radius: initial
}

.modal-mask .modal-wraper .modal-container .modal-btn .modal-btn-confirm {
    color: #00549b
}

@media screen and(max-width:1080px) {
    .modal-mask .modal-wraper .modal-container {
        margin: 0 20%;
    }
    .modal-mask .modal-wraper .modal-container .modal-body {
        padding: .2rem;
        font-size: .36rem;
        ine-height: 1.5;
    }
    .modal-mask .modal-wraper .modal-container .modal-btn .modal-btn-cancel,
    .modal-mask .modal-wraper .modal-container .modal-btn .modal-btn-confirm {
        font-size: .36rem;
    }
    .modal-mask .modal-wraper .modal-container .modal-header {
        font-size: .36rem;
        line-height: 1.5;
    }
}

loading

  • js
var loading = {
    show: function(txt) {
        if($('#sysLoading').length <= 0) {
        var html = '<div id="loading" class="loading-mask">'
                    + '<div class="loading-body">'
                    + '<div class="loading-three-bounce"><div class="one"></div><div class="two"></div><div class="three"></div></div>'
                    + '<span class="loading-txt"></span>'
                    + '</div>'
                    + '</div>'
        $('body').append(html);
        }
        txt = txt || '加载中...';
        $('#sysLoading').find('.loading-txt').text(txt);
        $('#sysLoading').show();
    },
    hide:function() {
        $('#sysLoading').hide();
    }
}
  • css
.loading-mask {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    background: rgba(0,0,0,0.5);
    z-index: 10000;
}


.loading-body {
    position: relative;
    top: 50%;
    left: 50%;
    -ms-transform: translate(-50%,-50%);
    -moz-transform: translate(-50%,-50%);
    -webkit-transform: translate(-50%,-50%);
    transform: translate(-50%,-50%);
    text-align: center;
}
.loading-txt {
    vertical-align: middle;
    display: inline-block;
    color: #fff;
    font-size: 0.15rem;
}
.loading-three-bounce {
    position: relative;
    text-align: center;
}
.loading-three-bounce>div {
    display: inline-block;
    width: 0.2rem;
    height: 0.2rem;
    border-radius: 100%;
    background: #fff;
    animation: bouncedelay 1.4s infinite ease-in-out;
    animation-fill-mode: both;
}
.loading-three-bounce>div:not(:last-child) {
    margin-right: 0.05rem;
}
@keyframes bouncedelay{
    0%,100%,80% {transform:scale(0);-webkit-transform:scale(0)}
    40% {transform:scale(1);-webkit-transform:scale(1)}
}
.loading-three-bounce .one {
    animation-delay: -.32s;
}
.loading-three-bounce .two {
    animation-delay: -.16s;
}

vue项目

modal

  • component
<template>
  <div v-if="!bIsMB" class="modal-mask" v-show="visible">
    <div class="modal-wraper">
      <div class="modal-container">
        <div class="modal-header" v-if="title">{{title}}</div>
        <div class="modal-body">
          <div>
            <div v-html="message"></div>
          </div>
        </div>
        <div class="modal-btn">
          <input v-if="!showOneBtn" type="button" class="modal-btn-cancel" @click="handleCancel()" :value="cancelButtonText" />
          <input type="button" class="modal-btn-confirm" @click="handleConfirm()" :value="confirmButtonText" />
        </div>
      </div>
    </div>
  </div>
  <div v-else class="modal-mask m-modal-mask" v-show="visible">
    <div class="modal-wraper m-modal-wraper">
      <div class="modal-container m-modal-container">
        <div class="modal-header m-modal-header" v-if="title">{{title}}</div>
        <div class="modal-body m-modal-body">
          <div>
            <div v-html="message"></div>
          </div>
        </div>
        <div class="modal-btn m-modal-btn">
          <input v-if="!showOneBtn" type="button" class="modal-btn-cancel m-modal-btn-cancel" @click="handleCancel()" :value="cancelButtonText" />
          <input type="button" class="modal-btn-confirm m-modal-btn-confirm" @click="handleConfirm()" :value="confirmButtonText" />
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { IsMobile } from '../utils/util';
export default {
  name: 'modal',
  props: {
    title: {
      type: String,
      default: ''
    },
    message: {
      type: String,
      default: ''
    },
    confirmButtonText: {
      type: String,
      default: '确定'
    },
    cancelButtonText: {
      type: String,
      default: '取消'
    },
    handleConfirm: {
      type: Function,
      default() {
        this.visible = false;
      }
    },
    handleCancel: {
      type: Function,
      default() {
        this.visible = false;
      }
    },
    showOneBtn: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      visible: false,
      bIsMB: IsMobile(),
    }
  },
  watch: {
    visible(val,oldVal){
      if(!val) {
        this.close();
      }
    }
  },
  methods: {

  }
}
</script>
<style lang="scss">
  .modal-mask {
    position: fixed;
    z-index: 9998;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    display: table;
    transition: opacity .3s ease;
    overflow: hidden;
    .modal-wraper {
      vertical-align: middle;
      display: table-cell;
      .modal-container {
        margin: 0px 35%;
        background-color: #fff;
        border-radius: 0.05rem;
        box-shadow: 0 0.02rem 0.08rem rgba(0, 0, 0, 0.33);
        transition: all .3s ease;
        font-family: Arial, "Microsoft YaHei";
        .modal-header {
          line-height: .56rem;
          font-size: 18px;
          padding-top: .23rem;
          text-align: center;
          font-weight: bolder;
          color: #1e1e1e;
        }
        .modal-body {
          padding: 0.12rem 0.8rem 0.3rem 0.8rem;
          font-size: 18px;
          line-height: .4rem;
          text-align: center;
        }
        .modal-btn {
          border-top: 0.01rem solid #e7e7e7;
          display: flex;
          width: 100%;
          .modal-btn-cancel,.modal-btn-confirm {
            flex: 1;
            // height: .9rem;
            line-height: 2;
            font-size: 18px;
            border: none;
            background: none;
          }
          .modal-btn-cancel {
            color: #dadada;
            border-right: 0.01rem solid #e7e7e7;
            border-radius: initial; //解决safari border继承bug
          }
          .modal-btn-confirm {
            color: blue;
          }
        }
      }
    }
  }
  .m-modal-mask {
    .m-modal-wraper {
      .m-modal-container {
        margin: 0px 20%;
        div.m-modal-header {
          font-size: 0.36rem;
          line-height: 1.5;
        }
        div.m-modal-body {
          padding: 0.2rem;
          font-size: 0.36rem;
          line-height: 1.5;
        }
        .m-modal-btn {
          input.modal-btn-cancel,input.modal-btn-confirm {
            font-size: 0.36rem;
          }
        }
      }
    }
  }
  • js
import Vue from 'vue' 
import Modal from '../components/Modal.vue';
export const VModal = (() => {
  let ModalC = Vue.extend(Modal);
  let modalInstance;
  let el = document.createElement('div');
  return {
    show(options = {}) {
      // if(!modalInstance) {
        this.initInstance(options);
      // }
      // modalInstance.visible = true;
    },
    initInstance(options) {
      modalInstance = new ModalC({
        el: el
      });
      modalInstance.message = options.message || '请输入内容';
      for (var prop in options) {
        if (options.hasOwnProperty(prop)) {
          modalInstance[prop] = options[prop];
        }
      }
      document.body.appendChild(modalInstance.$el);
      Vue.nextTick(() => {
        modalInstance.visible = true;
      });
      modalInstance.close = function() {
        document.body.removeChild(modalInstance.$el);
      }
    },
    close() {
      modalInstance.visible = false;
      document.body.removeChild(modalInstance.$el);
    }
  }
})();

loading

  • component
<template>
    <div class="loading" v-show="visible">
        <div class="loading-mask">
            <div class="loading-outter">
                <div class="loading-wrap">
                    <div class="loading-ring"></div>
                </div>
                <div class="loading-rect"></div>
                <div class="loading-text">{{ text }}</div>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    props: {
        text: {
            type: String,
            default: ''
        }
    },
    data () {
        return {
            visible: true
        };
    }
};
</script>
<style lang="scss" scoped>
    .loading{
        transition: opacity .3s linear;
        width: 100%;
        height: 100%;
        position: fixed;
        display: block;
        text-align: center;
        top: 0;
        background-color: transparent;//背景透明
        z-index: 9999;
        &:after{
            content: "";
            display: inline-block;
        }
    }
    .loading-mask{
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, .2);
    }
.loading-outter {
    position: relative;
    top: 50%;
    margin-top: -0.35rem;
    display: inline-block;
    vertical-align: middle;
    background-color: #222;
    border-radius: .5rem;
    height: .75rem;
}
.loading-wrap {
    position: absolute;
    width: .56rem;
    height: .56rem;
    top: .094rem;
    left: .09rem
}
.loading-ring {
    width: .56rem;
    height: .56rem;
    background-image: url("../assets/images/loading.svg");
    background-size: cover;
    position: absolute;
}
.loading-rect {
    height: .18rem;
    width: .18rem;
    background-color: #FD404A;
    border-radius: .05rem;
    transform: rotate3D(0, 0, 1, 45deg);
    position: absolute;
    left: .28rem;
    top: .28rem;
}

.loading-text {
    text-align: left;
    color: #fff;
    font-size: .24rem;
    font-family: sans-serif;
    line-height: .75rem;
    padding-left: .85rem;
    padding-right: .26rem;
}

.loading-enter,
.loading-leave-active {
    opacity: 0;
}
</style>
  • js
import Loading from '../components/Loading.vue';

let LoadingC = Vue.extend(Loading);
let instance;
export const Load = {
  open(options = {}) {
    if (!instance) {
      this.initInstance(options);
    }
    instance.visible = true;
  },
  initInstance(options) {
    instance = new LoadingC({
      el: document.createElement('div')
    });
    instance.text = options.text || '加载中';
    for (var prop in options) {
      if (options.hasOwnProperty(prop)) {
        instance[prop] = options[prop];
      }
    }
    document.body.appendChild(instance.$el);
    Vue.nextTick(() => {
      instance.visible = true;
    });
  },
  close() {
    instance.visible = false;
  }
};

扩展

react与vue封装类似,这里不再贴出代码了,可自行借鉴动手实现一下。
提示:一个文件作为component,一个js文件作为调用封装。
不知道有没有大神愿意分享更易用的封装函数,这些也只是我自己个人技术有限的分享。

总结

2020的疫情影响太大,作为一名蠢蠢欲动的小前端跳槽失败只能选择观望。如果有前端开发职位可以联系我了解一下,看我能不能成为幸运的一位网民。当然志同道合的朋友也可以联系我,技术交流沟通我求之不得。
最后,希望每个人都能成就自己的一番事业。当自己在中年时不是平庸,不是叹息现实暗自无奈,无所适从。


明明很开心
0 声望0 粉丝

“路漫漫其修远兮,吾将上下而求索”