当前位置:   article > 正文

Vue封装一个Dialog(对话框)组件_vue 手动实现dialog

vue 手动实现dialog

前几天被人问到过,当时挺懵的,回来看了看,发现原来是这样做的

效果图如下,只实现了一个最基本的,可以传入属性,也可以使用方法,后续需要什么,再往里面加

  主要是通过v-model控制对话框的显示和隐藏,实现父子组件的双向数据绑定

  • v-model用在组件上,默认绑定的值为modelValue,相当于v-model:modelValue。当然也可以自定义值
  • 父组件中子组件标签里的内容,子组件用插槽进行接收

父组件

  1. <template>
  2. <div class="dialog">
  3. <button @click.stop="showModel">显示对话框 -- {{ show }}</button>
  4. <Diglog
  5. v-model="show"
  6. :title="title"
  7. @open="handleOpen"
  8. @close="handleClose"
  9. >
  10. <p>插槽内容</p>
  11. <template #footer>
  12. <span>
  13. <button @click="show = false">确定</button>
  14. <button @click="show = false">取消</button>
  15. </span>
  16. </template>
  17. </Diglog>
  18. </div>
  19. </template>
  20. <script setup>
  21. import { ref } from 'vue'
  22. import Diglog from './components/Diglog.vue'
  23. // 控制对话框显示/隐藏
  24. let show = ref(false)
  25. // 窗口标题
  26. let title = ref('标题呀')
  27. const showModel = () => {
  28. show.value = true
  29. }
  30. const handleOpen = (a) => {
  31. console.log('打开了' + '默认参数为' + a)
  32. }
  33. const handleClose = (a) => {
  34. console.log('关闭了' + '默认参数为' + a)
  35. }
  36. </script>

子组件

  1. <template>
  2. <div class="box" ref="box" v-show="props.modelValue">
  3. <i class="close" @click="closeModel">X</i>
  4. <h3 class="title">{{ props.title }}</h3>
  5. <slot>插槽备用内容1</slot>
  6. <footer class="footer">
  7. <slot name="footer">插槽备用内容2</slot>
  8. </footer>
  9. </div>
  10. </template>
  11. <script setup>
  12. import { defineProps, defineEmits, ref, watch } from 'vue'
  13. const props = defineProps({
  14. modelValue: {
  15. type: Boolean,
  16. default: false,
  17. },
  18. title: {
  19. type: String,
  20. default: '',
  21. },
  22. })
  23. let box = ref(null)
  24. const emits = defineEmits(['update:modelValue', 'open', 'close'])
  25. document.addEventListener('click', function (e) {
  26. if (!box.value.contains(e.target)) {
  27. emits('update:modelValue', false)
  28. }
  29. })
  30. const closeModel = () => {
  31. emits('update:modelValue', false)
  32. }
  33. watch(
  34. // 这种写法会侦听到 props 中 test 的变化
  35. () => props.modelValue,
  36. (newValue) => {
  37. // 打开了
  38. if (newValue === true) {
  39. emits('open', '随便传个参数吧1')
  40. }
  41. // 关闭了
  42. if (newValue === false) {
  43. emits('close', '随便传个参数吧2')
  44. }
  45. }
  46. )
  47. </script>
  48. <style scoped>
  49. .box {
  50. position: relative;
  51. width: 500px;
  52. height: 300px;
  53. background-color: pink;
  54. margin: auto;
  55. }
  56. .title {
  57. text-align: center;
  58. height: 30px;
  59. background: skyblue;
  60. }
  61. .close {
  62. display: block;
  63. position: absolute;
  64. top: 0;
  65. right: 0;
  66. width: 30px;
  67. text-align: center;
  68. line-height: 30px;
  69. background-color: #ccc;
  70. cursor: pointer;
  71. }
  72. .footer {
  73. position: absolute;
  74. bottom: 0;
  75. right: 0;
  76. }
  77. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/761366
推荐阅读
相关标签
  

闽ICP备14008679号