React自定义hooks是一种用于共享逻辑和状态逻辑的强大方式,可以帮助你在不同的组件之间复用代码。自定义hooks是普通的JavaScript函数,它们以"use"开头,并且可以调用React的内置hooks,如useState、useEffect、useContext等
在Vue3中,虽然没有像React中的自定义hooks一样的直接概念,但你可以使用Composition(组合式) API的功能来创建自己的可复用逻辑。你可以将逻辑封装到函数中,然后在组件中使用它们。
下面用React封装一个异步请求的Hooks
使用Vue封装一个自动获取焦点的
异步请求
import { useState, useEffect } from 'react';
import axios from 'axios';
function useAxios(url) {
// 初始化状态
const [data, setData] = useState(null); // 存储响应数据
const [loading, setLoading] = useState(false); // 控制加载状态
const [error, setError] = useState(null); // 存储错误信息
useEffect(() => {
// 创建异步请求函数
const fetchData = async () => {
setLoading(true); // 开始加载
setError(null); // 清除之前的错误
try {
// 发起 GET 请求
const response = await axios.get(url);
setData(response.data); // 保存响应数据
} catch (err) {
setError(err); // 处理错误
} finally {
setLoading(false); // 完成加载
}
};
// 调用异步请求函数
fetchData();
}, [url]); // 仅在 URL 改变时触发
// 返回数据、加载状态和错误状态
return { data, loading, error };
}
export default useAxios;
使用 Axios 进行异步请求的组件中使用这个自定义 hooks
import React from 'react';
import useAxios from './useAxios'; // 导入自定义 hooks
function MyComponent() {
// 使用自定义 hooks,传入 API URL
const { data, loading, error } = useAxios('https://api.example.com/data');
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
if (!data) {
return null;
}
return (
<div>
{/* 在这里显示数据 */}
</div>
);
}
export default MyComponent;
Vue3 拖拽:
<template>
<div ref="draggableElement" class="draggable-element">
Drag me!
</div>
</template>
<script>
import { ref, onMounted, onUnmounted } from 'vue';
// 创建自定义Composition API拖拽Hook
function useDraggable(elementRef) {
const x = ref(0); // 存储元素的X坐标
const y = ref(0); // 存储元素的Y坐标
const isDragging = ref(false); // 控制拖拽状态
// 处理鼠标按下事件
const handleMouseDown = (event) => {
isDragging.value = true;
const element = elementRef.value;
x.value = event.clientX - element.getBoundingClientRect().left;
y.value = event.clientY - element.getBoundingClientRect().top;
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
};
// 处理鼠标移动事件
const handleMouseMove = (event) => {
if (isDragging.value) {
const element = elementRef.value;
element.style.left = event.clientX - x.value + 'px';
element.style.top = event.clientY - y.value + 'px';
}
};
// 处理鼠标释放事件
const handleMouseUp = () => {
isDragging.value = false;
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
// 在组件挂载时设置初始样式和事件监听
onMounted(() => {
const element = elementRef.value;
element.style.position = 'absolute';
element.style.cursor = 'grab';
element.addEventListener('mousedown', handleMouseDown);
});
// 在组件卸载时移除事件监听
onUnmounted(() => {
const element = elementRef.value;
element.removeEventListener('mousedown', handleMouseDown);
});
return { x, y };
}
export default {
setup() {
const draggableElement = ref(null);
const { x, y } = useDraggable(draggableElement);
return { x, y, draggableElement };
},
};
</script>
<style scoped>
.draggable-element {
width: 100px;
height: 100px;
background-color: lightblue;
}
</style>