10个有用的自定义钩子vue.js

Posted @大迁世界

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10个有用的自定义钩子vue.js相关的知识,希望对你有一定的参考价值。

作者:Sang Nguyen
译者:前端小智
来源:medium

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

Vue 是我使用的第一个 JS 框架。可以说,Vue 是我进入javascript世界的第一道门之一。目前,Vue 仍然是一个很棒的框架。随着 composition API 的出现,Vue 只会有更大的发展。在这篇文章中,我将介绍 10 个有用的自定义钩子,让我们的代码更加好看。

useWindowResize

这是一个基本的钩子,因为它被用在很多项目中.

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
  

使用就更简单了,只需要调用这个钩子就可以获得 window 的宽度和高度。

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

useStorage

你想通过在 session storage 或 local storage 中存储数据的值来持久化数据,并将该值绑定到视图?有了一个简单的钩子–useStorage,这将变得非常容易。我们只需要创建一个钩子来返回从存储空间得到的数据,以及一个函数来在我们想要改变数据时将其存储在存储空间。下面是我的钩子。

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** 来格式化数据。如果你不想格式化它,你可以删除它。下面是一个如何使用这个钩子的例子。

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

useNetworkStatus

这是一个有用的钩子,支持检查网络连接的状态。为了实现这个钩子,我们需要为事件 "在线"和 "离线"添加事件监听器。在事件中,我们只是调用一个回调函数,参数为网络状态。下面是我的代码。

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);
  )

调用方式:

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

useCopyToClipboard

剪切板是一个比较常见的功能,我们也可以将它封装成 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;
  

使用如下:

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

useTheme

只是一个简短的钩子来改变网站的主题。它可以帮助我们轻松地切换网站的主题,只需用主题名称调用这个钩子。下面是一个我用来定义主题变量的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');

usePageVisibility

有时,当客户不专注于我们的网站时,我们需要做一些事情。要做到这一点,我们需要一些东西,让我们知道用户是否在关注。这是一个自定义的钩子。我把它叫做 PageVisibility,代码如下:

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);
  );

用法如下:

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

useViewport

有时我们会用宽度来检测当前的用户设备,这样我们就可以根据设备来处理对应的内容。这种场景,我们也可以封装成一个 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
  

使用如下:

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

useOnClickOutside

当 model 框弹出时,我们希望能点击其它区域关闭它,这个可以使用 clickOutSide,这种场景我们也可以封装成钩子,代码如下:

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);
  );

用法如下:

<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>

useScrollToBottom

除了分页列表,加载更多(或懒惰加载)是一种友好的加载数据的方式。特别是对于移动设备,几乎所有运行在移动设备上的应用程序都在其用户界面中应用了load more。要做到这一点,我们需要检测用户滚动到列表底部,并为该事件触发一个回调。 useScrollToBottom 是一个有用的钩子,支持你这样做。代码如下:

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);
  );

用法如下:

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

useTimer

useTimer 的代码比其他钩子要长一些。 useTimer 支持运行一个带有一些选项的定时器,如开始、暂停/恢复、停止。要做到这一点,我们需要使用 setInterval 方法。在这里,我们需要检查定时器的暂停状态。如果定时器没有暂停,我们只需要调用一个回调函数,该函数由用户作为参数传递。为了支持用户了解该定时器当前的暂停状态,除了action useTimer之外,还要给他们一个变量 isPaused,其值为该定时器的暂停状态。代码如下:

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
  

用法如下:

function handleTimer(round)       
    roundNumber.value = round;    

const  
    start,
    stop,
    pause,
    resume,
    isPaused
 = useTimer(handleTimer);

本文分享了10个有用的Vue自定义钩子。希望它们对你有帮助。Vue. 是一个很棒的框架,希望你能用它来构建更多很棒的东西。


代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

原文:https://javascript.plainenglish.io/10-useful-custom-hook-with-vue-js-37f0fd42ce0d

交流

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

以上是关于10个有用的自定义钩子vue.js的主要内容,如果未能解决你的问题,请参考以下文章

最简单的方式理解Vue的自定义指令

Vue.js - 带有自定义叠加层的自定义照片网格

Vue.js 中的自定义指令

vue.js实现内部自定义指令和全局自定义指令------directive

如何从 Vue.js 2 中的自定义指令中获取文字表达式?

创建永不重建的自定义钩子