在 vue 和 react 的使用中,都有涉及到 ref,除了定义变量之外,ref 的一个重要用处就是绑定 dom 节点或组件,那在 vue 和 react 中,关于 ref 的用法有什么相同与不同呢,我们来一起看看。
1. ref 在 react 中的使用
在 react 中提供了名为 useRef 的 hook 来创建 ref , 既可以保存变量,又可以用来绑定 dom。
a. 绑定单节点
import { useRef } from "react"
function App() {
// 定义 ref
const inputRef = useRef(null)
const handleClick = () => {
console.log(inputRef.current)
inputRef.current.focus()
}
return (
<>
<input ref={inputRef} type="text"/>
<button onClick={handleClick}>focus the input</button>
</>
)
}
b. 绑定多节点
import { useRef, useState } from "react"
function App() {
const [list] = useState([1, 2, 3, 4, 5])
const listRef = useRef([])
const formatRef = (el) => {
listRef.current.push(el);
}
const handleClick = () => {
console.log(listRef.current);
}
return (
<>
<ul>
{list.map((v) => {
return (
<li ref={formatRef} key={v}>
{v}
</li>
)
})}
</ul>
<button onClick={handleClick}>获取dom节点</button>
</>
)
}
c.绑定组件实例
class组件添加ref
class MyTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
componentDidMount() {
this.textInput.current.focusTextInput();
}
render() {
return (
<CustomTextInput ref={this.textInput} />
);
}
}
在函数组件中,这样使用 ref 是无效的,可以使用 forwardRef,或者可以将该组件转化为 class 组件。不过,在函数组件内部同样可以使用 ref 属性,只要它指向一个 dom 元素或 class 组件。
使用forwardRef 与useImperativeHandle 进行ref转发,并指定子组件暴露的内容
import { useEffect, useRef, forwardRef, useImperativeHandle } from 'react'
function MyInput(props,ref) {
const inputRef = useRef()
useEffect(() => {
console.log('inputRef',inputRef)
},[])
useImperativeHandle(ref, () => ({
input: inputRef.current,
focus:() => inputRef.current.focus()
}))
return (
<input ref={inputRef} {...props} />
)
}
export default forwardRef(MyInput)
import React, { useEffect, useRef } from 'react'
import MyInput from './MyInput'
export default function App() {
const input_ref = useRef()
useEffect(() => {
console.log(input_ref.current)
input_ref.current?.focus()
}, [])
return (
<MyInput ref={input_ref} />
)
}
2. ref在vue中的使用
在 vue 中则是提供了 ref 来声明响应式变量,或者进行 dom 操作。
a. 绑定单节点
<script setup>
import { ref } from "vue"
const inputRef = ref()
const handleClick = () => {
console.log(inputRef.value)
inputRef.vaule.focus()
}
</script>
<template>
<input ref="inputRef" type="text" />
<button @click="handleClick">获取input焦点</button>
</template>
b.绑定多节点
<script setup>
import { ref, reactive } from "vue"
const list = reactive([1, 2, 3, 4, 5])
const listRef = ref([])
const formatRef = (el) => {
if (el) {
listRef.value.push(el)
}
}
const handleClick = () => {
console.log(listRef.value)
}
</script>
<template>
<ul>
<li v-for="item in list" :key="item" :ref="formatRef">
{{ item }}
</li>
</ul>
<button @click="handleClick">获取dom节点</button>
</template>
c.绑定组件实例
// 子组件
<script setup>
import { ref, expose } from "vue"
defineProps({
title: String
})
const inputRef = ref()
const desc = ref('描述')
const focus = () => {
if(inputRef.value) {
inputRef.value.focus()
console.log('focus')
}
}
expose({
focus
})
</script>
<template>
<div>
<h3>{{ title }}</h3>
<input ref="inputRef" type="text" />
<button @click="handleClick">获取input焦点</button>
</div>
</template>
// 父组件
<script setup>
import { ref, expose } from "vue"
import Child from 'child.vue'
const childRef = ref()
onMounted(() => {
console.log(childRef.value)
console.log(childRef.value?.desc)
console.log(childRef.value?.focus())
})
</script>
<template>
<div>
<Child ref="childRef" />
</div>
</template>
本文主要介绍 vue 和 react 中 通过 ref 绑定 dom 元素或组件实例的用法区别,两者使用方法总体来讲还是大致相近的。