干燥机配套车间生产管理系统/云平台前端
baoshiwei
2023-03-10 1fb197352b6a263646e4ccd3ed1c7854ede031dd
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
import { defineComponent, h, ref, watch } from 'vue';
import { randomString } from '/@/utils/common/compUtils';
import '../style/reload-effect.less';
 
// 修改数据特效
export default defineComponent({
  props: {
    vNode: null,
    // 是否启用特效
    effect: Boolean,
  },
  emits: ['effectBegin', 'effectEnd'],
  setup(props, { emit }) {
    // vNode: null,
    const innerEffect = ref(props.effect);
    // 应付同时多个特效
    const effectIdx = ref(0);
    const effectList = ref<any[]>([]);
 
    watch(
      () => props.effect,
      () => (innerEffect.value = props.effect)
    );
    watch(
      () => props.vNode,
      (_vNode, old) => {
        if (props.effect && old != null) {
          let topLayer = renderSpan(old, 'top');
          effectList.value.push(topLayer);
        }
      },
      { deep: true, immediate: true }
    );
 
    // 条件渲染内容 span
    function renderVNode() {
      if (props.vNode == null) {
        return null;
      }
      let bottom = renderSpan(props.vNode, 'bottom');
      // 启用了特效,并且有旧数据,就渲染特效顶层
      if (innerEffect.value && effectList.value.length > 0) {
        emit('effectBegin');
        // 1.4s 以后关闭特效
        window.setTimeout(() => {
          let item = effectList.value[effectIdx.value];
          if (item && item.elm) {
            // 特效结束后,展示先把 display 设为 none,而不是直接删掉该元素,
            // 目的是为了防止页面重新渲染,导致动画重置
            item.elm.style.display = 'none';
          }
          // 当所有的层级动画都结束时,再删掉所有元素
          if (++effectIdx.value === effectList.value.length) {
            innerEffect.value = false;
            effectIdx.value = 0;
            effectList.value = [];
            emit('effectEnd');
          }
        }, 1400);
        return [effectList.value, bottom];
      } else {
        return bottom;
      }
    }
 
    // 渲染内容 span
    function renderSpan(vNode, layer) {
      let options = {
        key: layer + effectIdx.value + randomString(6),
        class: ['j-vxe-reload-effect-span', `layer-${layer}`],
        style: {},
      };
      if (layer === 'top') {
        // 最新渲染的在下面
        options.style['z-index'] = 9999 - effectIdx.value;
      }
      return h('span', options, [vNode]);
    }
 
    return () =>
      h(
        'div',
        {
          class: ['j-vxe-reload-effect-box'],
        },
        [renderVNode()]
      );
  },
});