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

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

<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

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

普通元素

Typing Component Template Refs

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 获取子元素,并操作子元素

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

vue2升级vue3: TSX Vue 3 Composition API Refs的更多相关文章

  1. vue2升级vue3:Vue Demij打通vue2与vue3壁垒,构建通用组件

    如果你的vue2代码之前是使用vue-class-component 类组件模式写的.选择可以使用 https://github.com/facing-dev/vue-facing-decorator ...

  2. vue2升级vue3:vue2 vue-i18n 升级到vue3搭配VueI18n v9

    项目从vue2 升级vue3,VueI18n需要做适当的调整.主要是Vue I18n v8.x 到Vue I18n v9 or later 的变化,其中初始化: 具体可以参看:https://vue- ...

  3. vue2升级vue3指南(二)—— 语法warning&error篇

    本文总结了vue2升级vue3可能会遇到的语法警告和错误,如果想知道怎样升级,可以查看我的上一篇文章:vue2升级vue3指南(一)-- 环境准备和构建篇 Warning 1.deep /deep/和 ...

  4. vue2升级vue3:vue-i18n国际化异步按需加载

    vue2异步加载之前说过,vue3还是之前的方法,只是把 i18n.setLocaleMessage改为i18n.global.setLocaleMessage 但是本文还是详细说一遍: 为什么需要异 ...

  5. uniapp项目vue2升级vue3简单记录

    看到好多开源项目都升级了vue3,看文章说vue3性能升级很多,而且组合式api很香,遂把最近开发的自助洗车app升级下,在此记录下出现的问题. uniapp升级vue3官方指南 我是先去vue官网看 ...

  6. 蒲公英 &#183; JELLY技术周刊 Vol.21 -- 技术周刊 &#183; React Hooks vs Vue 3 + Composition API

    蒲公英 · JELLY技术周刊 Vol.21 选 React 还是 Vue,每个人心中都会有自己的答案,有很多理由去 pick 心水的框架,但是当我们扪心自问,我们真的可以公正的来评价这两者之间的差异 ...

  7. vue2升级vue3指南(一)—— 环境准备和构建篇

    1.nodejs和npm 注意二者的版本,版本过低需要升级,本人升级后的版本如下: $ node -v v16.15.1 $ npm -v 8.11.0 2.package.json 和依赖升级 由于 ...

  8. Vue3:不常用的Composition API && Fragment、Teleport、Suspense && 与Vue2对比的一些变化

    1 # 一.Vue3不常用的Composition API 2 # 1.shallowReactive与shallowRef 3 .shallowReactive: 只处理对象最外层属性的响应式(浅响 ...

  9. Vue2 到 Vue3,重温这 5 个常用的 API

    距离Vue3发布已经过去一年多时间了,从Vue2到Vue3是一个不小的升级,包括周边生态等.虽然目前大多数开发者们在使用的仍旧以Vue2为准,但Vue3显然是Vue开发者们未来必须面对的,而且前不久V ...

  10. 了解 Vue 的 Compsition API

    在这篇文章中,我将讲讲 Vue 的 Composition API 为什么比之前的 Options API 要好,以及它是如何工作的. Options API 有什么问题 首先,这里不是要大家放弃 O ...

随机推荐

  1. CF48C [The Race]

    Problem 题目简述 现有 \(n\) 个已经加过油的加油站,如果当前剩余油量 \(< 10\) 升,则会加 \(x\) 升的油. 初始状态下,有 \(x\) 升油.每个加油站之间的距离为 ...

  2. JavaScript:对象的三个属性

    每一个对象都有与之相关的原型(prototype).类(class)和可扩展性(extension attribute). 原型 prototype 对象的原型属性是用来继承属性的.通过对象直接量创建 ...

  3. Python JSON 使用指南:解析和转换数据

    JSON 是一种用于存储和交换数据的语法.JSON 是文本,使用 JavaScript 对象表示法编写. Python 中的 JSON Python 有一个内置的 json 包,可用于处理 JSON ...

  4. 研读Java代码必须掌握的Eclipse快捷键

    1. Ctrl+左键 和F3 这个是大多数人经常用到的,用来查看变量.方法.类的定义 跳到光标所在标识符的定义代码.当按执行流程阅读时,F3实现了大部分导航动作. 2 Ctrl+Shift+G 在工作 ...

  5. Net 高级调试之五:如何在托管函数上设置断点

    一.简介 今天是<Net 高级调试>的第五篇文章.今天这篇文章开始介绍如何在托管方法和非托管方法设置断点,我们要想调试程序,必须掌握调试的一些命令,动态调试的命令,我们在上一篇文章已经讲过 ...

  6. 浏览器事件循环Event Loop

    引言: 事件循环不是浏览器独有的,从字面上看,"循环"可以简单地认为就是重复,比如for循环,就是重复地执行for循环体中的语句,所以事件循环,可以理解为重复地处理事件,那么下一个 ...

  7. JavaScript高级程序设计笔记12 BOM

    BOM BOM的核心--window对象 窗口和弹窗 location对象--页面信息 navigator对象--浏览器信息 history对象--浏览器历史记录 BOM是使用JavaScript开发 ...

  8. 混合应用与Hybrid App开发上架流程透析

    Hybrid App(混合 App)已经成为大家接触最为广泛的 App 形式,不管是我们用到的微信.支付宝还是淘宝.京东等大大小小的应用都非常热衷于Hybrid App 带来的研发效率提升和灵活性. ...

  9. 如何系统学习Python?

    学习 Python 可以通过以下系统性的步骤进行: 1. 设定学习目标 确定你学习 Python 的主要目的,是为了编写脚本.数据分析.Web 开发.机器学习还是其他应用?理解这个目标可以帮助你更有针 ...

  10. 大白话说Python+Flask入门(六)Flask SQLAlchemy操作mysql数据库

    写在前面 这篇文章被搁置真的太久了,不知不觉拖到了周三了,当然,也算跟falsk系列说再见的时候,真没什么好神秘的,就是个数据库操作,就大家都知道的CRUD吧. Flask SQLAlchemy的使用 ...