10 useful custom hooks for vue.js

Author: Sang Nguyen Translator: Front-end Xiaozhi Source: medium

If you have dreams and dry goods, you can search for [Great Move to the World] on WeChat and pay attention to this Shawanzhi who is still washing dishes in the early hours of the morning.

This article GitHub github.com/qq449245884... has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.

Vue was the first JS framework I used. It can be said that Vue was one of my first doors into the JavaScript world. For now, Vue is still a great framework. With the advent of the composition API, Vue will only grow even more. In this article, I will introduce 10 useful custom hooks to make our code look better.

useWindowResize

This is a basic hook as it is used in many projects.

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
  }
}
复制代码

It's easier to use, just call this hook to get the width and height of the window.

setup() {
    const { width, height } = useWindowResize();
}
复制代码

useStorage

Do you want to persist data by storing its value in session storage or local storage and bind that value to the view? With a simple hook -- useStorage , this becomes very easy. We just need to create a hook to return the data obtained from the storage space, and a function to store the data in the storage space when we want to change it. Below is my 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)
  ]
}
复制代码

In my code, I use JSON.parse** and JSON.stringify** to format the data. If you don't want to format it, you can delete it. Below is an example of how to use this hook.

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

The code for useTimer is a bit longer than other hooks. useTimerSupports running a timer with some options like start, pause/resume, stop. To do this, we need to use the setIntervalmethod . Here, we need to check the paused state of the timer. If the timer is not paused, we just need to call a callback function, which is passed by the user as a parameter. In order to support users to understand the current pause state of the timer, in addition to action useTimer, they should also be given a variable isPausedwhose value is the pause state of the timer. code show as below:

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
  }
}
复制代码

The usage is as follows:

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

This article shares 10 useful Vue custom hooks. Hope they are helpful to you. Vue. is a great framework, hope you can use it to build more great things.


The bugs that may exist after the code is deployed cannot be known in real time. In order to solve these bugs afterwards, a lot of time is spent on log debugging. By the way, I recommend a useful bug monitoring tool , Fundebug .

Original: javascript.plainenglish.io/10-useful-c…

communicate with

If you have dreams and dry goods, you can search for [Great Move to the World] on WeChat and pay attention to this Shawanzhi who is still washing dishes in the early hours of the morning.

This article GitHub github.com/qq449245884... has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.

Guess you like

Origin juejin.im/post/7084013999330689054