vue3封装出让后来者难以理解的组件,让不是大佬的你变得不再随时可替代

image.png

前言

害,最近两个月忙于工作和生活(明明就是给自己偷懒找借口),太久太久没更新文章了,正好趁着今天加班(摸鱼)来写一写最近在项目中封装的自以为很装的组件。在ui疯狂出图的前提条件下,我发现了很多轻提示和弹框dialog高度相似又要支持自定义,便开始了封装之路。

好孩子要学会先借鉴别人的作业

我在封装的第一版轻提示中,还是用的老传统props去接收一个visiable控制提示的显示和隐藏,归根结底还是不让组件一上来就挂载在dom节点上。组件写完了自然要使用不是吗,便高高兴兴的提交了代码。我自己在使用的过程中就感觉到很麻烦了,因为还要先引入组件,再定义一个visiable,再在template上写上一个<Toast :xxx=”xxx” xxxxxxx/>,再一个页面上如果出现多次调用的话,要么你就多写几个toast(不会吧,不会吧,应该没人会选择这么做吧),要么就疯狂的改变data中定义的数据。虽然自己已经发现了这个弊端,但是不偷懒的程序员不是一个好的程序员,还是选择忽视了这个问题,害,躲的了初一躲不了十五,第二天旁边的仙女同事(她自认为的嘻嘻嘻)就在不经意间吐槽了使用起来过于复杂,完全没有element的好用。内心os:我要是能写的和element差不多就不坐在这了。当然,有其他人也提出了和我相同的问题,那自然要去解决不是吗。

熟练的打开element ui翻到MessageBox组件哪里(此时的我还没意识到自己的项目是vue3环境),发现他们的调用方法也太简单了吧:


<template>

<el-button type="text" @click="open">点击打开 Message Box</el-button>

</template>

<script>
export default {
  methods: {
    open() {
      this.$alert('这是一段内容', '标题名称', {
        confirmButtonText: '确定',
        callback: action => {
          this.$message({
            type: 'info',
            message: `action: ${ action }`
          });
        }
      });
    }
  }
}
</script>

<style>

</style>

 

再看看自己的代码,简直不能看哈哈哈。古人云:师夷长技以制夷。打开自己开的vue2项目,打开庞大的node_modules包,找到对应的代码开始借鉴。

第一步,先写好要展示的页面。

工欲善其事,必先利其器。我们要想组件能使用,自然少不了我们的页面,我们写个demo演示一下:

<template>
  <div>测试{{booo}}</div>
</template>

<script>
export default {
  data() {
    return {
      visiable: false
    };
  }
};
</script>

<style></style>

 

可能有小伙伴会问我写的visiable是干啥的,前面不是才说这个东西会抛弃掉吗?嘿嘿嘿,这里写只是单纯的为了后面测试用的,没有实际作用哈。

第二步,使用vue构造器创造“子类”

在翻阅官方文档过程中,我们可以得知vue.extend(options)中的options必须是一个组件,也就是我们前面写的demo,有一点必须要知道的是data必须是一个函数,不过,我相信小伙伴们肯定一直写的都是函数。又因为我们extend创建的不是平常我们写的组件实例,所以不能使用new Vue({ components: test }),这里官方为我们提供了挂在到节点的方法$mount。千说万说不如直接上代码靠谱。

import Vue from "vue";
import Main from "./main.vue";
const MessageConstructor = Vue.extend(Main);
let instance;
const Message = function(options) {
  if (Vue.prototype.$isServer) {
    return;
  }
  console.log(Vue.prototype.$isServer);
  options = options || {};
  instance = new MessageConstructor({
    data: options
  });
  instance.$mount();
  document.body.appendChild(instance.$el);
  console.log(instance.visiable);
  console.log(instance.booo);
  return instance;
};
export default Message;
 

在看完代码中,可能会有部分小伙伴会问Vue.prototype.$isServer是什么,说实话,在没看文档前我也不会哈哈哈。

image.png

通过文档中可以知道这是判断是否运行在服务器上,我们在服务器上又没有界面自然不需要了。当我们调用方法的时候可以将参数正常传递进来就需要在new构造器的时候接受参数,然后再挂载在$mount上,最后插入到我们的body上.

第三步,收获成果调用方法

我们前面的准备工作都做完之后先别着急,怎么会这么容易就让我们可以使用了呢。我们还需要在最外面的main.js导入我们写好的文件

import Vue from "vue";
import ElementUI from "element-ui";
import Message from "@/components/test/main";
import "element-ui/lib/theme-chalk/index.css";
import App from "./App.vue";

Vue.config.productionTip = false;
Vue.use(ElementUI);
// Vue.use(Message);
Vue.prototype.$Message = Message;
new Vue({
  render: h => h(App)
}).$mount("#app");
 

这样我们就可以正常使用啦。

 mounted() {
    setTimeout(() => {
      this.$Message({
        booo: true
      });
    }, 3000);
  },
 

image.png

看到这里有人会问这个booo哪里来的,为什么在组件中没有props去接收参数也可以显示,这个就是构造器特殊的地方哈。

开始在正式项目中使用

有了前面的铺垫,我自然兴致冲冲的把自己的思路在项目中实践,突然想到自己之前挖的坑项目使用的是vue3,不确定之前写的还可不可以,先放上去试试。果然不出意外的报错了。翻看vue3文档,因为现在不能直接import Vue from “vue”;了,所以对应的vue.extend()也没有了。虽然官方删除了extend但是也提供了新的createApp给我们使用。

image.png

最后改造完的代码如下:

import { createApp } from "vue";
import ToastMessage from "./index.vue";

const createMount = options => {
  const mountNode = document.createElement("div");
  document.body.appendChild(mountNode);

  const app = createApp(ToastMessage, {
    ...options,
    remove() {
      app.unmount(mountNode);
      document.body.removeChild(mountNode);
    }
  });
  return app.mount(mountNode);
};

const toast = options => {
  return createMount(options);
};

toast.install = app => {
  app.component("Toast", ToastMessage);
  app.config.globalProperties.$toast = toast;
};

export default toast;
 

这里小伙伴们要注意了,在vue2中我们可以不用props接受数据也可以显示出来,但是vue3不行了哦。

后记

希望这篇文章能对大家有所帮助,如果有写的不对的地方也希望指点一二。

                                                            --wy白菜
 

原创文章,作者:我心飞翔,如若转载,请注明出处:https://www.pipipi.net/14685.html

发表评论

登录后才能评论