未加星标

以v-model与promise两种方式实现vue弹窗组件

字体大小 | |
[前端(javascript) 所属分类 前端(javascript) | 发布者 店小二03 | 时间 | 作者 红领巾 ] 0人收藏点击收藏

最近公司有一个后台业务虽然也是写在了现有的后台系统中,但是之后要为这个业务单独拉出来新建一个后台系统,所以现有的后台系统中的vue组件库,就不能用了(因为不知道将来的系统要基于什么组件库,以防给未来移植项目带来麻烦),这次业务中又遇到了弹窗的功能,所以只能手动写一个了(虽然说弹窗组件很简单,也是想自己总结一下,有不对的地方也请指出),一开始用传统的props,$emit但是觉得要接两个取消与确认的回调这块的逻辑分散了所以就用了promise两个回调的方式把两个回调写在了一起,并不一定好,算是提供一种思路吧。

一.概览

先看最后的调用方式

props $emit方式

<chat-modal ref="chat-modal" v-model="showModal" cancelText="取消" sureText="确认" title="弹窗标题" small @on-ok="onOK" @on-cancel="onCancel">
<div>slot的东西,想向弹窗中添加自定义的内容</div>
</chat-modal>
methods: {
display() {
this.showModal = true;//交互点击手动触发显示弹窗
},
onOK() {},//点击确认的回调
onCancel() {}//点击取消的回调
}
promise的回调方式

<chat-modal ref="chat-modal"></chat-modal>
methods: {
display() {
this.$refs["chat-modal"].openModal({
title: "弹窗标题",
sureText: "确认",
cancelText: "取消"
}).then(res => {
//点击确认的回调
}, res => {
//点击取消的回调
})
}
}

第二种方式的好处就是把所有的逻辑都集中到了一个方法里。

二.看下组件的源码

tip: 样式有些烂...

<template>
<div>
<div class="shadow" v-show="showModal"></div>
<div class="modal" :class="{'smSize': otherText.small || small}" v-show="showModal">
<div class="header">{{ otherText.title || title}}</div>
<div class="body">
<slot></slot>
</div>
<div class="footer">
<div class="item success" id="sure" ref="sure" @click="makeSure" v-show="otherText.sureText || sureText">{{ otherText.sureText || sureText }}</div>
<div class="item red" id="cancel" ref="cancel" @click="makeCancel" v-show="otherText.cancelText || cancelText">{{ otherText.cancelText || cancelText }}</div>
</div>
</div>
</div>
</template>
<script>
//此组件提供两种调用方法,可以在组件上v-model一个表示是否显示弹窗的对话框,然后需要的一些值通过props传入,然后$emit在组件上@监听做回调
//第二中方法所有的传值回调都只需要在组件内部的一个方法调用然后在组件外部this.$refs[xxx].open调用然后.then触发回调,比上一种方便些
var initOtherText = {
sureText: "",
cancelText: "",
title: "",
small: false
};
export default {
props: {
title: {
type: String
},
sureText: {
type: String
},
cancelText: {
type: String
},
value: {
type: Boolean
},
small: {
type: Boolean
}
},
watch: {
value(newVal) {
this.showModal = newVal;
}
},
data() {
return {
otherText: JSON.parse(JSON.stringify(initOtherText)),
showModal: this.value
};
},
methods: {
makeSure() {
this.$emit("on-ok");
this.$emit("input", false);
},
makeCancel() {
this.$emit("on-cancel");
this.$emit("input", false);
},
openModal(otherText) {
this.otherText = { ...otherText };
this.showModal = true;
var pms = new Promise((resolve, reject) => {
this.$refs["sure"].addEventListener("click", () => {
this.showModal = false;
resolve("点击了确定");
});
this.$refs["cancel"].addEventListener("click", () => {
this.showModal = false;
reject("点击了取消");
});
});
return pms;
}
}
};
</script>
<style lang="scss" scoped>
.shadow {
background-color: rgba(0, 0, 0, 0.5);
display: table;
height: 100%;
left: 0;
position: fixed;
top: 0;
transition: opacity 0.3s ease;
width: 100%;
z-index: 50;
}
.modal {
display: table-cell;
vertical-align: middle;
overflow-x: hidden;
position: fixed;
background-color: white;
box-shadow: rgba(0, 0, 0, 0.33) 0px 2px 8px;
border-radius: 5px;
outline: 0px;
overflow: hidden;
transition: all 0.3s ease;
width: 600px;
height: 400px;
top: 50%;
left: 50%;
margin-top: -200px;
margin-left: -300px;
}
.header {
align-items: center;
background-color: #62a39e;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.16);
color: #fff;
font-weight: bold;
display: -ms-flexbox;
display: flex;
height: 3.5rem;
padding: 0 1.5rem;
position: relative;
z-index: 1;
}
.body {
align-items: center;
padding: 1.5rem;
}
.footer {
justify-content: flex-end;
padding: 1.5rem;
position: absolute;
bottom: 0;
width: 100%;
float: right;
}
.item {
color: white;
text-align: center;
border-radius: 5px;
padding: 10px;
cursor: pointer;
display: inline-block;
}
.info {
background-color: #2196f3;
}
.success {
background-color: #62a39e;
}
.red {
background-color: #e95358;
}
.smSize {
height: 200px;
}
</style>

首先分析一下第一种方式: 调用者需要在组件外部v-model上绑定一个变量(例中为showModal)来指示弹窗是否显示,显示的时候需要在组件外部手动设置 this.showModal = true ,组件内部props定义一个属性来接这个值为 value: {type: Boolean} ,同时在组件内部在用声明一个变量用来同步外部传进来的props值 默认值为 showModal: this.value (内部声明的值也叫了showModal),在watch中监听进行同步 watch: { value(newVal) { this.showModal = newVal } } ;然后把组件内部的这个showModal值绑定在需要显示或者隐藏的DOM元素上。向外抛出事件的时候是在点击组件内部的确定与关闭按钮时候

makeSure() {
this.$emit("on-ok");
this.$emit("input", false);
},
makeCancel() {
this.$emit("on-cancel");
this.$emit("input", false);
}
this.$emit("on-ok");this.$emit("on-cancel"); 这两句的是向外抛出事件在组件外部@接一下然后写自己需要的回调函数。这时就可以实现弹窗的显示与隐藏了,你可能发现并没有一句代码去设置this.showModal = false;弹窗就隐藏了。主要是因为这几句代码 v-model = 'showModal' 和 组件内部的 props: {value: {type: Boolean}} this.$emit("input", false) 。v-model其实是vue的语法糖, <chat-modal v-model="showModal"> 其实可以写为 <chat-modal :value="showModal" @input="showModal = arguments[0]"> 所以要求我们在组件内部必须规定props的名字必须为value, 然后在组件内部触发确定或者取消的时候在组件内部触发 this.$emit("input", false) 这样实现了直接隐藏弹窗而不必打扰用户让用户在组件外部在手动将showModal置为false.

然后来看promise的方式: 第一种方式传进来的值都通过props来接的,这种方式通过在组件内部定义了另一个对象来接传进来的值,

var initOtherText = {
sureText: "",
cancelText: "",
title: "",
small: false
};
otherText: JSON.parse(JSON.stringify(initOtherText)),

然后在menthods里定义了一个名为openModal的方法,然后把传进来的一系列参数赋值给组件内部的对象 this.otherText = { ...otherText }; this.showModal = true; 并且将showModal置为true,然后每次触发的时候新建一个promise对象,里面的异步事件为点击确定和取消的两个点击事件,这里要操作DOM了

this.$refs["sure"].addEventListener("click", () => {
this.showModal = false;
resolve("点击了确定");
});

获取确定按钮的DOM元素绑定点击事件,回调里将showModal置为false并且resolve,

this.$refs["cancel"].addEventListener("click", () => {
this.showModal = false;
reject("点击了取消");
});

获取取消按钮的DOM绑定点击事件,回调里reject.

遇到的坑

这之前遇到了一个坑,因为第一次已经绑定了点击事件,第二次resolve和reject就会失败,本想取消一下绑定事件,但是因为将整个弹窗v-show="showModal"的原因整个DOM被display:none;了就不需要手动解绑了。 第二个是关于用v-if还是v-show来隐藏弹窗,一开始用的是v-if但是发现在这步时

this.showModal = true;
var pms = new Promise((resolve, reject) => {
this.$refs["sure"].addEventListener.xxx//省略
});
return pms;

将showModal置为true时然后就去绑定事件这时候还没有DOM还没有解析玩DOM树上还没有,要不就得用this.$nextTick增加了复杂度,最后采用了v-show;

关于优先级问题

如果既在组件上用prop传了值(title,sureText之类的)如 <chat-modal" title="xx" sureText="xxx"></chat-modal> 也在方法里传了

this.$refs["chat-modal"].openModal({
title: "服务小结",
sureText: "提交并结束",
cancelText: "取消"
}).then();

是以方法的优先级为高,在组件内部DOM元素上通过||设置了优先级,比如 <div class="header popModal">{{ otherText.title || title}}</div> 有方法的值取方法的值,没有取props得值。

总结

以上所述是小编给大家介绍的以v-model与promise两种方式实现vue弹窗组件,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!


您可能感兴趣的文章:vue弹窗消息组件的使用方法使用Vue组件实现一个简单弹窗效果很棒的vue弹窗组件关于vue.js弹窗组件的知识点总结浅谈 Vue v-model指令的实现原理vue v-model表单控件绑定详解Vue 进阶教程之v-model详解vue.js指令v-model使用方法Vue2.0利用 v-model 实现组件props双向绑定的优美解决方案详解vue-resource promise兼容性问题

本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程

主题: 其实谢大变量
tags: gt,lt,showModal,组件,div,弹窗,emit,false,otherText,modal,model,sureText,chat,title
分页:12
转载请注明
本文标题:以v-model与promise两种方式实现vue弹窗组件
本站链接:https://www.codesec.net/view/576828.html


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 前端(javascript) | 评论(0) | 阅读(118)