分享 10 个可以使用 Vue.js 制作的有用的自定义钩hook

更新日期: 2018-11-23阅读: 2.9k标签: Hook

vue.js 是我使用的第一个 JavaScript 框架。 我可以说 Vue.js 是我进入 JavaScript 世界的第一扇门之一。 

目前,Vue.js 仍然是一个很棒的框架。 我认为有了组合 api,Vue.js 只会增长得更多。 在本文中,我将向分享 10 个可以使用 Vue.js 制作的有用的自定义钩hook。


1、使用窗口调整大小

这是一个基本的hook。 因为它在许多项目中使用,并且使用纯 JavaScript 或任何框架构建它太容易了。 

与 Vue 相同,只需几行代码即可构建它。 

这是我的代码:

import { ref, onMounted, onUnmounted } from 'vue';

export function useWindowResize() {
const width = ref(window.innerWidth);
const height = ref(window.innerHeight);
const handleResize = () => {
width.value = window.innerWidth;
height.value = window.innerHeight;
}

onMounted(() => {
window.addEventListener('resize', handleResize)
});

onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})

return {
width,
height
}
}

不仅构建简单,而且使用起来也很容易。 只需要调用这个钩子即可获取窗口的宽度和高度:

setup() {
const { width, height } = useWindowResize();
}


2、使用存储

您想通过将数据值存储在会话存储或本地存储中并将该值绑定到视图来持久保存数据吗? 只需一个简单的hook——useStorage,一切就变得如此简单。 

我们只需要创建一个hook,返回从存储中获取的数据,以及一个在我们想要更改数据时将数据存储在存储中的函数。 

这是我的代码。

import { ref } from 'vue';

const getItem = (key, storage) => {
let value = storage.getItem(key);
if (!value) {
return null;
}
try {
return JSON.parse(value)
} catch (error) {
return value;
}
}

export const useStorage = (key, type = 'session') => {
let storage = null;
switch (type) {
case 'session':
storage = sessionStorage;
break;
case 'local':
storage = localStorage;
break;
default:
return null;
}
const value = ref(getItem(key, storage));
const setItem = (storage) => {
return (newValue) => {
value.value = newValue;
storage.setItem(key, JSON.stringify(newValue));
}
}
return [
value,
setItem(storage)
]
}

在我的代码中,我使用 JSON.parse 和 JSON.stringify 来格式化数据。 

如果您不想格式化它,可以将其删除。 这是如何使用此hook的示例。

const [token, setToken] = useStorage('token');
setToken('new token');


3、使用网络状态

这是一个有用的hook,支持检查网络连接的状态。 为了实现这个hook,我们需要为“在线”和“离线”事件添加事件监听器。 

在事件中,我们只是调用一个回调函数,参数为网络状态。 

这是我的代码:

import { onMounted, onUnmounted } from 'vue';

export const useNetworkStatus = (callback = () => { }) => {
const updateOnlineStatus = () => {
const status = navigator.onLine ? 'online' : 'offline';
callback(status);
}

onMounted(() => {
window.addEventListener('online', updateOnlineStatus);
window.addEventListener('offline', updateOnlineStatus);
});

onUnmounted(() => {
window.removeEventListener('online', updateOnlineStatus);
window.removeEventListener('offline', updateOnlineStatus);
})
}

只是简单易用。 

目前,我使用参数“online”/“offline”调用回调函数。 您可以将其更改为真/假或任何您想要的。

useNetworkStatus((status) => { 
console.log(`Your network status is ${status}`);
}


4、使用复制到剪贴板

将文本复制到剪贴板是每个项目中都很流行的功能。 我知道我们可以创建一个函数来代替钩子来做到这一点。 

但我喜欢数字 10,所以我决定在这篇文章中加入这个hook。 这个hook非常简单,只需返回一个支持将文本复制到剪贴板的函数即可。

function copyToClipboard(text) {
let input = document.createElement('input');
input.setAttribute('value', text);
document.body.appendChild(input);
input.select();
let result = document.execCommand('copy');
document.body.removeChild(input);
return result;
}

export const useCopyToClipboard = () => {
return (text) => {
if (typeof text === "string" || typeof text == "number") {
return copyToClipboard(text);
}
return false;
}
}

在我的代码中,我在函数 copyToClipboard 中将逻辑复制文本放入剪贴板。 我知道我们有很多方法可以做到这一点。 你可以在此功能中尝试最适合你的方法。 

至于如何使用,调用即可。

const copyToClipboard = useCopyToClipboard();
copyToClipboard('just copy');


5、使用主题

只需一个简短的钩子即可更改网站的主题。 它可以帮助我们轻松切换网站的主题,只需用主题名称调用此hook即可。 这是我用来定义主题变量的 css 代码示例。

html[theme="dark"] {
--color: #FFF;
--background: #333;
}
html[theme="default"], html {
--color: #333;
--background: #FFF;
}

要更改主题,我们只需要创建一个自定义挂钩,它将返回一个通过主题名称更改主题的函数。 

这是我的这个钩子的代码:

export const useTheme = (key = '') => {
return (theme) => {
document.documentElement.setAttribute(key, theme);
}
}

而且使用起来太方便了。

const changeTheme = useTheme();
changeTheme('dark');


6、使用页面可见性

有时,当客户不关注我们的网站时,我们需要做一些事情。 为此,我们需要一些东西来让我们知道用户是否集中注意力。 这是一个定制的hook。 

我称之为 usePageVisibility,下面是该hook的代码:

import { onMounted, onUnmounted } from 'vue';

export const usePageVisibility = (callback = () => { }) => {
let hidden, visibilityChange;
if (typeof document.hidden !== "undefined") {
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}

const handleVisibilityChange = () => {
callback(document[hidden]);
}

onMounted(() => {
document.addEventListener(visibilityChange, handleVisibilityChange, false);
});

onUnmounted(() => {
document.removeEventListener(visibilityChange, handleVisibilityChange);
});
}

要使用这个hook,我们只需要创建一个带有客户端隐藏状态(焦点状态)参数的回调函数。

usePageVisibility((hidden) => {
console.log(`User is${hidden ? ' not' : ''} focus your site`);
});


7、使用视口

在第一个自定义hook中,我们构建了useWindowRezie,它可以帮助我们查看窗口的当前宽度和高度。 

我认为这对于那些想要构建适用于多种屏幕尺寸的东西的人很有帮助。 

在我处理过的案例中,我们经常使用宽度来检测当前用户设备。 它可以帮助我们在他们的设备上安装一些东西。 

在此hook中,我将使用 useWindowResize 构建相同的内容,但它返回设备名称而不是宽度和高度值。 

这是这个hook的代码。

import { ref, onMounted, onUnmounted } from 'vue';

export const MOBILE = 'MOBILE'
export const TABLET = 'TABLET'
export const DESKTOP = 'DESKTOP'

export const useViewport = (config = {}) => {
const { mobile = null, tablet = null } = config;
let mobileWidth = mobile ? mobile : 768;
let tabletWidth = tablet ? tablet : 922;
let device = ref(getDevice(window.innerWidth));
function getDevice(width) {
if (width < mobileWidth) {
return MOBILE;
} else if (width < tabletWidth) {
return TABLET;
}
return DESKTOP;
}

const handleResize = () => {
device.value = getDevice(window.innerWidth);
}

onMounted(() => {
window.addEventListener('resize', handleResize);
});

onUnmounted(() => {
window.removeEventListener('resize', handleResize);
});

return {
device
}
}

它是如此容易。 除了默认的设备尺寸之外,当我们使用包含手机和平板电脑尺寸的参数对象调用该hook时,用户可以修改它。 这是我们使用它的方式:

const { device } = useViewport({ mobile: 700, table: 900 });


8、使用OnClickOutside

目前,模态被用于许多应用程序中。 它对于许多用例(表单、确认、警告等)确实很有帮助。 

我们经常用它处理的流行操作之一是用户在模式之外单击。 useonClickOutside 对于这种情况是一个有用的hook。 

我们只需要一个 ref 元素、回调函数并将其绑定到窗口事件中。 这是我的代码(适用于桌面和移动设备):

import { onMounted, onUnmounted } from 'vue';

export const useOnClickOutside = (ref = null, callback = () => {}) => {
function handleClickOutside(event) {
if (ref.value && !ref.value.contains(event.target)) {
callback()
}
}

onMounted(() => {
document.addEventListener('mousedown', handleClickOutside);
})

onUnmounted(() => {
document.removeEventListener('mousedown', handleClickOutside);
});
}

正如我所说,要使用它,我们只需要使用参数 ref 元素和回调函数来调用它。

<template>
<div ref="container">View</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const container = ref(null);
useOnClickOutside(container, () => {
console.log('Clicked outside');
})
}
}
</script>


9、使用滚动到底部

除了分页列表之外,加载更多(或延迟加载)是加载数据的一种友好方式。 特别是对于移动设备,几乎在移动设备上运行的应用程序都会在其 UI 中加载更多负载。 为此,我们需要检测用户滚动到列表底部并触发该事件的回调。 

useScrollToBottom 是一个有用的hook来支持您这样做。 这是我构建该hook的代码:

import { onMounted, onUnmounted } from 'vue';

export const useScrollToBottom = (callback = () => { }) => {
const handleScrolling = () => {
if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
callback();
}
}

onMounted(() => {
window.addEventListener('scroll', handleScrolling);
});

onUnmounted(() => {
window.removeEventListener('scroll', handleScrolling);
});
}

在我的hook中,我通过条件“((window.innerHeight + window.scrollY) >= document.body.scrollHeight)”检测到底部。 

我们有很多方法来检测它。 如果您的项目符合其他条件,我们就使用它们。 以下是如何使用此hook的示例:

useScrollToBottom(() => { console.log('Scrolled to bottom') })


10、使用定时器

最后,我们来到最后一个钩子。 这个钩子的代码比其他钩子要长一些。 useTimer 将支持我们运行带有一些选项的计时器,例如开始、暂停/恢复、停止。 

为此,我们需要使用 setInterval 方法,在该方法中,我们将推送处理函数。 在那里,我们需要检查计时器的暂停状态。 

如果计时器没有暂停,我们只需要调用一个回调函数,该函数由用户作为参数传递。 

为了支持用户了解该计时器的当前暂停状态,除了 useTimer 操作之外,还为他们提供一个变量 isPaused ,其值作为计时器的暂停状态。 

这是我构建该hook的代码:

import { ref, onUnmounted } from 'vue';

export const useTimer = (callback = () => { }, step = 1000) => {
let timerVariableId = null;
let times = 0;
const isPaused = ref(false);

const stop = () => {
if (timerVariableId) {
clearInterval(timerVariableId);
timerVariableId = null;
resume();
}
}

const start = () => {
stop();
if (!timerVariableId) {
times = 0;
timerVariableId = setInterval(() => {
if (!isPaused.value) {
times++;
callback(times, step * times);
}
}, step)
}
}

const pause = () => {
isPaused.value = true;
}

const resume = () => {
isPaused.value = false;
}

onUnmounted(() => {
if (timerVariableId) {
clearInterval(timerVariableId);
}
})

return {
start,
stop,
pause,
resume,
isPaused
}
}

这是使用 useTimer hook的一种方法:

function handleTimer(round) {      
roundNumber.value = round;
}
const {
start,
stop,
pause,
resume,
isPaused
} = useTimer(handleTimer);

到这里,我已经跟大家分享了10 个有用的 Vue.js hook。 我认为它们的构建和使用都很简单。 我只是为那些想要在 Vue.js 中使用这些钩子的人提供一些注释。

请记住删除要添加到窗口的事件。 Vue 为我们提供了一个有用的组合 API onUnmounted ,它可以帮助我们在卸载hook之前运行我们的操作。 

在我构建的每个钩子中,我总是删除 onUnmounted 中的事件侦听器。

仅在真正需要时才使用反应变量。 如果您想使用一个存储某些内容的变量,并且希望在数据更改时同步其数据,那么,让我们使用反应式变量。 

但如果它只是一个在我们的hook中存储数据的变量(计数器、标志......),我认为你不需要使用反应变量。

如果可以的话,不要在钩子中进行硬编码(设置固定值)。 

我认为我们只需要将逻辑存储在我们的hook中。 关于配置值,我们应该让用户填写它(例如:useViewport)。

最后,在我的文章中,我与您分享了10 个有用的 Vue 自定义hook,我希望它们对您有所帮助。 Vue.js 是一个很棒的框架,我希望你可以用它构建更多很棒的东西。

英文 | https://javascript.plainenglish.io/10-useful-custom-hooks-with-vue-js-37f0fd42ce0d

链接: https://www.fly63.com/article/detial/1394

pytest插件探索——hook开发

conftest.py可以作为最简单的本地plugin调用一些hook函数,以此来做些强化功能。pytest整个框架通过调用如下定义良好的hooks来实现配置,收集,执行和报告这些过程:

React中useState Hook 示例

到 React 16.8 目前为止,如果编写函数组件,然后遇到需要添加状态的情况,咱们就必须将组件转换为类组件。编写 class Thing extends React.Component,将函数体复制到render()方法中,修复缩进,最后添加需要的状态。

useContext Hook 是如何工作的?

所有这些新的React Hook之间都有一个宗旨:就是为了使函数组件像类组件一样强大。useContext hook 与其它几个有点不一样,但它在特定场景下还是很有用的。React 的 Context API 是一种在应用程序中深入传递数据的方法

结合React的Effect Hook分析组件副作用的清除

我们在DidMount的时候通过ID订阅了好友的在线状态,并且为了防止内存泄漏,我们需要在WillUnmount清除订阅,但是当组件已经显示在屏幕上时,friend prop 发生变化时会发生什么?

结合高阶函数聊聊useMemo和useCallback

useCallback和useMemo是其中的两个 hooks,本文旨在通过解决一个需求,结合高阶函数,深入理解useCallback和useMemo的用法和使用场景。 之所以会把这两个 hooks 放到一起说,是因为他们的主要作用都是性能优化

关于为什么使用React新特性Hook的一些实践与浅见

Hook是对函数式组件的一次增强,使得函数式组件可以做到class组件的state和生命周期。Hook的语法更加简练易懂,消除了class的生命周期方法导致的重复逻辑代码,解决了高阶组件难以理解和使用困难的问题。

React封装强业务hook的一个例子

最近因为使用列表展示的需求有点多,就想着把列表分页筛选的逻辑抽象一下。看了umi的一个useTable的hook,也不能满足业务需要,于是就自己写了一个,支持本地分页筛选和接口分页筛选。

React官方团队出手,补齐原生Hook短板

然而实际上,由于回调函数被useCallback缓存,形成闭包,所以点击的效果始终是sendMessage()。这就是「闭包陷阱」。以上代码的一种解决方式是「为useCallback增加依赖项」

实现一个自定义 React Hook:UseLocalStorageState

最近做需求,需要将数据保存到 localStorage 里,在组件初始化的时候获取,然后修改该值的时候,要保存到本地的 localStorage 中。很显然,这些逻辑完全可以封装为一个 React Hook

为什么Hook没有ErrorBoundary?

在很多全面使用Hooks开发的团队,唯一使用ClassComponent的场景就是使用ClassComponent创建ErrorBoundary。可以说,如果Hooks存在如下两个生命周期函数的替代品,就能全面抛弃ClassComponent了:

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!