当前位置:   article > 正文

基于Vue.js和Element UI框架的自定义对话框组件_vue聊天对话框

vue聊天对话框

一个基于Vue.js和Element UI框架的自定义对话框组件。这个组件名为biuDialog,封装了Element UI的el-dialog组件,并添加了一些自定义的功能和样式。

组件特点

  1. 自定义标题和底部:组件允许通过插槽(slots)来自定义对话框的标题和底部内容。如果没有提供自定义内容,它会使用默认的标题和底部按钮(取消和确定)。

  2. 控制显示和隐藏:通过visible属性来控制对话框的显示和隐藏。show计算属性与visible属性同步,当show改变时,会通过$emit通知父组件。

  3. 事件回调:提供了openopenedcloseclosed事件,以便在对话框打开或关闭时执行特定的逻辑。

  4. 关闭逻辑beforeClose方法允许在关闭对话框之前执行一些逻辑,例如确认操作。beforeClose2方法是一个快捷方式,它在用户点击关闭按钮时触发。

  5. 样式定制:通过customClass属性可以添加自定义样式。默认情况下,对话框有一个基础样式,可以通过SCSS样式部分进行修改。

组件属性

  • visible: 对话框是否可见。
  • title: 对话框标题。
  • appendToBody: 对话框是否插入到body元素上。
  • modal: 是否需要遮罩层。
  • fullscreen: 是否全屏。
  • destroyOnClose: 关闭时是否销毁对话框中的元素。
  • width: 对话框宽度。
  • top: 对话框距离顶部的距离。
  • customClass: 自定义类名。
  • showClose: 是否显示关闭按钮。
  • closeOnClickModal: 是否可以通过点击遮罩层关闭对话框。
  • beforeClose: 关闭前的回调函数。

组件方法

  • open: 触发open事件。
  • opened: 触发opened事件。
  • close: 触发close事件。
  • closed: 触发closed事件。
  • cancel: 触发cancel事件,通常用于取消操作。
  • submit: 触发submit事件,通常用于确认操作。

样式

样式使用了SCSS,并且是作用域化的,这意味着样式只应用于当前组件。对话框的头部和底部有特定的样式,可以通过修改这些样式来改变对话框的外观。

这个组件可以很容易地集成到使用Element UI的Vue.js项目中,为开发者提供了一个灵活且易于定制的对话框解决方案。

<template>
    <div class="biu-dialog-box">
      <el-dialog
        :custom-class="customClass"
        :title="$slots.title ? '' : title"
        :visible.sync="show"
        :width="width"
        :top="top"
        :append-to-body="appendToBody"
        :modal="modal"
        :fullscreen="fullscreen"
        :destroy-on-close="destroyOnClose"
        :modal-append-to-body="modalAppendToBody"
        :before-close="beforeClose"
        :close-on-click-modal="closeOnClickModal"
        :show-close="false"
        @open="open"
        @opened="opened"
        @close="close"
        @closed="closed"
      >
        <!-- 有写弹窗头部则采用输入的 -->
        <template v-if="$slots.title">
          <span slot="title">
            <slot name="title" />
          </span>
        </template>
        <!-- 自定义默认头部 -->
        <template v-if="!$slots.title">
          <div slot="title" class="biu-default-header-box">
            <div class="biu-default-header-title">{{ title }}</div>
            <div
              class="biu-default-header-close"
              @click="beforeClose2"
              v-if="showClose"
            >
              <span class="biu-icon-guanbi2">
               <i class="el-icon-circle-close"  style="font-size:16px"></i>
              </span>
            </div>
          </div>
        </template>
        <!-- 弹窗内容区域 -->
        <slot />
        <!-- 弹窗底部区域 -->
        <template v-if="$slots.footer">
          <span slot="footer">
            <slot name="footer" />
          </span>
        </template>
        <!-- 自定义默认头部 -->
        <template v-if="!$slots.footer">
          <div slot="footer" class="biu-default-header-box">
            <el-button class="btn" @click="cancel">取消</el-button>
            <el-button class="btn sure" @click="submit">确定</el-button>
          </div>
        </template>
      </el-dialog>
    </div>
  </template>
  
  <script>

  export default {
    name: "biuDialog",
    props: {
      visible: {
        type: Boolean,
        default: false,
      },
      title: {
        type: String,
        default: "提示",
      },
      appendToBody: {
        // Dialog 自身是否插入至 body 元素上。嵌套的 Dialog 必须指定该属性并赋值为 true
        type: Boolean,
        default: true,
      },
      modalAppendToBody: {
        // 遮罩层是否插入至 body 元素上,若为 false,则遮罩层会插入至 Dialog 的父元素上
        type: Boolean,
        default: true,
      },
      modal: {
        // 是否需要遮罩层
        type: Boolean,
        default: true,
      },
      fullscreen: {
        // 是否全屏
        type: Boolean,
        default: false,
      },
      destroyOnClose: {
        // 关闭时销毁 Dialog 中的元素
        type: Boolean,
        default: true,
      },
      width: {
        type: String,
        default: "30%",
      },
      top: {
        type: String,
        default: "15vh",
      },
      customClass: {
        type: String,
        default: "biu-dialog",
      },
      showClose: {
        type: Boolean,
        default: false,
      },
      closeOnClickModal: {
        type: Boolean,
        default: true,
      },
      beforeClose: {
        type: Function,
      },
    },
    computed: {
      show: {
        get() {
          return this.visible;
        },
        set(val) {
          this.$emit("update:visible", val); // visible 改变的时候通知父组件
        },
      },
    },
    data() {
      return {};
    },
    methods: {
      //点击自定义的关闭按钮
      beforeClose2() {
        this.beforeClose(() => {
          this.show = false;
        });
      },
      open() {
        // Dialog 打开的回调
        this.$emit("open");
      },
      opened() {
        // Dialog 打开动画结束时的回调
        this.$emit("opened");
      },
      close() {
        // Dialog 关闭的回调
        this.$emit("close");
      },
      closed() {
        // Dialog 关闭动画结束时的回调
        this.$emit("closed");
      },
      cancel() {
        this.$emit("cancel");
      },
      submit() {
        this.$emit("submit");
      },
    },
  };
  </script>
  
  <style scoped lang="scss">
  :deep(.el-dialog) {
    min-width: 320px;
    .el-dialog__header {
      padding: 0;
      color: #d37332;
      font-weight: 500;
      height: 50px;
      display: flex;
      flex-direction: column;
      justify-content: center;
      border-bottom: 2px solid #e9e8e8;
      font-size: 14px;
      .biu-default-header-box {
        padding: 0 20px;
        display: flex;
        line-height: 20px;
        .biu-default-header-title {
          flex: 1;
        }
        .biu-default-header-close {
          width: 15px;
          height: 15px;
          cursor: pointer;
        }
      }
    }
    .el-dialog__footer {
      padding: 0;
      text-align: center;
      height: 88px;
      border-top: 2px solid #e9e8e8;
      display: flex;
      justify-content: center;
      flex-direction: column;
      .btn {
        width: 120px;
        height: 40px;
        background: #e9e8e8;
        border-radius: 2px;
      }
      .sure {
        color: #ffffff;
        background: #de9a6c;
        margin-left: 66px;
      }
    }
  }
  </style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218

在使用biuDialog组件时,您可以通过Vue的插槽(slots)机制来自定义对话框的标题和底部。插槽允许您插入自定义的HTML、组件或者任何其他Vue实例,从而实现高度的灵活性和可定制性。

自定义标题

要自定义对话框的标题,您可以在组件实例中使用<slot>元素,并给它命名(在这个例子中是title)。例如:

<template>
  <biu-dialog :visible.sync="dialogVisible" title="我的对话框">
    <span slot="title">
      <h1 class="custom-title">这是自定义标题</h1>
    </span>
    <!-- 对话框的其他内容 -->
  </biu-dialog>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这个例子中,<span slot="title">定义了一个名为title的插槽,您可以在其中放置任何您想要的内容。biuDialog组件会检查是否有任何内容被插入到title插槽中,如果有,它将使用这些内容作为对话框的标题。

自定义底部

自定义对话框底部的方法与自定义标题类似。您需要在biuDialog组件中使用<slot>元素,并为其命名为footer。例如:

<template>
  <biu-dialog :visible.sync="dialogVisible" title="我的对话框">
    <!-- 对话框的内容 -->
    <span slot="footer">
      <el-button @click="handleCancel">取消</el-button>
      <el-button type="primary" @click="handleConfirm">确认</el-button>
    </span>
  </biu-dialog>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这个例子中,<span slot="footer">定义了一个名为footer的插槽,您可以在其中放置任何您想要的按钮或其他元素。当您需要不同的按钮或逻辑时,只需在插槽内容中进行更改即可。

注意事项

  • 确保您的自定义内容不会破坏对话框的布局或功能。
  • 如果您提供了自定义标题或底部,biuDialog组件将不会显示其默认的标题和底部。
  • 使用插槽时,您需要了解父组件和子组件之间的数据传递和事件触发机制,以确保您的自定义内容能够正确响应用户的交互。

如果希望弹框内容通过配置显示,而不是硬编码在模板中,可以采用以下方法:

使用组件的props传递配置

您可以在父组件中定义一些数据,这些数据将作为配置传递给biuDialog组件。然后,在biuDialog组件内部使用这些配置来动态渲染内容。

父组件示例
<template>
  <div>
    <!-- 触发弹框的按钮 -->
    <el-button @click="openDialog">打开对话框</el-button>

    <!-- 使用biuDialog组件 -->
    <biu-dialog
      :visible.sync="dialogVisible"
      :config="dialogConfig"
    >
    </biu-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dialogVisible: false,
      dialogConfig: {
        title: '配置标题',
        content: '这是通过配置显示的内容'
        // 可以添加更多配置项,如按钮文本、样式等
      }
    };
  },
  methods: {
    openDialog() {
      this.dialogVisible = true;
    }
  }
};
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

修改biuDialog组件以接收和使用配置

您需要在biuDialog组件中添加新的props来接收配置,并在组件的模板中使用这些配置来渲染内容。

biuDialog组件修改示例
export default {
  // ...
  props: {
    // ...
    config: {
      type: Object,
      default: () => ({
        title: '默认标题',
        content: '默认内容'
      })
    }
  },
  // ...
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

然后在模板中使用这些配置:

<template>
  <!-- ...其他代码... -->
  <div v-if="config.title" class="dialog-content">
    {{ config.content }}
  </div>
  <!-- ...其他代码... -->
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这个例子中,config对象包含了titlecontent属性,这些属性被用来动态渲染对话框的标题和内容。如果config对象中的属性不存在,您可以设置默认值或者不渲染相应的内容。

注意事项

  • 确保父组件传递的配置对象中的属性名称与子组件props中定义的名称相匹配。
  • biuDialog组件中,您可能需要根据配置的不同来决定是否渲染某些元素,或者如何渲染它们。
  • 如果配置项较多或者较为复杂,您可能需要在组件内部编写更多的逻辑来处理这些配置。

通过这种方式,可以使弹框内容更加灵活,根据需要轻松更改配置,而无需修改模板代码。

如果弹框内容是一个对象,且该对象包含多个元素,可以将这个对象作为配置传递给biuDialog组件。然后在组件内部,根据这个对象的结构动态渲染每个元素。

父组件示例

在父组件中,您可以定义一个对象,该对象包含了弹框需要显示的所有元素和配置。然后,通过props将这个对象传递给biuDialog组件。

<template>
  <div>
    <!-- 触发弹框的按钮 -->
    <el-button @click="openDialog">打开对话框</el-button>

    <!-- 使用biuDialog组件 -->
    <biu-dialog
      :visible.sync="dialogVisible"
      :dialog-content-object="contentObject"
    >
    </biu-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dialogVisible: false,
      contentObject: {
        title: '详细信息',
        elements: [
          { type: 'text', content: '这是一段文本。' },
          { type: 'image', src: 'path/to/image.jpg' },
          { type: 'button', text: '点击我', onClick: this.handleButtonClick }
          // 更多元素...
        ]
      },
      handleButtonClick() {
        // 处理按钮点击事件
        console.log('按钮被点击了!');
      }
    }
  },
  methods: {
    openDialog() {
      this.dialogVisible = true;
    }
  }
};
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

修改biuDialog组件以接收和使用对象配置

biuDialog组件中,您需要添加一个新的prop来接收父组件传递的对象,并在模板中遍历这个对象的elements数组,根据每个元素的type来决定如何渲染。

export default {
  // ...
  props: {
    // ...
    dialogContentObject: {
      type: Object,
      default: () => ({
        title: '',
        elements: []
      })
    }
  },
  // ...
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在模板中使用这个对象:

<template>
  <el-dialog
    :visible.sync="show"
    :custom-class="customClass"
    :title="config.title || dialogContentObject.title"
    @open="open"
    @opened="opened"
    @close="close"
    @closed="closed"
  >
    <!-- 遍历元素数组并渲染每个元素 -->
    <div v-for="element in dialogContentObject.elements" :key="element.type">
      <template v-if="element.type === 'text'">
        <p>{{ element.content }}</p>
      </template>
      <template v-if="element.type === 'image'">
        <img :src="element.src" alt="Image" />
      </template>
      <template v-if="element.type === 'button'">
        <el-button @click="element.onClick">{{ element.text }}</el-button>
      </template>
      <!-- 更多类型的条件渲染... -->
    </div>
  </el-dialog>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

在这个例子中,dialogContentObject对象包含了一个title和一个elements数组。elements数组中的每个元素都有一个type属性,用于指示应该渲染哪种类型的元素(如文本、图片、按钮等)。模板中的v-for指令用于遍历这些元素,并根据type属性使用v-ifv-else-if来决定渲染哪种模板。

注意事项

  • 确保父组件传递的对象结构与子组件中处理该对象的逻辑相匹配。
  • 在处理事件(如按钮点击)时,确保事件处理函数能够正确地从父组件传递到子组件,并且能够在子组件中被正确调用。
  • 如果元素类型未知或组件需要处理更多类型的元素,您可能需要扩展v-if/v-else-if条件渲染逻辑,以支持更多的元素类型。

这种方法使得弹框内容的渲染完全基于配置,提供了极高的灵活性和可扩展性。您可以根据需要轻松添加或修改配置对象中的元素,而无需更改组件的模板代码。

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/761372
推荐阅读
相关标签
  

闽ICP备14008679号