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

vue2.x挂载$mount函数的作用(有elementUI message联想)

程序员文章站 2024-03-05 11:23:12
...

文章参考

  1. vm.$mount( [elementOrSelector] )
  2. Vue renderless组件(函数式组件)

问题描述

  1. 在使用elementUI的时候,发现了 this.$message('这是一条消息提示'); 这个函数,觉得使用非常方法,不需要引用组件,直接调用方法
  2. 自己琢磨了一下,如果针对提示或者一些简单的UI界面,如果使用方法调用,大大提高使用效率,于是查看了源代码
  3. 是使用了 Vue函数式编程(类似于React的函数式组件写法),本质还是使用了vue文件(定义好了template界面和methods逻辑),然后继承该组件,通过方法实例化

vm.$mount 官方文档介绍

参数:

{Element | string} [elementOrSelector]
{boolean} [hydrating]
返回值:vm - 实例自身

用法:

  1. 如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。可以使用 vm.$mount() 手动地挂载一个**未挂载的实例**。
  2. 如果没有提供 elementOrSelector 参数,模板将被渲染为文档之外的的元素,并且你必须使用原生 DOM API 把它插入文档中
  3. 这个方法返回实例自身,因而可以链式调用其它实例方法。

不执行 $mount()方法,则Vue对象中的 $el 属性是没有的

示例:

var MyComponent = Vue.extend({
  template: '<div>Hello!</div>'
})

// 创建并挂载到 #app (会替换 #app)
new MyComponent().$mount('#app')

// 同上
new MyComponent({ el: '#app' })

// 或者,在文档之外渲染并且随后挂载
var component = new MyComponent().$mount()
document.getElementById('app').appendChild(component.$el)

elementUI 提供方法的源代码

import Vue from 'vue';
import { PopupManager } from 'hui/src/utils/popup';
import { isVNode } from 'hui/src/utils/vdom';
import MessageMain from './main.vue'; // 定义好 message 的组件界面和逻辑
// let MessageConstructor = Vue.extend(require('./main.vue'));
// 创建一个组件继承 message组件的配置
const MessageConstructor = Vue.extend(MessageMain); 

let instance;
const instances = [];
let seed = 1;

var Message = function(  ) {
  if (Vue.prototype.$isServer) return;
  options = options || {};
  if (typeof options === 'string') {
    options = {
      message: options
    };
  }
  const userOnClose = options.onClose;
  const id = 'message_' + seed++;

  options.onClose = function() {
    Message.close(id, userOnClose);
  };
  // 根据配置创建一个 message Vue对象 实例
  instance = new MessageConstructor({
    data: options
  });
  let verticalOffset = 0;
  instances.forEach(item => {
    verticalOffset += item.$el.offsetHeight + 16;
  });
  // 首个的位置为top:20px
  verticalOffset += 20;
  instance.verticalOffset = verticalOffset;
  instance.id = id;
  if (isVNode(instance.message)) {
    instance.$slots.default = [instance.message];
    instance.message = null;
  }
  // vm.$mount() 手动地挂载一个未挂载的实例,返回自身实例
  instance.vm = instance.$mount();
  // 将组件的界面最后添加到 body 标签中
  document.body.appendChild(instance.vm.$el);
  instance.vm.visible = true;
  instance.dom = instance.vm.$el;
  instance.dom.style.zIndex = PopupManager.nextZIndex();
  instances.push(instance);
  return instance.vm;
};

// 优化API接口 ,提供 this.$message.error('错了哦,这是一条错误消息'); 使用方式
['success', 'warning', 'info', 'error'].forEach(type => {
  Message[type] = options => {
    if (typeof options === 'string') {
      options = {
        message: options
      };
    }
    options.type = type;
    return Message(options);
  };
});

Message.close = function(id, userOnClose) {
  const len = instances.length;
  for (let i = 0; i < len; i++) {
    if (id === instances[i].id) {
      if (typeof userOnClose === 'function') {
        userOnClose(instances[i]);
      }
      const removedHeight = instances[i].dom.offsetHeight;
      instances.splice(i, 1);
      if (len <= 1) return;
      for (let j = i; j < len - 1; j++) {
        instances[j].dom.style.top =
          parseInt(instances[j].dom.style.top, 10) - removedHeight - 16 + 'px';
      }
      break;
    }
  }
};

Message.closeAll = function() {
  for (let i = instances.length - 1; i >= 0; i--) {
    instances[i].close();
  }
};

export default Message;

在elementUI中的说明

  1. instance.$mount(); 手动地挂载一个未挂载的实例,生成了HTML代码,但是没有挂载到body标签中
  2. document.body.appendChild(instance.vm.$el); 将生成的HTML代码挂载到Body中,形成了我们看到的界面