# 二.Loading

# element-ui
├── packages         # 放置element的组件(css样式放置在这个目录下theme-chalk下)
│   ├── alert
│   │  ├── src          # alert组件
│   │  │ └── main.vue     # 组件注册的入口文件
│   │  └── index.js     # 组件注册的入口文件
1
2
3
4
5
6

# index.js

import directive from "./src/directive"
import service from "./src/index"

export default {
  install(Vue) {
    Vue.use(directive)
    Vue.prototype.$loading = service
  },
  directive,
  service,
}
1
2
3
4
5
6
7
8
9
10
11

在 vue 项目中通过引用这个组件,然后通过 vue.use 加载这个组件,内部会调用 install 方法,将组件加载到 Vue 实例内部

# index.js

import Vue from "vue"
import loadingVue from "./loading.vue"
import { addClass, removeClass, getStyle } from "element-ui/src/utils/dom"
import { PopupManager } from "element-ui/src/utils/popup"
import afterLeave from "element-ui/src/utils/after-leave"
import merge from "element-ui/src/utils/merge"

const LoadingConstructor = Vue.extend(loadingVue)

const defaults = {
  text: null,
  fullscreen: true,
  body: false,
  lock: false,
  customClass: "",
}

let fullscreenLoading

LoadingConstructor.prototype.originalPosition = ""
LoadingConstructor.prototype.originalOverflow = ""

LoadingConstructor.prototype.close = function() {
  if (this.fullscreen) {
    fullscreenLoading = undefined
  }
  afterLeave(
    this,
    (_) => {
      const target = this.fullscreen || this.body ? document.body : this.target
      removeClass(target, "el-loading-parent--relative")
      removeClass(target, "el-loading-parent--hidden")
      if (this.$el && this.$el.parentNode) {
        this.$el.parentNode.removeChild(this.$el)
      }
      this.$destroy()
    },
    300
  )
  this.visible = false
}

const addStyle = (options, parent, instance) => {
  let maskStyle = {}
  if (options.fullscreen) {
    instance.originalPosition = getStyle(document.body, "position")
    instance.originalOverflow = getStyle(document.body, "overflow")
    maskStyle.zIndex = PopupManager.nextZIndex()
  } else if (options.body) {
    instance.originalPosition = getStyle(document.body, "position")
    ;["top", "left"].forEach((property) => {
      let scroll = property === "top" ? "scrollTop" : "scrollLeft"
      maskStyle[property] =
        options.target.getBoundingClientRect()[property] +
        document.body[scroll] +
        document.documentElement[scroll] +
        "px"
    })
    ;["height", "width"].forEach((property) => {
      maskStyle[property] =
        options.target.getBoundingClientRect()[property] + "px"
    })
  } else {
    instance.originalPosition = getStyle(parent, "position")
  }
  Object.keys(maskStyle).forEach((property) => {
    instance.$el.style[property] = maskStyle[property]
  })
}

const Loading = (options = {}) => {
  if (Vue.prototype.$isServer) return
  options = merge({}, defaults, options)
  if (typeof options.target === "string") {
    options.target = document.querySelector(options.target)
  }
  options.target = options.target || document.body
  if (options.target !== document.body) {
    options.fullscreen = false
  } else {
    options.body = true
  }
  if (options.fullscreen && fullscreenLoading) {
    return fullscreenLoading
  }

  let parent = options.body ? document.body : options.target
  let instance = new LoadingConstructor({
    el: document.createElement("div"),
    data: options,
  })

  addStyle(options, parent, instance)
  if (
    instance.originalPosition !== "absolute" &&
    instance.originalPosition !== "fixed"
  ) {
    addClass(parent, "el-loading-parent--relative")
  }
  if (options.fullscreen && options.lock) {
    addClass(parent, "el-loading-parent--hidden")
  }
  parent.appendChild(instance.$el)
  Vue.nextTick(() => {
    instance.visible = true
  })
  if (options.fullscreen) {
    fullscreenLoading = instance
  }
  return instance
}

export default Loading
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113