情不知从何起,一往而情深
排名
6
文章
199
粉丝
4
评论
3
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术

开发一个简单的 Vue 弹窗组件。Vue实现弹窗

4375人阅读 2023/3/23 14:30 总访问:1110466 评论:0 收藏:1 手机
分类: 前端

一个弹窗组件通常包含两个部分,分别是遮罩层和内容层。

遮罩层是背景层,一般是半透明或不透明的黑色。

内容层是放我们要展示的内容的容器。

  1. <template>
  2. <div class="modal-bg" v-show="show">
  3. <div class="modal-container">
  4. <div class="modal-header">
  5. {{ title }}
  6. </div>
  7. <div class="modal-main">
  8. <slot></slot>
  9. </div>
  10. <div class="modal-footer">
  11. <button @click="hideModal">取消</button>
  12. <button @click="submit">确认</button>
  13. </div>
  14. </div>
  15. </div>
  16. </template>

现在弹窗组件的结构已经搭建出来了。

  • 类 modal-bg: 遮罩层
  • 类 modal-container: 内容层容器
  • 类 modal-header: 内容层头部
  • 类 modal-main: 内容层主体部分(用来展示内容)
  • 类 modal-footer: 内容层脚部
  • 属性 v-show: 控制弹窗的展示与关闭
  • 属性 title: 标题
  • 方法 hideModal: 点击取消的回调函数
  • 方法 submit: 点击确认的回调函数
  • 插槽 slot: 用来展示内容

定义完 HTML 结构,还得定义组件的 props 属性,用来接收父组件的传参,以方便在父组件通过属性来控制弹窗。

  1. export default {
  2. name: 'modal',
  3. props: {
  4. show: {
  5. type: Boolean,
  6. default: false
  7. },
  8. title: {
  9. type: String,
  10. default: ''
  11. },
  12. },
  13. methods: {
  14. hideModal() {
  15. this.$emit('hideModal')
  16. },
  17. submit() {
  18. this.$emit('submit')
  19. },
  20. }
  21. }

从上述代码可知,组件只有两个 prop 属性,分别是 show(控制弹窗展示与关闭)和 title(弹窗标题)。 另外还有两个方法,分别是点击取消和确认的回调函数,它们的作用是触发对应的事件。 到这里,一个简单的弹窗组件已经完成了(样式后面再说)。

如何调用

一个组件写完了,要怎么调用呢?

假设这个组件的文件名为 Modal.vue,我们在父组件里这样调用 (假设父组件和弹窗组件在同一文件夹下)。

  1. <Modal :show="show" :title="title" @hideModal="hideModal" @submit="submit">
  2. <p>这里放弹窗的内容</p>
  3. </Modal>
  1. import Modal from './Modal.vue'
  2. export default {
  3. data() {
  4. return {
  5. title: '弹窗标题',
  6. show: true,
  7. }
  8. },
  9. components: {
  10. Modal
  11. },
  12. methods: {
  13. hideModal() {
  14. // 取消弹窗回调
  15. this.show = false
  16. },
  17. submit() {
  18. // 确认弹窗回调
  19. this.show = false
  20. }
  21. }
  22. }

把子组件要求的两个属性和两个方法都写上,一个简单的弹窗组件就这样完成了。

改进

样式

现在市面上的 UI 库特别多,所以一些通用的组件样式不建议自己写,直接用现成的就好。在这个组件上,我们可以使用 element-ui,改造后变成这样。

  1. <template>
  2. <div class="modal-bg" v-show="show">
  3. <div class="modal-container">
  4. <div class="modal-header">
  5. {{ title }}
  6. </div>
  7. <div class="modal-main">
  8. <slot></slot>
  9. </div>
  10. <div class="modal-footer">
  11. <el-button round @click="hideModal">取消</el-button>
  12. <el-button type="primary" round @click="submit">确认</el-button>
  13. </div>
  14. </div>
  15. </div>
  16. </template>

嗯… 看起来只有两个按钮变化了,不过没关系,后面的内容部分肯定还有用得上的时候。

功能

看起来这个简单的弹窗组件真的是非常简单,我们可以在此基础上适当的增加一些功能,例如:拖拽。

一个弹窗组件的拖拽一般通过三个事件来控制,分别是 mousedown、mousemove、mouseup。

  • mousedown 用来获取鼠标点击时弹窗的坐标
  • mousemove 用来计算鼠标移动时弹窗的坐标
  • mouseup 取消弹窗的移动

先来看代码。

  1. <template>
  2. <div class="modal-bg" v-show="show" @mousemove="modalMove" @mouseup="cancelMove">
  3. <div class="modal-container" :class="position">
  4. <div class="modal-header" @mousedown="setStartingPoint">
  5. {{ title }}
  6. </div>
  7. <div class="modal-main">
  8. <slot></slot>
  9. </div>
  10. <div class="modal-footer">
  11. <el-button round @click="hideModal">取消</el-button>
  12. <el-button type="primary" round @click="submit">确认</el-button>
  13. </div>
  14. </div>
  15. </div>
  16. </template>

在弹窗上增加了三个事件 mousedown、mousemove、mouseup,用来控制弹窗移动(点击弹窗头部进行拖拽)。

  1. data() {
  2. return {
  3. x: 0, // 弹窗 X 坐标
  4. y: 0, // 弹窗 Y 坐标
  5. node: null, // 弹窗元素
  6. isCanMove: false // 是否能拖动弹窗
  7. }
  8. },
  9. mounted() {
  10. // 将弹窗元素赋值给 node
  11. this.node = document.querySelector('.modal-container')
  12. },
  13. setStartingPoint(e) {
  14. this.x = e.clientX - this.node.offsetLeft
  15. this.y = e.clientY - this.node.offsetTop
  16. this.isCanMove = true
  17. },
  18. modalMove(e) {
  19. if (this.isCanMove) {
  20. this.node.style.left = e.clientX - this.x + 'px'
  21. this.node.style.top = e.clientY - this.y + 'px'
  22. }
  23. },
  24. cancelMove() {
  25. this.isCanMove = false
  26. }

通过这些新增的代码,这个弹窗就具有了拖拽的功能。

最后附上这个弹窗组件的完整代码

  1. <template>
  2. <div class="modal-bg" v-show="show" @mousemove="modalMove" @mouseup="cancelMove">
  3. <div class="modal-container">
  4. <div class="modal-header" @mousedown="setStartingPoint">
  5. {{ title }}
  6. </div>
  7. <div class="modal-main">
  8. <slot></slot>
  9. </div>
  10. <div class="modal-footer">
  11. <el-button round @click="hideModal">取消</el-button>
  12. <el-button type="primary" round @click="submit">确认</el-button>
  13. </div>
  14. </div>
  15. </div>
  16. </template>
  1. <script>
  2. export default {
  3. name: 'modal',
  4. props: {
  5. show: {
  6. type: Boolean,
  7. default: false
  8. },
  9. title: {
  10. type: String,
  11. default: ''
  12. },
  13. },
  14. data() {
  15. return {
  16. x: 0,
  17. y: 0,
  18. node: null,
  19. isCanMove: false
  20. }
  21. },
  22. mounted() {
  23. this.node = document.querySelector('.modal-container')
  24. },
  25. methods: {
  26. hideModal() {
  27. this.$emit('hideModal')
  28. },
  29. submit() {
  30. this.$emit('submit')
  31. },
  32. setStartingPoint(e) {
  33. this.x = e.clientX - this.node.offsetLeft
  34. this.y = e.clientY - this.node.offsetTop
  35. this.isCanMove = true
  36. },
  37. modalMove(e) {
  38. if (this.isCanMove) {
  39. this.node.style.left = e.clientX - this.x + 'px'
  40. this.node.style.top = e.clientY - this.y + 'px'
  41. }
  42. },
  43. cancelMove() {
  44. this.isCanMove = false
  45. }
  46. }
  47. }
  48. </script>
  1. <style scoped>
  2. .modal-bg {
  3. position: fixed;
  4. top: 0;
  5. left: 0;
  6. width: 100%;
  7. height: 100%;
  8. background: rgba(0,0,0,.5);
  9. z-index: 10;
  10. }
  11. .modal-container {
  12. background: #fff;
  13. border-radius: 10px;
  14. overflow: hidden;
  15. position: fixed;
  16. top: 50%;
  17. left: 50%;
  18. transform: translate(-50%,-50%);
  19. }
  20. .modal-header {
  21. height: 56px;
  22. background: #409EFF;
  23. color: #fff;
  24. display: flex;
  25. align-items: center;
  26. justify-content: center;
  27. cursor: move;
  28. }
  29. .modal-footer {
  30. display: flex;
  31. align-items: center;
  32. justify-content: center;
  33. height: 57px;
  34. border-top: 1px solid #ddd;
  35. }
  36. .modal-footer button {
  37. width: 100px;
  38. }
  39. .modal-main {
  40. padding: 15px 40px;
  41. }
  42. </style>

原文:https://blog.csdn.net/weixin_42176612/article/details/112264679

如果弹窗打开关闭需要有一点淡入谈出的动画

可以在外面包括一层transition组件

  1. <template>
  2. <transition name="fade">
  3. <div class="modal-bg" v-show="show" @mousedown="setStartingPoint" @mousemove="modalMove" @mouseup="cancelMove">
  4. <div class="modal-container">
  5. <!-- <div class="modal-header" @mousedown="setStartingPoint">
  6. {{ title }}
  7. </div> -->
  8. <div class="header_wrap">
  9. 2022级计算机1班
  10. <img :src="require('@/assets/img/close.png')" @click="$emit('closemodal')"
  11. style="height: 13px;width: 13px;cursor: pointer;position:absolute;right: 13px;top:13px" alt="">
  12. </div>
  13. <div class="modal-main">
  14. <slot></slot>
  15. </div>
  16. <!-- <div class="modal-footer">
  17. <el-button round @click="hideModal">取消</el-button>
  18. <el-button type="primary" round @click="submit">确认</el-button>
  19. </div> -->
  20. </div>
  21. </div>
  22. </transition>
  23. </template>

然后在写一点样式即可

  1. // 写一点淡入谈出的动画试试
  2. .fade-leave, // 离开前,进入后透明度是1
  3. .fade-enter-to {
  4. opacity: 1;
  5. }
  6. .fade-leave-active,
  7. .fade-enter-active {
  8. transition: all 1s; //过度时间
  9. }
  10. .fade-leave-to,
  11. .fade-enter {
  12. opacity: 0;
  13. }

在有滚动条的情况下垂直居中

参考:https://blog.csdn.net/rinima6114/article/details/17596019

当然如果是在大屏那种按比例自适的,其实偏移值按照比例写死就行了,不用动态计算,按比例自适其实就是动态计算了,所以偏移量就设置固定的值就行了,那个比例会自动计算在不同分辨率下的扩大缩小比例。


欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739。有需要软件开发,或者学习软件技术的朋友可以和我联系~(Q:815170684)

评价

Vue.js+Layer实现表格数据绑定与更新

一:使用Vue.js绑定好数据与更新事件 使用v-on绑定好事件,在事件里边直接把该行数据传递进去,在更新方法里边就可以直接...

Vue.js 实现省市联动

HTML代码&lt;divid=&quot;pro_citys&quot;&gt; 省:&lt;selectid=&quot;provice&quot;v-on:change=&quot;prochange()&quo...

Vue.js常见问题

一:花括号当做字符串显示的问题1:检查下绑定到vue.js的id是否重复,如果id重复了,就有可能存在这种问题,因为有可能把数...

Vue.js常用指令

v-html可以把字符串当成一个html来渲染,而不是原样输出Html类似.net mvc中的@Html.Raw()方法&lt;divv-html=&quot;item.tit...

干货!div滚动到一定位置就固定他。Vue中实现一侧滚动到底部就固定

尊重原创:转载请注名出处div滚动到一定位置就固定他,例如左边的内容很多,右边的内容很少,如果不处理滚动到一定位置后右...

Vue.js常用指令,事件绑定等,Vue过滤器解析状态过滤器多个参数。Vue表格状态解析。Vue解析类型,element ui解析类型,状态,el-tag

按照html的编码显示:v-html&lt;div class=&quot;font_info&quot; v-html=&quot;item.Content&quot;&gt;{{item.Content}}&l...

Vue.js if用法

vue.js if可以做一些判断例如我们要把下面这个输出varvm=newVue({ el:&quot;#content&quot;, data:{ titles:[&quot;小明...

Vue.js 学习日记第一章-安装Vue开发环境

官网:https://cn.vuejs.org/v2/guide/ 这是一篇学习性文章,不定时更新,用来记录我学习vue.js的过程。 首先,是v...

Vue.js 学习日记第二章-在Vue中编写function及一些简单指令

官网:https://cn.vuejs.org/v2/guide/ vue.js 学习日记第一章:http://www.tnblog.net/18323015640/article/details/2...

Vue.js 学习日记第三章-Vue中的简单事件及事件修饰符

官网:https://cn.vuejs.org/v2/guide/ vue.js 学习日记第二章:http://www.tnblog.net/18323015640/article/details/2...

Vue.js 学习日记第四章-Vue中文本框数据获取与绑定及computed计算属性

官网:https://cn.vuejs.org/v2/guide/ vue.js学习日记第三章: http://www.tnblog.net/18323015640/article/details/2...

Vue.js 学习日记第五章-v-if和v-for指令的使用方式

官网:https://cn.vuejs.org/v2/guide/ vue.js学习日记第四章: http://www.tnblog.net/18323015640/article/details/2...

Vue.js 学习日记第六章-Vue组件初步学习

官网:https://cn.vuejs.org/v2/guide/ vue.js学习日记第五章: http://www.tnblog.net/18323015640/article/details/2...

Vue.js学习日记第七章-搭建脚手架

官网:https://cn.vuejs.org/v2/guide/ vue.js学习日记第六章: http://www.tnblog.net/18323015640/article/details/2...

Vue实现好友选中效果

逛过vue官网肯定会发现一个有趣的指令“v-for”,相比与以前拼接html代码确实要上档次一点,而且减少了工作量,先看一波效...