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>

最终效果如下:

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

🐳 文章小尾巴


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

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

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

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

相关推荐
江号软件分享4 分钟前
无接触服务的关键:二维码生成识别技术详解
前端
江号软件分享5 分钟前
如何利用取色器实现跨平台色彩一致性
前端
灰海9 分钟前
封装WebSocket
前端·网络·websocket·网络协议·vue
前端小巷子19 分钟前
深入理解TCP协议
前端·javascript·面试
万少20 分钟前
鸿蒙外包的十大生存法则
前端·后端·面试
顽疲34 分钟前
从零用java实现 小红书 springboot vue uniapp(13)模仿抖音视频切换
java·vue.js·spring boot
江号软件分享1 小时前
有效保障隐私,如何安全地擦除电脑上的敏感数据
前端
web守墓人2 小时前
【前端】ikun-markdown: 纯js实现markdown到富文本html的转换库
前端·javascript·html
Savior`L2 小时前
CSS知识复习5
前端·css
许白掰2 小时前
Linux入门篇学习——Linux 工具之 make 工具和 makefile 文件
linux·运维·服务器·前端·学习·编辑器