Written by Sang Nguyen

Have a dream, have dry goods, wechat search [big Move the world] pay attention to this in the early morning is still in the bowl washing wisdom.

In this paper, making github.com/qq449245884… Has been included, a line of large factory interview complete test sites, information and my series of articles.

Vue was the first JS framework I used. Vue was one of my first doors into the JavaScript world. For now, Vue is still a great framework. Vue can only grow with the advent of composition apis. In this article, I’ll introduce 10 useful custom hooks to make our code look better.

useWindowResize

This is a basic hook because 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
  }
}
Copy the code

It’s much easier to use, simply calling the hook to get the width and height of the window.

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

useStorage

Do you want to persist data by storing its value in session storage or local storage and binding that value to the view? With a simple hook, useStorage, this becomes very easy. We just need to create a hook to return data from storage and a function to store data in storage if we want to change it. Here’s 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) ] }Copy the code

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. Here is an example of how to use this hook.

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

useNetworkStatus

This is a useful hook for checking the status of a network connection. To implement this hook, we need to add event listeners for events “online” and “offline”. In the event, we simply call a callback function that takes the network state. Here is my code.

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); })}Copy the code

Call method:

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

useCopyToClipboard

A clipboard is a common feature, but it can also be wrapped as a hook, as shown below:

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; }}Copy the code

Use as follows:

const copyToClipboard = useCopyToClipboard();
copyToClipboard('just copy');
Copy the code

useTheme

Just a short hook to change the theme of the site. It allows you to easily switch the theme of your site by simply calling this hook with the theme name. Here is an example of CSS code I used to define theme variables.

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

To change the theme, just make a custom hook that returns a function to change the theme by the theme name. The code is as follows:

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

Use as follows:

const changeTheme = useTheme();
changeTheme('dark');
Copy the code

usePageVisibility

Sometimes there are things we need to do when customers are not focused on our site. To do that, we need something that lets us know if users are paying attention. This is a custom hook. I’ll call it PageVisibility and the code is as follows:

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); }); }Copy the code

Usage:

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

useViewport

Sometimes we use the width to detect the current user device so that we can process the content according to the device. This scenario can also be encapsulated as a hook with the following code:

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
  }
}
Copy the code

Use as follows:

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

useOnClickOutside

When the Model box pops up, we want to be able to click on another area to close it. This can be done using 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); }); }Copy the code

Usage:

<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>
Copy the code

useScrollToBottom

In addition to paged lists, loading more (or lazy loading) is a friendly way to load data. Especially for mobile devices, almost all applications running on mobile devices have Load More applied to their user interfaces. To do this, we need to detect the user scrolling to the bottom of the list and trigger a callback for that event. UseScrollToBottom is a useful hook that allows you to do this. The code is as follows:

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);
  });
}
Copy the code

Usage:

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

useTimer

The useTimer code is longer than the other hooks. UseTimer supports running a timer with options such as start, pause/resume, and Stop. To do this, we need to use the setInterval method. Here, we need to check the pause status of the timer. If the timer is not paused, all we need to do is call a callback function that is passed by the user as an argument. To enable users to know the current paused state of the timer, in addition to the Action useTimer, they are also given a variable isPaused, whose value is the paused state of the timer. The code is as follows:

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 } }Copy the code

Usage:

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

This article shares 10 useful Vue custom hooks. I hope they are helpful. Vue. Is a great framework and hopefully you can use it to build more great things.


The bugs that may exist after code deployment cannot be known in real time. In order to solve these bugs, I spent a lot of time on log debugging. Incidentally, I recommend a good BUG monitoring tool for youFundebug.

Original text: javascript. Plainenglish. IO / 10 – useful – c…

communication

Have a dream, have dry goods, wechat search [big Move the world] pay attention to this in the early morning is still in the bowl washing wisdom.

In this paper, making github.com/qq449245884… Has been included, a line of large factory interview complete test sites, information and my series of articles.