wupengfei
2025-02-12 2d4a6ebe75599eaa51d5fb0f522dc9fa6825af00
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
<template>
  <slot></slot>
  <PortalManager ref="_manager" />
</template>
 
<script lang="ts">
defineComponent({
  name: 'portal-host',
  inheritAttrs: false,
});
</script>
 
<script setup lang="ts">
import {
  PortalContextKey,
  Operation,
  getUniqueKey,
  addType,
  removeType,
  TopViewEventEmitter,
  PortalNode,
  PortalManagerInstance,
} from './portal';
import PortalManager from './PortalManager.vue';
 
const _nextKey = ref(0);
const _queue = ref<Operation[]>([]);
const _manager = ref<PortalManagerInstance>();
 
onMounted(() => {
  TopViewEventEmitter.on(getUniqueKey(addType), _mount);
  TopViewEventEmitter.on(getUniqueKey(removeType), _unmount);
 
  while (_queue.value.length && _manager.value) {
    const action = _queue.value.pop();
    if (!action) {
      continue;
    }
 
    switch (action.type) {
      case 'mount':
        _manager.value.mount(action.key, action.children);
        break;
      case 'update':
        _manager.value.update(action.key, action.children);
        break;
      case 'unmount':
        _manager.value.unmount(action.key);
        break;
    }
  }
});
 
onUnmounted(() => {
  TopViewEventEmitter.off(getUniqueKey(addType), _mount);
  TopViewEventEmitter.off(getUniqueKey(removeType), _unmount);
});
 
const _setManager = (manager?: any) => {
  _manager.value = manager;
};
 
const _mount = (children: PortalNode, _key?: number) => {
  const key = _key || _nextKey.value++;
  if (_manager.value) {
    _manager.value.mount(key, children);
  } else {
    _queue.value.push({ type: 'mount', key, children });
  }
 
  return key;
};
 
const _update = (key: number, children: PortalNode) => {
  if (_manager.value) {
    _manager.value.update(key, children);
  } else {
    const op: Operation = { type: 'mount', key, children };
    const index = _queue.value.findIndex(
      (o) => o.type === 'mount' || (o.type === 'update' && o.key === key)
    );
 
    if (index > -1) {
      _queue.value[index] = op;
    } else {
      _queue.value.push(op);
    }
  }
};
 
const _unmount = (key: number) => {
  if (_manager.value) {
    _manager.value.unmount(key);
  } else {
    _queue.value.push({ type: 'unmount', key });
  }
};
 
provide(PortalContextKey, {
  mount: _mount,
  update: _update,
  unmount: _unmount,
});
</script>