基于Vant封装一套弹窗插件
最近这段时间,公司要求做一套移动端审批流程的页面。大量页面包含了固定样式的提示窗口。类似(alert、toast、confirm)的提示弹窗。考虑到移动端开发,所以采用了市面上面比较火的Vant(友赞)的UI框架。
但是一般公司的设计都会比较定制化,会再原有的基础之上,做些主题、样式、交互上的一些调整。不过话说回来,毕竟用的是基于Vue这种框架。此时插槽不就是信手拈来。
考虑到多人协作开发,弹窗又都是一样。所以就自己封装了一套插件,供其他人使用。虽可能不尽完美,但是确实是学习到了一些底层封装的思路。这不就是我们作为开发的人热衷的方向吗?做这些事情实际上也是在锻炼自己的技术,学习其他框架编写的思路,理解底层业务的实现原理。这一套封装虽不是多么强大,但也算是重新给我打开了一扇大门,让我对Javascript的有了更进一步的理解。
公司UI
封装的弹窗最终效果
虽然可能有些出入(button,主要是没完善)
设计思路
最开始想到的肯定是Components,因为Vue本身全部都是组件,所有页面也都是以组件的形式开发,包括Template。通常如果封装弹窗组件,使用顺序一般都是
import
、然后声明、再然后用标签注入到相对应的页面上面使用,其实感觉并不是很友好。而且操作起来很麻烦,还要考虑到子组件注册弹窗后调用的时候,生命周期问题。如果对依赖顺序不太理不清的时候,会出现类似this.$refs... is undifiend | not function
的情况。 那为什么不能用类似
this.$confirm
或者this.$alert
的形式,再我想要用到的时候直接一条命令就可以了呢?想到这里,就想到Vue
提供的插件开发的支持。也就有了上面的最终效果。
供上代码
目录结构
VMessage
├── Confirm
│ ├── main.js
│ └── main.vue
└── index.js
Confirm/mian.vue
<template>
<div class="private-vant-confirm-container">
<private-dialog
v-model="show"
:before-close="beforeClose"
:show-cancel-button="showCancelButton"
:show-confirm-button="showConfirmButton"
:close-on-click-overlay="closeOnClickOverlay"
>
<section>
<svg-icon :icon-class="iconClass" v-if="iconClass" class-name="icon"></svg-icon>
<span v-if="tips" class="tips">{{tips}}</span>
<span v-if="message" class="message">{{message}}</span>
</section>
</private-dialog>
</div>
</template>
<script>
/* 确认弹窗 */
import { Dialog } from "vant";
export default {
components: {
"private-dialog": Dialog.Component
},
data() {
return {
show: false,
type: "success",
tips: "",
icon: "",
message: "",
showCancelButton: false /* 是否展示取消按钮 */,
showConfirmButton: false /* 是否展示确认按钮 */,
closeOnClickOverlay: false /* 是否在点击遮罩层后关闭弹窗 */,
onClose: null,
duration: 2000
};
},
watch: {
show(val) {
const { showCancelButton, showConfirmButton, duration } = this.$data;
if (val && !showCancelButton && !showConfirmButton) {
setTimeout(() => {
this.show = false;
this.handleCallback("close");
}, duration);
}
}
},
computed: {
iconClass() {
return this.icon || this.type;
}
},
methods: {
beforeClose(action, done) {
this.show = false;
done();
this.handleCallback(action);
},
handleCallback(action) {
if (typeof this.onClose === "function") {
this.onClose(action);
}
}
}
};
</script>
<style lang="scss" scoped>
.private-vant-confirm-container {
section {
padding: 20px 0;
display: flex;
justify-content: space-around;
align-items: center;
flex-direction: column;
.icon {
font-size: 65px;
}
span {
margin-top: 10px;
}
.tips {
color: #2c2d2f;
font-size: 20px;
}
.message {
color: #48494c;
font-size: 17px;
}
}
}
</style>
Confirm/mian.js
import Vue from "vue";
import Main from "./main.vue";
let ConfirmConstructor = Vue.extend(Main);
const Confirm = function(options) {
options = options || {};
if (typeof options === "string") {
options = {
message: options,
};
}
let instance = new ConfirmConstructor({
data: options,
});
instance.$mount();
document.body.appendChild(instance.$el);
instance.show = true;
return instance;
};
["success", "warning"].forEach((type) => {
Confirm[type] = (options) => {
if (typeof options === "string") {
options = {
message: options,
};
}
options.type = type;
return Confirm(options);
};
});
export default Confirm;
VMessage/index.js
/* 确认弹窗 */
import Confirm from "./Confirm/main";
/**
使用示例
this.$vConfirm.success({
message: "提交成功",
onClose(action) {
console.log(action, " action");
}
});
this.$vConfirm.warning({
message: "确定同意该申请?",
tips: "提示",
showCancelButton: true,
showConfirmButton: true,
onClose(action) {
console.log(action, " action");
}
});
try {
const action = await this.$vConfirmSync({
type: "warning",
message: "提交成功",
showCancelButton: true,
closeOnClickOverlay: false
});
console.log(action, " action");
} catch (error) {
console.log(error, " error");
}
*/
/**
* 同步用法
* @param {String} tips 提示
* @param {String} message 内容
* @param {String} type success (default) | warning
* @param {String} icon 图标 load svg-icon
* @param {Boolean} showCancelButton 是否展示取消按钮 default:false
* @param {Boolean} showConfirmButton 是否展示确认按钮 default:false
* @param {Boolean} closeOnClickOverlay 是否在点击遮罩层后关闭弹窗 default: false
* @param {Number} duration 关闭时间 showCancelButton为false && showConfirmButton为false时 default:2000
*/
function vConfirmSync(options) {
return new Promise((resolve, reject) => {
Confirm({
...options,
onClose(action) {
if (action === "confirm") resolve(action);
else reject(action);
},
});
});
}
/**
* @author Gj
* 封装Vant Dialog
*/
const install = function(Vue) {
Vue.prototype.$vConfirm = Confirm;
Vue.prototype.$vConfirmSync = vConfirmSync;
};
export default {
install,
};
src/main.js
vue
的注入口文件注册
import { VMessage } from "@/components/index";
Vue.use(VMessage);
...
new Vue({
router,
store,
i18n,
render: (h) => h(App),
}).$mount("#app");