十个有用的 Vue.js 自定义 Hook

news2024/11/30 6:35:15

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');
  • 1.
  • 2.
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,
    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 是一个很棒的框架,我希望你可以用它构建更多很棒的东西。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1054920.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机竞赛 深度学习手势识别 - yolo python opencv cnn 机器视觉

文章目录 0 前言1 课题背景2 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 3 YOLOV53.1 网络架构图3.2 输入端3.3 基准网络3.4 Neck网络3.5 Head输出层 4 数据集准备4.1 数据标注简介4.2 数据保存 5 模型训练5.1 修…

竞赛 多目标跟踪算法 实时检测 - opencv 深度学习 机器视觉

文章目录 0 前言2 先上成果3 多目标跟踪的两种方法3.1 方法13.2 方法2 4 Tracking By Detecting的跟踪过程4.1 存在的问题4.2 基于轨迹预测的跟踪方式 5 训练代码6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习多目标跟踪 …

【笔试强训day01】组队竞赛 删除公共字符

​&#x1f47b;内容专栏&#xff1a; 笔试强训集锦 &#x1f428;本文概括&#xff1a;C笔试面试常考题之笔试强训day01。 &#x1f43c;本文作者&#xff1a; 阿四啊 &#x1f438;发布时间&#xff1a;2023.10.1 一、day01 1.组队竞赛 题目描述 题目描述&#xff1a;牛牛举…

【JavaEE】JavaScript

JavaScript 文章目录 JavaScript组成书写方式行内式内嵌式外部式&#xff08;推荐写法&#xff09; 输入输出变量创建动态类型基本数据类型数字类型特殊数字值 String转义字符求长度字符串拼接布尔类型undefined未定义数据类型null 运算符条件语句if语句三元表达式switch 循环语…

【算法|贪心算法系列No.3】leetcode334. 递增的三元子序列

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

[C++_containers]10分钟让你掌握vector

前言 在一个容器的创建或是使用之前&#xff0c;我们应该先明白这个容器的一些特征。 我们可以通过文档来来了解&#xff0c;当然我也会将重要的部分写在下面。 1. vector 是表示可变大小数组的序列容器。 2. 就像数组一样&#xff0c; vector 也采用的连续存储空间来存储元…

picoctf_2018_shellcode

picoctf_2018_shellcode Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments32位&#xff0c;啥都没开 这个看着挺大的&#xff0c;直接来个ROPchain&#xff0c;…

Mapfree智驾方案,怎样实现成本可控?

整理|睿思 编辑|祥威 编者注&#xff1a;本文是HiEV出品的系列直播「智驾地图之变」第二期问答环节内容整理。 元戎启行副总裁刘轩与连线嘉宾奥维咨询董事合伙人张君毅、北汽研究总院智能网联中心专业总师林大洋、主持嘉宾周琳展开深度交流&#xff0c;并进行了答疑。 本期元…

新手--安装好Quartus II13.0(带modelsim集成包)并用Quartus II搭建一个工程

前言 今天是国庆节&#xff0c;我们正式来学习Quartus II13.0软件的安装与使用。学习verilog与学习C语言都是学习一门语言&#xff0c;那么学习一门语言&#xff0c;光看理论不敲代码绝对是学习不好的。要用verilog语言敲代码&#xff0c;就要像C语言那样搭建起语言的编译环境&…

USART串口协议

通信接口 •通信的目的&#xff1a;将一个设备的数据传送到另一个设备&#xff0c;扩展硬件系统 • 通信协议&#xff1a;制定通信的规则&#xff0c;通信双方按照协议规则进行数据收发 全双工&#xff1a;指通信双方能够同时进行双向通信&#xff0c;一般来说&#xff0c;全双…

扩容领跑者 Arbitrum 抢占 Layer3 竞争高地

近段时间以来&#xff0c;Arbitrum 凭借创新技术和优越生态系统逐渐成为顶尖的以太坊扩容解决方案。当新一轮 Layer3 竞争在 Rollup 领域展开时&#xff0c;Arbitrum 和 Optimism 始终是备受瞩目的两大角色。Optimism 以独特的 OP Stack 进行水平扩展&#xff0c;而 Arbitrum 则…

K-Means(下):数据分析 | 数据挖掘 | 十大算法之一

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ &#x1f434;作者&#xff1a;秋无之地 &#x1f434;简介&#xff1a;CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作&#xff0c;主要擅长领域有&#xff1a;爬虫、后端、大数据…

shell脚本使用(宿主机windows-服务器-centos)--用于使用shell脚本方式控制docker容器

需求: 我想要使得windows上编写shell脚本&#xff0c;并且在这个shell脚本在linux中也可用 shell脚本在windows上无法直接运行&#xff0c;但是有WSL这个linux子系统的工具 可以使得shell脚本在主机上执行 视频讲解连接 https://www.bilibili.com/video/BV1Tw411Y7FP/方式1 …

Object.defineProperty()方法详解,了解vue2的数据代理

假期第一篇&#xff0c;对于基础的知识点&#xff0c;我感觉自己还是很薄弱的。 趁着假期&#xff0c;再去复习一遍 Object.defineProperty(),对于这个方法&#xff0c;更多的还是停留在面试的时候&#xff0c;面试官问你vue2和vue3区别的时候&#xff0c;不免要提一提这个方法…

【VIM】VIm-plug插件

如何查找需要的插件 https://github.com/mhinz/vim-startify https://github.com/vim-airline/vim-airline https://github.com/Yggdroot/indentLine github.com/w0ng/vim-hybrid github.com/altercationi/vim-colors-solarized guithub.com/morhetz/gruvbox github.com/sc…

cesium 雷达扫描 (波纹线性雷达扫描效果)

cesium 雷达扫描 (波纹线性雷达扫描效果) 1、实现方法 使用ellipse方法加载圆型,修改ellipse中material方法来实现效果 2、示例代码 2.1 <!DOCTYPE html> <html lang="en"><head>&l

NSSCTF做题(3)

[鹤城杯 2021]EasyP 代码审计 <?php include utils.php; if (isset($_POST[guess])) { $guess (string) $_POST[guess]; if ($guess $secret) {//两个变量相等 $message Congratulations! The flag is: . $flag; } else { $message Wron…

java多线程相关介绍

1. 线程的创建和启动 在 Java 中创建线程有两种方式。一种是继承 Thread 类并重写其中的 run() 方法&#xff0c;另一种是实现 Runnable 接口并重写其中的 run() 方法。创建完线程对象后&#xff0c;调用 start() 方法可以启动线程。 2. 线程的状态 Java 的线程在不同阶段会处于…

计算机竞赛 深度学习火车票识别系统

文章目录 0 前言1 课题意义课题难点&#xff1a; 2 实现方法2.1 图像预处理2.2 字符分割2.3 字符识别部分实现代码 3 实现效果4 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 图像识别 火车票识别系统 该项目较为新颖&#xff0c;适…

牛客网_HJ2_计算某字符出现次数

HJ2_计算某字符出现次数 原题思路代码运行截图收获 原题 HJ2_计算某字符出现次数 思路 把输入的字符串和字符都变成大写或小写&#xff0c;然后逐一计数 代码 #include <cctype> #include <iostream> #include <string> #include <algorithm> usi…