相关文章推荐
逃课的茶壶  ·  如何用three.js繪製一個四面填充不同材 ...·  6 天前    · 
谈吐大方的仙人球  ·  如何用three.js繪製一個四面填充不同材 ...·  6 天前    · 
重情义的小马驹  ·  枘凿六合,天下第一 | 小前端·  6 天前    · 
独立的树叶  ·  GitHub - ...·  5 天前    · 
重情义的冲锋衣  ·  你可能不需要 Effect – React ...·  3 天前    · 
爱喝酒的白开水  ·  Netflix ...·  1 年前    · 
发财的青椒  ·  【日产】日产汽车报价_图片_日产新款车型_网易汽车·  1 年前    · 
被表白的米饭  ·  我国规模最大的高校学情调查是怎么炼成的? ...·  1 年前    · 
老实的红豆  ·  最爱你的那十年_百度百科·  1 年前    · 
道上混的滑板  ·  类型漫画作品大全-相关漫画全集-爱奇艺叭嗒·  1 年前    · 
Code  ›  分享 10 个有用的 Vue.js 自定义 Hook开发者社区
vue const
https://cloud.tencent.com/developer/article/2336559
安静的签字笔
1 年前
前端达人

分享 10 个有用的 Vue.js 自定义 Hook

腾讯云
开发者社区
文档 建议反馈 控制台
首页
学习
活动
专区
工具
TVP
最新优惠活动
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP 最新优惠活动
返回腾讯云官网
前端达人
首页
学习
活动
专区
工具
TVP 最新优惠活动
返回腾讯云官网
社区首页 > 专栏 > 分享 10 个有用的 Vue.js 自定义 Hook

分享 10 个有用的 Vue.js 自定义 Hook

作者头像
前端达人
发布 于 2023-10-09 10:17:41
213 0
发布 于 2023-10-09 10:17:41
举报
文章被收录于专栏: 前端达人 前端达人

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

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

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

01、使用窗口调整大小

这是一个基本的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();
}

02、使用存储

您想通过将数据值存储在会话存储或本地存储中并将该值绑定到视图来持久保存数据吗? 只需一个简单的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');

03、使用网络状态

这是一个有用的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}`);
}

04、使用复制到剪贴板

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

但我喜欢数字 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');

05、使用主题

只需一个简短的钩子即可更改网站的主题。 它可以帮助我们轻松切换网站的主题,只需用主题名称调用此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');

06、使用页面可见性

有时,当客户不关注我们的网站时,我们需要做一些事情。 为此,我们需要一些东西来让我们知道用户是否集中注意力。 这是一个定制的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`);
});

07、使用视口

在第一个自定义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 });

08、使用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>

09、使用滚动到底部

除了分页列表之外,加载更多(或延迟加载)是加载数据的一种友好方式。 特别是对于移动设备,几乎在移动设备上运行的应用程序都会在其 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,
 
推荐文章
逃课的茶壶  ·  如何用three.js繪製一個四面填充不同材質的正四面體? - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天
6 天前
谈吐大方的仙人球  ·  如何用three.js繪製一個四面填充不同材質的正四面體? - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天
6 天前
重情义的小马驹  ·  枘凿六合,天下第一 | 小前端
6 天前
独立的树叶  ·  GitHub - croxs-power/QJson: 基于 "开源库cJSON" 进行Qt版本的二次封装,支持Qt4、Qt5,比Qt5自带的json处理库要方便一些
5 天前
重情义的冲锋衣  ·  你可能不需要 Effect – React 中文文档
3 天前
爱喝酒的白开水  ·  Netflix 3000万美元买下暴走漫画动画电影全球发行权
1 年前
发财的青椒  ·  【日产】日产汽车报价_图片_日产新款车型_网易汽车
1 年前
被表白的米饭  ·  我国规模最大的高校学情调查是怎么炼成的? | CCSS专题_研究
1 年前
老实的红豆  ·  最爱你的那十年_百度百科
1 年前
道上混的滑板  ·  类型漫画作品大全-相关漫画全集-爱奇艺叭嗒
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号