React和Vue中暴露子组件的属性和方法给父组件用,并且控制子组件暴露的颗粒度的做法

React

在 React 中,forwardRef 是一种高级技术,它允许你将 ref 从父组件传递到子组件,从而直接访问子组件的 DOM 节点或公开的方法。这对于需要操作子组件内部状态或 DOM 的场景非常有用。为了使子组件能够暴露其属性和方法给父组件,通常会结合 useImperativeHandle Hook 使用 forwardRef

如何使用 forwardRefuseImperativeHandle

  1. 创建一个带有 forwardRef 的子组件:

    • 使用 React.forwardRef 来创建一个接受 ref 参数的组件。
  2. 使用 useImperativeHandle 定义要暴露的方法和属性:

    • 在子组件中使用 useImperativeHandle 来定义哪些方法或属性应该通过 ref 暴露出去。
  3. 在父组件中使用 ref 来访问子组件的公开接口:

    • 创建一个 ref 并将其传递给子组件,然后通过这个 ref 访问子组件暴露的方法或属性。

示例代码

子组件 (ChildComponent.js)
jsx 复制代码
import React, { useRef, useImperativeHandle, forwardRef } from 'react';

const ChildComponent = forwardRef((props, ref) => {
  const inputRef = useRef(null);

  // 定义要暴露的方法
  useImperativeHandle(ref, () => ({
    focusInput: () => {
      inputRef.current.focus();
      console.log('子组件的输入框获得了焦点');
    },
    getInputValue: () => inputRef.current.value,
  }));

  return (
    <div>
      <input ref={inputRef} type="text" placeholder="这是子组件的输入框" />
    </div>
  );
});

export default ChildComponent;
父组件 (ParentComponent.js)
jsx 复制代码
import React, { useRef } from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
  const childComponentRef = useRef(null);

  const handleFocus = () => {
    if (childComponentRef.current) {
      childComponentRef.current.focusInput();
    }
  };

  const handleGetValue = () => {
    if (childComponentRef.current) {
      const value = childComponentRef.current.getInputValue();
      console.log('子组件的输入值:', value);
    }
  };

  return (
    <div>
      <ChildComponent ref={childComponentRef} />
      <button onClick={handleFocus}>让子组件的输入框获得焦点</button>
      <button onClick={handleGetValue}>获取子组件的输入值</button>
    </div>
  );
};

export default ParentComponent;

解释

  • 子组件 (ChildComponent.js):

    • 使用 forwardRef 创建了一个接受 ref 参数的组件。
    • 使用 useImperativeHandle 定义了 focusInputgetInputValue 方法,并将它们绑定到传入的 ref 上。这意味着父组件可以通过 ref 访问这些方法。
  • 父组件 (ParentComponent.js):

    • 创建了一个 ref (childComponentRef) 并将其传递给 ChildComponent
    • 提供了两个按钮,分别用于调用子组件的 focusInputgetInputValue 方法。

这种方法确保了父组件可以安全地与子组件进行交互,同时保持良好的封装性。通过 useImperativeHandle,你可以精确控制哪些方法或属性是公开的,而不会意外地暴露不必要的实现细节。

Vue

当你通过 ref 获取到子组件的根 DOM 元素后,你可以使用标准的 DOM API 来访问或操作该元素及其子元素。如果你想要访问 <p> 标签,可以通过多种方式实现,具体取决于你想要进行的操作。

访问子元素的方法

  1. 使用 querySelectorquerySelectorAll:

    • 这些方法允许你根据选择器(如标签名、类名、ID 等)来查找特定的子元素。
  2. 遍历子节点:

    • 你可以使用 childrenchildNodes 或其他类似属性来遍历子节点。
  3. 直接访问特定子元素:

    • 如果你知道子元素的具体位置,可以直接通过 firstElementChildlastElementChild 等属性访问。

示例代码

假设你想在父组件中访问并打印子组件中的 <p> 标签的内容,可以按照以下方式修改你的代码:

子组件 (ChildComponent.vue)
vue 复制代码
<template>
  <div ref="root">
    <p id="content">这是子组件的内容</p>
  </div>
</template>

<script setup>
import { defineExpose, ref } from 'vue';

const root = ref(null);

// 使用 defineExpose 显式暴露给父组件的方法或属性
defineExpose({
  getRootEl: () => root.value,
});
</script>
父组件 (ParentComponent.vue)
vue 复制代码
<template>
  <ChildComponent ref="childComponent" />
  <button @click="handleClick">点击我</button>
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const childComponent = ref(null);

const handleClick = () => {
  if (childComponent.value) {
    // 调用子组件的公开方法来获取 DOM 引用
    const el = childComponent.value.getRootEl();
    
    // 使用 querySelector 查找 <p> 标签
    const pElement = el.querySelector('p#content');
    console.log('子组件的 <p> 内容:', pElement?.textContent);
  }
};
</script>

解释

  • 子组件 (ChildComponent.vue):

    • 我们为 <p> 标签添加了一个 id="content",以便更容易地通过 querySelector 查找它。
  • 父组件 (ParentComponent.vue):

    • handleClick 方法中,我们首先调用 getRootEl 获取子组件的根元素。
    • 然后,使用 querySelector 方法通过 ID 选择器查找 <p> 标签,并打印其文本内容。这里使用了可选链操作符 (?.) 来安全处理可能为 null 的情况。

这种方法确保了你能够以一种安全且可控的方式访问子组件内部的特定 DOM 元素。请记住,尽量减少对 DOM 的直接操作,除非确实有必要。保持尽可能多的逻辑在 Vue 的响应式系统内,这样可以使应用更加高效和易于维护。

相关推荐
又尔D.2 小时前
vue3+webOffice合集
vue.js·weboffice
古蓬莱掌管玉米的神5 小时前
vue3语法watch与watchEffect
前端·javascript
林涧泣5 小时前
【Uniapp-Vue3】uni-icons的安装和使用
前端·vue.js·uni-app
拉一次撑死狗5 小时前
Vue基础(2)
前端·javascript·vue.js
qq_544329177 小时前
下载一个项目到跑通的大致过程是什么?
javascript·学习·bug
林涧泣7 小时前
【Uniapp-Vue3】下拉刷新
前端·vue.js·uni-app
Jane - UTS 数据传输系统9 小时前
VUE+ Element-plus , el-tree 修改默认左侧三角图标,并使没有子级的那一项不展示图标
javascript·vue.js·elementui
凯哥爱吃皮皮虾9 小时前
如何给 react 组件写单测
前端·react.js·jest
ThomasChan12311 小时前
Typescript 多个泛型参数详细解读
前端·javascript·vue.js·typescript·vue·reactjs·js
zzlyx9911 小时前
.NET 9 微软官方推荐使用 Scalar 替代传统的 Swagger
javascript·microsoft·.net