前言
在项目中弹窗和加载模块必不可少,如果是大型项目首先会考虑使用哪些适用于自身的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的疫情影响太大,作为一名蠢蠢欲动的小前端跳槽失败只能选择观望。如果有前端开发职位可以联系我了解一下,看我能不能成为幸运的一位网民。当然志同道合的朋友也可以联系我,技术交流沟通我求之不得。
最后,希望每个人都能成就自己的一番事业。当自己在中年时不是平庸,不是叹息现实暗自无奈,无所适从。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。