首页 web前端 js教程 如何使用v-model与promise两种方式实现vue弹窗组件

如何使用v-model与promise两种方式实现vue弹窗组件

May 28, 2018 pm 03:00 PM
promise v-model

这次给大家带来如何使用v-model与promise两种方式实现vue弹窗组件,使用v-model与promise两种方式实现vue弹窗组件的注意事项有哪些,下面就是实战案例,一起来看一下。

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

一.概览

先看最后的调用方式

props $emit方式

<chat-modal ref="chat-modal" v-model="showModal" cancelText="取消" sureText="确认" title="弹窗标题" small @on-ok="onOK" @on-cancel="onCancel">
  <p>slot的东西,想向弹窗中添加自定义的内容</p>
</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>
  <p>
    <p class="shadow" v-show="showModal"></p>
    <p class="modal" :class="{&#39;smSize&#39;: otherText.small || small}" v-show="showModal">
      <p class="header">{{ otherText.title || title}}</p>
      <p class="body">
        <slot></slot>
      </p>
      <p class="footer">
        <p class="item success" id="sure" ref="sure" @click="makeSure" v-show="otherText.sureText || sureText">{{ otherText.sureText || sureText }}</p>
        <p class="item red" id="cancel" ref="cancel" @click="makeCancel" v-show="otherText.cancelText || cancelText">{{ otherText.cancelText || cancelText }}</p>
      </p>
    </p>
  </p>
</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();
登录后复制

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

如何使用Vue内父子组件通讯todolist组件

如何使用Vue整合AdminLTE模板

以上是如何使用v-model与promise两种方式实现vue弹窗组件的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Vue中如何使用v-model.number实现输入框的数据类型转换 Vue中如何使用v-model.number实现输入框的数据类型转换 Jun 11, 2023 am 08:54 AM

在Vue中,v-model是用来实现双向绑定的一个重要指令,它可以让我们很方便地将用户输入的内容同步到Vue的data属性中。但是在一些情况下,我们需要对数据进行转换,比如将用户输入的字符串类型转换成数字类型,这时候就需要使用v-model的.number修饰符来实现。v-model.number的基本用法v-model.number是v-model的一个修

言出必行:兑现承诺的好处和坏处 言出必行:兑现承诺的好处和坏处 Feb 18, 2024 pm 08:06 PM

在日常生活中,我们常常会遇到承诺与兑现之间的问题。无论是在个人关系中,还是在商业交易中,承诺的兑现都是建立信任的关键。然而,承诺的利与弊也常常会引起争议。本文将探讨承诺的利与弊,并给出一些建议,如何做到言出必行。承诺的利是显而易见的。首先,承诺可以建立信任。当一个人信守承诺时,他会让别人相信自己是一个可信赖的人。信任是人与人之间建立起的纽带,它可以让人们更加

在Vue应用中遇到Uncaught (in promise) TypeError怎么办? 在Vue应用中遇到Uncaught (in promise) TypeError怎么办? Jun 25, 2023 pm 06:39 PM

Vue是一款流行的前端框架,在开发应用时经常会遇到各种各样的错误和问题。其中,Uncaught(inpromise)TypeError是常见的一种错误类型。在本篇文章中,我们将探讨它的产生原因和解决方法。什么是Uncaught(inpromise)TypeError?Uncaught(inpromise)TypeError错误通常出现在

深入了解Promise.resolve() 深入了解Promise.resolve() Feb 18, 2024 pm 07:13 PM

Promise.resolve()详解,需要具体代码示例Promise是JavaScript中一种用于处理异步操作的机制。在实际开发中,经常需要处理一些需要按顺序执行的异步任务,而Promise.resolve()方法就是用来返回一个已经Fulfilled状态的Promise对象。Promise.resolve()是Promise类的一个静态方法,它接受一个

解决Vue报错:无法使用v-model进行双向数据绑定 解决Vue报错:无法使用v-model进行双向数据绑定 Aug 25, 2023 pm 04:49 PM

解决Vue报错:无法使用v-model进行双向数据绑定在使用Vue进行开发时,经常会使用v-model指令来实现双向数据绑定,但有时候我们会遇到一个问题,就是在使用v-model时会报错,无法正确进行双向数据绑定。这可能是由于一些常见的错误导致的,下面我将介绍几种常见的情况以及相应的解决方法。组件的props属性未正确设置当我们在使用组件时,如果需要通过v-

Vue报错:无法正确使用v-model进行双向数据绑定,如何解决? Vue报错:无法正确使用v-model进行双向数据绑定,如何解决? Aug 19, 2023 pm 08:46 PM

Vue报错:无法正确使用v-model进行双向数据绑定,如何解决?引言:在使用Vue进行开发时,双向数据绑定是一项非常常见且强大的功能。然而,有时候我们可能会遇到一个问题,就是当我们尝试使用v-model进行双向数据绑定时,却遭遇到了报错。本文将介绍该问题的原因以及解决方案,并通过代码示例来演示如何解决该问题。问题描述:当我们在Vue中尝试使用v-model

Vue中使用v-model的双向绑定优化应用的数据性能 Vue中使用v-model的双向绑定优化应用的数据性能 Jul 17, 2023 pm 07:57 PM

Vue中使用v-model的双向绑定优化应用的数据性能在Vue中,我们经常使用v-model指令来实现表单元素与数据之间的双向绑定。这种双向绑定的方式极大地简化了开发过程,并提高了用户体验。然而,由于v-model需要监听表单元素的input事件,当数据量较大时,这种双向绑定可能会带来一定的性能问题。本文将介绍如何优化使用v-model时的数据性能,并提供一

实例解析ES6 Promise的原理和使用 实例解析ES6 Promise的原理和使用 Aug 09, 2022 pm 03:49 PM

利用Promise对象,把普通函数改成返回Promise的形式,解决回调地狱的问题。明白Promise的成功失败调用逻辑,可以灵活的进行调整。理解核心知识,先用起来,慢慢整合吸收知识。

See all articles