欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

element-ui的message组件实现机制解析

程序员文章站 2022-06-19 16:01:43
在element-ui的组件中,有些组件的用法看起来比较特别,如message组件。在注册完element组件后,一般的组件是这样用的:但是message组件则是这样使用的:...this.$message.success('保存成功');...这样就会在页面上弹出一个成功的消息提示框。那么这类组件是怎么实现的呢?我们简单来看一下。......

在element-ui的组件中,有些组件的用法看起来比较特别,如message组件,它不是像别的组件一样写在模板中,而是通过js的方式调用的。

在注册完element组件后,一般的组件是这样用的:

<template>
  <el-button>点击我</el-button>
</template>

但是message组件则是这样使用的:

...
this.$message.success('保存成功');
...

这样就会在页面上弹出一个成功的消息提示框。

那么这类组件是怎么实现的呢?

首先,我们打开node_modules下的element-ui文件夹,这里是element-ui库所在的位置。src/index.js是项目的入口文件,它内部定义了element-ui的安装方法install

const install = function(Vue, opts = {}) {
  ...
  // 注册普通组件
  components.forEach(component => {
    Vue.component(component.name, component);
  });
  ...
  // 注册需要用js调用的组件
  Vue.prototype.$loading = Loading.service;
  Vue.prototype.$msgbox = MessageBox;
  Vue.prototype.$alert = MessageBox.alert;
  Vue.prototype.$confirm = MessageBox.confirm;
  Vue.prototype.$prompt = MessageBox.prompt;
  Vue.prototype.$notify = Notification;
  Vue.prototype.$message = Message;
};

我们看到,所有可以使用js方法调用的组件都是使用Vue.prototype.$xxx = xxx的格式注册到Vue的原型对象上的。由于在Vue2.x中,根组件是Vue构造函数的实例,而Vue在创建子组件时,会把根组件的原型方法添加到子组件上。所以当上述代码执行之后,所有组件实例都可以通过原型链访问这些组件,也就是说:

let comp = new Vue();
comp.$message;  // Message

// 在子组件内
this.$message;  // Message

接着我们打开packages文件夹,来看Message的实现。找到element-ui/packages/message文件夹,先来看它的入口文件index.js

import Message from './src/main.js';
export default Message;

顺着找到这里引用的main.js(注意是当前目录下的src):

import Vue from 'vue';
import Main from './main.vue';
...
let MessageConstructor = Vue.extend(Main);
let instance;
...
const Message = function(options) {
  ...
  instance = new MessageConstructor({
    data: options
  });
  ...
  instance.$mount();
  document.body.appendChild(instance.$el);
}

['success', 'warning', 'info', 'error'].forEach(type => {
  Message[type] = options => {
    if (typeof options === 'string') {
      options = {
        message: options
      };
    }
    options.type = type;
    return Message(options);
  };
});

这里只列出了关键代码。首先导入Vue和Main,我们打开同目录下的Main.vue,可以看到这就是Message组件的实现,和我们平时写的组件没什么差别,这里不再讨论。

接着,使用Vue.extend全局方法创建了一个继承自Vue的构造函数MessageConstructor,以Main组件为参数。这样,当调用new MessageContructor时就会创建一个Message组件实例。

接下来就是Message构造函数的实现了。它会调用MessageContructor构造一个Message组件实例,不过由于没有挂载,它仅处于以下阶段:
element-ui的message组件实现机制解析
此时模板还没有被编译为渲染函数。紧接着调用它的$mount方法,现在instance就是一个被完全初始化的组件实例了。

注意,这里在调用$mount的时候并没有传入根节点el,所以组件被挂载后不会真正地渲染到某个DOM节点下面。最后一步,就是执行document.body.appendChild(instance.$el),把整个组件挂到DOM树上的body节点下,使其渲染到页面上。于是,消息组件就显示在页面上了。

为了方便,element-ui还专门为Message构造函数添加了四个静态方法:successwarninginfoerror

['success', 'warning', 'info', 'error'].forEach(type => {
  Message[type] = options => {
    if (typeof options === 'string') {
      options = {
        message: options
      };
    }
    options.type = type;
    return Message(options);
  };
});

现在Message.success就等价于Message(Object.assign(options, {type: 'success'}))

现在你就可以用下面的方式来调用Message组件了:

this.$message({type: 'success', message: '消息组件'});
this.$message.success('消息组件');
Vue.prototype.$message({type: 'success', message: '消息组件'});
Vue.prototype.$message.success('消息组件');

可能后面两种方法我们平时不常用,不过如果你想在Vuex中使用Message组件,很可能需要用到它:
messageModule.js

import Vue from 'vue';
const messageModule = {
  state () {
    ...
  },
  mutations: {
    setMessage (state, message) {
      Vue.prototype.$message('在Vuex中使用Message!');
    }
  }
}
export default messageModule;

这里如果使用this.$message是无法访问Message组件的。因为虽然Vuex的store本身也是一个Vue实例,但是它的每个module并不是Vue实例,并且Vuex在创建module的时候不会像Vue创建组件那样把根实例的属性都复制到每个module上,所以module实例的属性并不包含$message,因此也就无法调用Message组件。这时候通过直接引用Vue的原型对象,就可以直接访问到Message组件了。

本文地址:https://blog.csdn.net/qq_41694291/article/details/107500396

相关标签: vue