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 的响应式系统内,这样可以使应用更加高效和易于维护。

相关推荐
天若有情67339 分钟前
程序员原创|借鉴JS事件冒泡,根治电脑文件混乱的“冒泡整理法”
开发语言·javascript·windows·ecmascript·电脑·办公·日常
FYKJ_20102 小时前
springboot校园兼职平台--附源码02041
java·javascript·spring boot·python·eclipse·django·php
用户6688599847666 小时前
Vue 3.0安装与使用
vue.js
空中海7 小时前
01 React Native 基础、核心组件与布局体系
javascript·react native·react.js
空中海7 小时前
05 React架构设计、项目实践与专家清单
前端·react.js·前端框架
前端之虎陈随易9 小时前
2年没用Nodejs了,Bun很香
linux·前端·javascript·vue.js·typescript
空中海10 小时前
04 工程化、质量体系与 React 生态
前端·ubuntu·react.js
空中海10 小时前
03 性能、动画与 React Native 新架构
react native·react.js·架构
好运的阿财10 小时前
OpenClaw工具拆解之host_workspace_write+host_workspace_edit
前端·javascript·人工智能·机器学习·ai编程·openclaw·openclaw工具
XiYang-DING11 小时前
JavaScript
开发语言·javascript·ecmascript