乐趣区

关于javascript:10个有用的自定义钩子vuejs

作者: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.plainengli…

交换

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

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

退出移动版