vue2升级vue3: TSX Vue 3 Composition API Refs

在vue2时代,$refs 直接操作子组件

1
this.$refs.gridlayout.$children[index];

虽然不推荐这么做,但是确实非常好用。但是vue2快速迁移到vue3,之前的这个写法因为干进度,不想重构,直接搬迁,发现不行?

看了下官方的文档:https://v3.cn.vuejs.org/guide/migration/array-refs.html#%E8%BF%81%E7%A7%BB%E7%AD%96%E7%95%A5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
    <div v-for="item in list" :ref="setItemRef"></div>
</template>
<script setup>
    let itemRefs = ref()
    const setItemRef = el => {
      if (el) {
        itemRefs.push(el)
      }
    }
    onBeforeUpdate(() => {
      itemRefs = []
    })
    onUpdated(() => {
      console.log(itemRefs)
    })
</script>

注意:

  • itemRefs 不必是数组:它也可以是一个对象,其 ref 可以通过迭代的 key 被设置

  • 如有需要,itemRefs 也可以是响应式的,且可以被侦听。

 

在tsx 这个怎么弄呢?

TSX refs

网上的大部分教程都是 template 的

Typing Template Refs

1
const el = ref<HTMLInputElement | null>(null)

普通元素

Typing Component Template Refs

1
2
3
4
5
6
7
import MyModal from './MyModal.vue'
 
const modal = ref<InstanceType<typeof MyModal> | null>(null)
 
const openModal = () => {
  modal.value?.open()
}

对于子组件,其实和 let timer: ReturnType<typeof setTimeout> = null; 类似。

如果不进行类型声明,modal 方法无法调用。 需要是as  魔法了

还有一个需要特别注意,就是子组件内容是暴露出来的,如果是 <script setup> 组件,是无法获取内容的,具体参看:

vue2升级vue3:单文件组件概述 及 defineExpos/expose https://www.zhoulujun.cn/html/webfront/ECMAScript/vue3/8872.html

 

Refs 获取子元素,并操作子元素

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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import { defineComponent, nextTick, onBeforeUpdate, onMounted, onUnmounted, ref } from 'vue';
import ChartWrapper from '@/components/chart-wrapper';
import props from './props';
import { AddChartType, PanelModel, IGridPos } from '@/typings';
 
import { DashboardModule, sortGridPanels } from '@modules/dashboard';
import { getPluginTypes, handleInitChartPlugin, handleInitDataSource } from '@/utils/dashboard';
import Loading from '@/components/loading';
import { GRID_COL_NUM, GRID_ROW_HEIGHT, GRID_ROW_MARGIN, initPanel } from '@/constants';
import { debounce } from 'lodash';
import { deepClone } from '@/utils';
import AddPanel from '@dashboard/grid-panel/add-panel';
import TabPanel from '@dashboard/tab-panel/index';
import { GridItem, GridLayout } from 'v3-grid-layout';
import 'v3-grid-layout/dist/style.css';
import './index.scss';
import Row from './Row';
import EventBus from '@/utils/eventBus';
 
export default defineComponent({
  name: 'GridPanelPlugin',
  props,
  emits: ['ready''delete''mounted'],
  setup(props, { emit }) {
    const layout = ref<IGridPos[]>([]);
    const gridLayout = ref<InstanceType<typeof GridLayout>>(null);
    const gridItem = ref<InstanceType<typeof GridItem>[]>([]);
    const dashboardPanel = ref<Element>(null);
    onBeforeUpdate(() => {
      gridItem.value = [];
    });
    function drag(e: DragEvent) {
      const parentRect = dashboardPanel.value.getBoundingClientRect();
      let mouseInGrid = false;
      if (
        ((mouseXY.x > parentRect.left) && (mouseXY.x < parentRect.right))
        && ((mouseXY.y > parentRect.top) && (mouseXY.y < parentRect.bottom))) {
        mouseInGrid = true;
      }
      if (mouseInGrid === true && (layout.value.findIndex(item => item.i === 'drop')) === -1) {
        layout.value.push({
          x: (layout.value.length * 2) % (GRID_COL_NUM || 12),
          y: layout.value.length + (GRID_COL_NUM || 12), // puts it at the bottom
          w: 1,
          h: 1,
          i: 'drop',
        });
      }
      const index = layout.value.findIndex(item => item.i === 'drop');
      if (index !== -1) {
        const el = gridItem.value[index];
        el.dragging.data = { top: mouseXY.y - parentRect.top, left: mouseXY.x - parentRect.left };
        const new_pos = el.calcXY(mouseXY.y - parentRect.top, mouseXY.x - parentRect.left);
        if (mouseInGrid === true) {
          gridLayout.value.dragEvent('dragstart''drop', new_pos.x, new_pos.y, 1, 1);
          DragPos.i = String(index);
          DragPos.x = layout.value[index].x;
          DragPos.y = layout.value[index].y;
        }
        if (mouseInGrid === false) {
          gridLayout.value.dragEvent('dragend''drop', new_pos.x, new_pos.y, 1, 1);
          layout.value = layout.value.filter(obj => obj.i !== 'drop');
        }
      }
    }
 
    function dragend(e: DragEvent) {
      // const parentRect = document.getElementById('dashboard-panel').getBoundingClientRect();
      const parentRect = dashboardPanel.value.getBoundingClientRect();
      let mouseInGrid = false;
      if (((mouseXY.x > parentRect.left) && (mouseXY.x < parentRect.right))
        && ((mouseXY.y > parentRect.top) && (mouseXY.y < parentRect.bottom))) {
        mouseInGrid = true;
      }
      if (mouseInGrid === true) {
        gridLayout.value.dragEvent('dragend''drop', DragPos.x, DragPos.y, 1, 1);
        layout.value = layout.value.filter(obj => obj.i !== 'drop');
        // UNCOMMENT below if you want to add a grid-item
        this.layout.push({
            x: DragPos.x,
            y: DragPos.y,
            w: 1,
            h: 1,
            i: DragPos.i,
        });
        this.$refs.gridLayout.dragEvent('dragend', DragPos.i, DragPos.x,DragPos.y,1,1);
        try {
            this.$refs.gridLayout.$children[this.layout.length].$refs.item.style.display="block";
        catch {
        }
      }
    }
 
    return {
      gridLayout,
      gridItem,
      dashboardPanel,
      layout,
      movedId,
      inited,
      isLayoutReady,
      isShowEditRowDialog,
      rowForm,
    };
  },
  render() {
    if (!this.inited) {
      return (<Loading/>);
    }
    return (
      <div
        ref='dashboardPanel'
        id='dashboard-panel'
        class={'dashboard-panel flex-1'}>
        <GridLayout
          ref='gridLayout'
          layout={this.layout}
          col-num={GRID_COL_NUM}
          row-height={GRID_ROW_HEIGHT}
          is-resizabl={this.editable}
          is-draggable={this.editable}
          vertical-compact={true}
          use-css-transforms={false}
          margin={GRID_ROW_MARGIN}
          on-layout-updated={this.handleLayoutUpdated}
          on-layout-ready={this.onLayoutReady}
        >
          {
            this.layout.map((item) => {
              return (
                <GridItem
                  ref={(el: any) => {
                    if (el) {
                      this.gridItem.push(el);
                    }
                  }}
                  {{...item}}
                 >
                  {chart}
                </GridItem>
              );
            })
          }
        </GridLayout>
      </div>
    );
  },
});

 

当然,这个代码是抽离出来的。

这个vue3-grid-layout,自己写了弄了一版,https://github.com/zhoulujun/vue3-grid-layout

 

 

 

 

转载本站文章《vue2升级vue3: TSX Vue 3 Composition API Refs》,
请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/vue3/8873.html

posted @   zhoulujun  阅读(235)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示