写在前面
和本博主一样的初学还不清楚怎么封装vue插件的道友,可以参考另一篇笔记: vue插件封装
基于回调封装confirm
// main.js
import ConfirmPlugin from "./components/confirm/confirmPlugin";
import Vue from "vue";
Vue.use(ConfirmPlugin)
new Vue({
data () {
return {
confirmOptions: {
isShow: true,
title: '提示',
content: '确定退出吗?'
}
}
},
methods: {
handleClick () {
this.$confirm({
...this.confirmOptions,
confirmCallBack: this.confirmCallBack,
cancelCallBack: this.cancelCallBack,
})
},
confirmCallBack () {
console.log('confirmCallBack this ======', this);
},
cancelCallBack () {
console.log('cancelCallBack this ======', this);
},
fff () {
console.log('fff', this);
},
FFF () {
console.log('FFF', this);
}
},
render () {
return <div onClick={this.handleClick} style={{ border: '1px solid red', display: 'inline-block' }}>click</div>
}
}).$mount("#app");
// confirm.vue
<template>
<div class="confirm-wrapper" v-if="isShow">
<div class="container">
<div class="title">{{ title }}</div>
<div class="content">{{ content }}</div>
<div class="btn">
<span class="btnCancel" v-if="cancelTxt" @click="onCancel">{{
cancelTxt
}}</span
><span class="btnConfirm" v-if="confirmTxt" @click="onConfirm">{{
confirmTxt
}}</span>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
isShow: {
type: Boolean,
default: false
},
title: {
type: String,
default: ''
},
content: {
type: String,
default: ''
},
cancelTxt: {
type: String,
default: '取消'
},
confirmTxt: {
type: String,
default: '确定'
},
confirmCallBack: {
type: Function,
default: null
},
cancelCallBack: {
type: Function,
default: null
}
},
data () {
return {
msg: '我是confirm组件'
}
},
methods: {
onCancel () {
this.isShow = false
this.cancelCallBack()
},
onConfirm () {
this.isShow = false
this.confirmCallBack();
},
}
}
</script>
<style>
.confirm-wrapper {
width: 100%;
height: 100%;
position: fixed;
left: 0;
top: 0;
background: rgba(0, 0, 0, 0.5);
}
.confirm-wrapper .container {
background-color: #fff;
position: fixed;
top: 50%;
left: 10%;
right: 10%;
padding: 30px 20px 0px 20px;
border-radius: 16px;
transform: translateY(-50%);
}
.confirm-wrapper .container .title {
margin-bottom: 38px;
color: #4a4a4a;
font-size: 38px;
}
.confirm-wrapper .container .content {
color: #999;
font-size: 32px;
text-align: center;
margin-top: 60px;
margin-bottom: 80px;
}
.confirm-wrapper .container .btn {
width: 100%;
margin: 0 auto;
border-top: 0.5px solid #999;
}
.confirm-wrapper .container .btn span.btnCancel {
display: inline-block;
text-align: center;
font-size: 34px;
background-color: #fff;
line-height: 48px;
width: 50%;
color: #666;
}
.confirm-wrapper .container .btn span.btnConfirm {
display: inline-block;
text-align: center;
width: 50%;
font-size: 34px;
color: #db2c17;
background-color: #fff;
line-height: 48px;
}
</style>
// confirmPlugin.js
import Confirm from './confirm.vue'
const confirmPlugin = {
install (Vue) {
let ConfirmConstruct = Vue.extend(Confirm)
Vue.prototype.$confirm = function (options) {
let instance = new ConfirmConstruct({ propsData: options })
document.body.appendChild(instance.$mount().$el)
}
}
}
export default confirmPlugin
基于promise封装confirm
// 在mains.js中使用
import Vue from "vue";
import ConfirmPlugin from "./components/confirm/confirmPlugin";
Vue.use(ConfirmPlugin)
new Vue({
methods: {
handleClick () {
this.$confirm({
isShow: true,
title: '提示',
content: '确定退出吗?',
cancelTxt: 'cancel',
confirmTxt: 'ok'
}).then(() => {
// 点击确定todo
}).catch(() => {
// 点击取消todo
})
},
},
render () {
return <div onClick={this.handleClick} style={{ border: '1px solid red', display: 'inline-block' }}>click</div>
}
}).$mount("#app");
// confirmPlugins.js
import Confirm from './confirm.vue'
const confirmPlugin = {
install (Vue) {
let ConfirmConstruct = Vue.extend(Confirm)
Vue.prototype.$confirm = options => {
let instance = new ConfirmConstruct({ propsData: options })
document.body.appendChild(instance.$mount().$el)
instance.$el.style.zIndex = 1000
return instance.showConfirm()
}
}
}
export default confirmPlugin
// confirm.vue
<template lang="pug">
.confirm-wrapper(v-if="isShow")
.container
.title(v-if="title") {{title}}
.content {{content}}
.doubleBtn(v-if="isShowCancelBtn")
span.btnCancel(v-if="cancelTxt" @click="onCancel") {{cancelTxt}}
span.btnConfirm(v-if="confirmTxt" @click="onConfirm") {{confirmTxt}}
.singleBtn(v-if="!isShowCancelBtn")
span.btnConfirm(v-if="confirmTxt" @click="onConfirm") {{confirmTxt}}
</template>
<script>
export default {
props: {
isShow: { // 是否展示confirm弹窗
type: Boolean,
default: false,
required: true
},
title: { // confirm弹窗标题
type: String,
default: ''
},
content: { // confirm弹窗内容
type: String,
default: ''
},
cancelTxt: { // 确认按钮文字
type: String,
default: '取消'
},
confirmTxt: { // 取消按钮文字
type: String,
default: '确定'
},
isShowCancelBtn: { // 是否展示取消按钮
type: Boolean,
default: true
}
},
data() {
return {
resolve: null, // resolve回调
reject: null, // reject回调
}
},
methods: {
// 点击取消触发的回调
onCancel() {
this.reject()
this.removeConfirm()
},
// 点击确定触发的回调
onConfirm() {
this.resolve()
this.removeConfirm()
},
// 展示弹窗
showConfirm() {
return new Promise((resolve, reject) => {
this.resolve = resolve
this.reject = reject
})
},
// 删除confirm组件
removeConfirm() {
this.isShow = false
setTimeout(() => {
document.body.removeChild(this.$el)
}, 500)
},
}
}
</script>
<style scoped lang="stylus">
div
line-height 0
margin 0
padding 0
.confirm-wrapper
width: 100%
height: 100%
position: fixed
left: 0
top: 0
background: rgba(0,0,0,0.50)
.container
background-color #fff
position fixed
top 50%
left 10%
right 10%
padding 30px 20px 0px 20px
border-radius 16px
transform translateY(-50%)
.title
color #4a4a4a
font-size 34px
font-weight 400
text-align left
padding-left 20px
line-height 68px
.content
color #999
font-size 38px
text-align center
padding 50px 0px
line-height 68px
font-weight 400
.doubleBtn
width 100%
margin 0 auto
border-top 0.5px solid rgba(51, 51, 51, .06)
span.btnCancel
display inline-block
text-align center
font-size: 32px;
background-color #fff
line-height 68px
width 50%
color #666666
border-right 0.5px solid rgba(51, 51, 51, .06)
padding: 24px 0px
span.btnConfirm
display inline-block
text-align center
width: 50%
font-size 32px
color #DB2C17
background-color #fff
line-height 68px
padding: 24px 0px
.singleBtn
width 100%
margin 0 auto
border-top 0.5px solid rgba(51, 51, 51, .06)
span.btnConfirm
display block
text-align center
font-size 32px
color #DB2C17
background-color #fff
line-height 68px
padding: 24px 0px
</style>
基于promise封装的思考
写出回调函数的方式很快,但是写出promise的过程并非一帆风顺;这里简单总结下封装promise过程中的思考。
可以留意下基于promise的封装代码的顺序,也是思考的顺序,先从confirm组件使用入手,希望用户怎么依赖promise使用confirm,接着想办法挂载方法或者对象到Vue原型上,使得返回是promise;最后就是promise和reject&resolve的理解了。
效果展示
封装过程中问题整理
参考
Vue原理解析(十一):搞懂extend和$mount原理并实现一个命令式Confirm弹窗组件