Vue.js如何直接在js中引用并调用组件
分类:Javascript 浏览:77 时间:2020-03-15 17:57

如何像Element中的Notification通知组件一样在js代码中就能调用显示呢,项目改造使用了vuetify组件但是它的Notification组件没有提供js api所以只能自己撸一个了。

直接看Element Notification组件的源码,照葫芦画瓢,它可以我就可以。

QQ截图20200315173602.png

发现源码中定义了两个文件,一个是js一个是vue的模板,模板文件自然不用多说,关键就在于这个main.js。

import Main from './main.vue';
const NotificationConstructor = Vue.extend(Main);

//省略若干行代码

instance = new NotificationConstructor({
  data: options
});

if (isVNode(options.message)) {
  instance.$slots.default = [options.message];
  options.message = 'REPLACED_BY_VNODE';
}
instance.id = id;
instance.$mount();
document.body.appendChild(instance.$el);
instance.visible = true;
instance.dom = instance.$el;
instance.dom.style.zIndex = PopupManager.nextZIndex();

阅读源码发现实现步骤如下:

1、导入模板文件然后使用Vue.extend继承得到子类NotificationConstructor;

2、创建一个NotificationConstructor的一个实例(完整的Vue实例,可以调用生命的方法,访问data中的属性等...),instance;

3、instance调用$mount()手动挂载;

4、将$el放到body上就可以显示了。


最后实现基于vuetify的Notification组件,源码如下:

1、vue组件

<template>
  <v-snackbar v-model="snackbar" top vertical :color="color" :timeout="5000">
    <div class="snackbar-content">{{ message }}</div>
    <v-btn text @click="snackbar = false" class="snackbar-close-btn">
      关闭
    </v-btn>
  </v-snackbar>
</template>

<script>
export default {
  name: "notification",
  data() {
    return {
      snackbar: false,
      status: "",
      message: "",
      onClose: () => {}
    };
  },
  computed: {
    color() {
      let color;
      //下面的bg-success样式需要自己提供,vuetify没有提供对应的样式
      switch (this.code) {
        case "ok":
          color = "bg-success";
          break;
        case "fail":
          color = "bg-error";
          break;
        case "error":
          color = "bg-error";
          break;
        case "warning":
          color = "bg-warning";
          break;
        case "forbidden":
          color = "bg-warning";
          break;
        case "missing":
          color = "bg-warning";
          break;
        case "invalid":
          color = "bg-error";
          break;
        default:
          color = "bg-default";
      }
      return color;
    }
  },
  watch: {
    snackbar(currVal) {
      if (!currVal && typeof this.onClose === "function") {
        this.onClose();
      }
    }
  },
  methods: {
    setOptions(options) {
      this.snackbar = true;
      this.status= options.status;
      this.message = options.message;
      this.onClose = options.onClose;
    }
  }
};
</script>

<style scoped>
.snackbar-content {
  word-break: break-all;
}
.snackbar-close-btn {
  margin-top: 0 !important;
}
</style>

2、我这里并没有像element一样使用多实例显示,我只使用了一个实例(多次调用页面上也只会显示一个消息框)

import Vue from "vue";
import Index from "./index.vue";

const NotificationConstructor = Vue.extend(Index);

let instance = new NotificationConstructor();
instance.$mount();
document.body.appendChild(instance.$el);
instance.visible = true;
instance.dom = instance.$el;

const Notification = function(options) {
  options = options || {};
  instance.setOptions(options);
};

//快捷调用方法
["ok", "fail", "error", "warning", "forbidden", "missing", "invalid"].forEach(
  code => {
    Notification[code] = (options, onClose) => {
      if (typeof options === "string") {
        options = {
          message: options,
          onClose: onClose
        };
      }
      options.code = code;
      return Notification(options);
    };
  }
);

export default Notification;

3、在main.js中导入,并使用

import Notification from "@/components/notification";
Vue.prototype.$notify = Notification;

4、在其他vue组件中调用

this.$notify.ok("some message")
this.$notify.fail("some message")
this.$notify.missing("some message")
...

5、弄完后我想起了vue官网的一句话:“下图展示了实例的生命周期。你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高。"

lifecycle.png

奇巧淫技 Vue