vue2中自定义MessageBox弹框、弹出复杂内容

🐳 引言


关于 MessageBox 弹框,Element UI 官方的介绍是:从场景上来说,MessageBox 的作用是美化系统自带的 alertconfirmprompt,因此适合展示较为简单的内容。如果需要弹出较为复杂的内容,请使用 Dialog。不过,MessageBox是可以自定义配置内容的,因此我想尝试使用 MessageBox 来展示复杂的内容,实现一个公共的全局弹框功能。

🐳 关于$createElement


$createElementVue 实例上的一个方法,用于创建虚拟节点 VNode$createElement 的功能非常强大,它为开发者提供了极大的灵活性。这里我们主要简要介绍一些常用的使用方法,了解其核心功能和应用场景。

1. 创建dom元素

首先,通过 $createElement 实现自定义配置内容,我希望将一个 list 数组中的内容渲染到 MessageBox 中。代码如下:

msgBox.vue 复制代码
<script>
export default {
  name: "msgBox",
  data() {
    return {
      list: [
        {
          date: "2016-05-02",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄"
        },
        {
          date: "2016-05-04",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1517 弄"
        },
        {
          date: "2016-05-01",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1519 弄"
        }
      ]
    };
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      const h = this.$createElement;
      this.$msgbox({
        title: "自定义弹框",
        showCancelButton: true,
        message: h("div", null, [
          this.list.map(item => {
            return h("div", { class: "msg-item" }, [
              h("div", null, item.name),
              h("div", null, item.date),
              h("div", null, item.address)
            ]);
          })
        ])
      });
    }
  }
};
</script>
<style lang="scss" scoped>
.msg-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 45px;
  padding: 10px;
}
</style>
2. 加载Element UI组件

上面我们仅演示了如何通过$createElement加载简单的dom元素,但现在我希望进一步利用$createElement来加载Element-UI中的组件。代码如下:

msgBox.vue 复制代码
<script>
import { Collapse } from "element-ui";
import { CollapseItem } from "element-ui";
export default {
  name: "msgBox",
  components: {
    Collapse,
    CollapseItem
  },
  data() {
    return {
      activeNames: ["1"],
      list: [
        {
          id: "1",
          title: "一致性 Consistency",
          content:
            "与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念 1"
        },
        {
          id: "2",
          title: "反馈 Feedback",
          content:
            "与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念 2"
        },
        {
          id: "3",
          title: "效率 Efficiency",
          content:
            "与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念 3"
        },
        {
          id: "4",
          title: "可控 Controllability",
          content:
            "与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念 4"
        }
      ]
    };
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      const h = this.$createElement;
      this.$msgbox({
        title: "自定义弹框",
        showCancelButton: true,
        message: h("div", null, [
          h(
            Collapse,
            {
              props: { value: this.activeNames },
              on: {
                change: this.handleChange
              }
            },
            [
              this.list.map(item => {
                return h(
                  CollapseItem,
                  {
                    props: {
                      name: item.id,
                      title: item.title
                    }
                  },
                  [h("div", null, [h("p", null, item.content)])]
                );
              })
            ]
          )
        ])
      });
    },
    handleChange(val) {
      console.log(val);
    }
  }
};
</script>
3. 加载自定义组件

如果采用上述方法来加载Element-UI中的组件显得过于繁琐,这并非我所期望的效果。既然$createElement能够用于加载组件,我们便可以在公共组件中编写代码,进而通过$createElement来加载这些自定义的公共组件。

创建一个公共组件,代码如下:

demo.vue 复制代码
<template>
  <div class="content">
    <el-collapse v-model="activeNames" @change="handleChange">
      <el-collapse-item
        v-for="item in list"
        :key="item.id"
        :title="item.title"
        :name="item.id"
      >
        <div>{{ item.content }}</div>
      </el-collapse-item>
    </el-collapse>
    <div>
      <div class="msg-item" v-for="item in list" :key="item.id">
        <div>{{ item.id }}</div>
        <div>{{ item.title }}</div>
        <div>{{ item.content }}</div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "demo",
  props: {
    initData: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    return {
      activeNames: ["1"],
      list: [
        {
          id: "1",
          title: "一致性 Consistency",
          content:
            "与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念 1"
        },
        {
          id: "2",
          title: "反馈 Feedback",
          content:
            "与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念 2"
        },
        {
          id: "3",
          title: "效率 Efficiency",
          content:
            "与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念 3"
        },
        {
          id: "4",
          title: "可控 Controllability",
          content:
            "与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念 4"
        }
      ]
    };
  },
  methods: {
    handleChange(val) {
      console.log(val);
    }
  }
};
</script>

<style lang="scss" scoped>
.content {
  width: 100%;
  height: 100%;
  padding: 10px;
  background: #fff;
  .msg-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 45px;
    padding: 10px;
  }
}
</style>

在MessageBox中使用公共组件,代码如下:

msgBox.vue 复制代码
<script>
import Demo from "./demo.vue";
export default {
  name: "msgBox",
  components: {
    Demo
  },
  data() {
    return {};
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      const h = this.$createElement;
      this.$msgbox({
        title: "自定义弹框",
        showCancelButton: true,
        message: h(Demo)
      });
    }
  }
};
</script>

🐳 封装自定义MessageBox


为了提升代码的复用性和开发效率,我计划将之前通过 $createElement 加载自定义公共组件的逻辑进行封装,将其转化为一个全局公共方法。通过这种方式,我们可以实现一个通用的全局弹框功能,从而在项目的任何地方轻松调用,避免重复代码,同时增强代码的可维护性和一致性。代码如下:

  1. 挂载全局方法,代码如下:
main.js 复制代码
Vue.prototype.msgBox = function(props) {
  const h = this.$createElement
  this.$msgbox({
    title: props.title || '提示',
    showCancelButton: props.showBtns || false,
    showConfirmButton: props.showBtns || false,
    closeOnClickModal: false,
    closeOnPressEscape: false,
    customClass: 'msg-container',
    message: h('div', { style: { height: props.height || 'auto', width: props.width || 'auto', overflow: 'auto' } }, [
      h(props.component, { props: { initData: { ...props.initData } } }) // 调用组件传入的值
    ])
  })
}
  1. 修改公共组件,代码如下:
demo.vue 复制代码
<template>
  <div class="content">
    <el-collapse v-model="initData.activeNames" @change="handleChange">
      <el-collapse-item
        v-for="item in list"
        :key="item.id"
        :title="item.title"
        :name="item.id"
      >
        <div>{{ item.content }}</div>
      </el-collapse-item>
    </el-collapse>
    <div>
      <div class="msg-item" v-for="item in list" :key="item.id">
        <div>{{ item.content }}</div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "demo",
  props: {
    initData: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    return {
      list: [
        {
          id: "1",
          title: "一致性 Consistency",
          content:
            "与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念 1"
        },
        {
          id: "2",
          title: "反馈 Feedback",
          content:
            "与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念 2"
        },
        {
          id: "3",
          title: "效率 Efficiency",
          content:
            "与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念 3"
        },
        {
          id: "4",
          title: "可控 Controllability",
          content:
            "与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念 4"
        }
      ]
    };
  },
  methods: {
    handleChange(val) {
      console.log(val);
    }
  }
};
</script>

<style lang="scss" scoped>
.content {
  width: 100%;
  height: 100%;
  background: #fff;
  .msg-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 45px;
    padding: 10px;
  }
}
</style>
  1. 在MessageBox中使用封装的全局函数,代码如下:
msgBox.vue 复制代码
<template> </template>
<script>
import Demo from "./demo.vue";
export default {
  name: "msgBox",
  components: {
    Demo
  },
  data() {
    return {
      activeNames: ["1"]
    };
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      this.msgBox({
        title: "自定义弹框",
        width: "600px",
        height: "400px",
        component: Demo,
        initData: {
          activeNames: this.activeNames
        }
      });
    }
  }
};
</script>
<style>
.msg-container {
  width: auto; /* 将最外层的宽度限制去掉 */
}
</style>

最终效果如下:

以上就是本次分享的全部内容。目前这里还只是一个初步的版本,并非最终的完整形态。我将在未来的分享中继续完善和补充更多细节,敬请期待!

🐳 文章小尾巴


感谢你看到最后,最后再说两点~

①如果你持有不同的看法,欢迎你在文章下方进行留言、评论。

②如果对你有帮助,或者你认可的话,欢迎给个小点赞,支持一下~
我是程序员张张,一个热爱编程也爱生活的程序员

(文章内容仅供学习参考,如有侵权,非常抱歉,请立即联系作者删除。)

相关推荐
LCG元3 小时前
Vue.js组件开发-如何使用day.js、luxon或date-fns处理日期时间
vue.js
随心Coding3 小时前
【零基础入门Go语言】struct 和 interface:Go语言是如何实现继承的?
前端·golang
金州饿霸4 小时前
YARN 架构组件及原理
linux·运维·前端
还这么多错误?!5 小时前
webpack打包要义
前端·webpack
小九九的爸爸5 小时前
浅谈ViewBox那些事(一)
前端·svg
ฅQSω[*邱╭5 小时前
写个自己的vue-cli
前端·javascript·vue.js·学习
阿芯爱编程5 小时前
typescript语法讲解
前端·javascript
Daniel_1875 小时前
Promise-课堂笔记
前端·javascript·笔记
一点一木5 小时前
TensorFlow.js 和 Brain.js 全面对比:哪款 JavaScript AI 库更适合你?
前端·javascript·人工智能
疯狂的沙粒5 小时前
如何更轻松的对React refs 的理解?都有哪些应用场景?
前端·react.js·前端框架