十个有用的自定义Vue钩子函数总结

目录
  • useWindowResize
  • useStorage
  • useNetworkStatus
  • useCopyToClipboard
  • useTheme
  • usePageVisibility
  • useViewport
  • useOnClickOutside
  • useScrollToBottom
  • useTimer

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

以上就是十个有用的自定义Vue钩子函数总结的详细内容,更多关于Vue钩子函数的资料请关注我们其它相关文章!

(0)

相关推荐

  • 深入理解Vue 的钩子函数

    前言 说到Vue的钩子函数,可能很多人只停留在一些很简单常用的钩子( created , mounted ),而且对于里面的区别,什么时候该用什么钩子,并没有仔细的去研究过,且Vue的生命周期在面试中也算是比较高频的考点,那么该如何回答这类问题,让人有眼前一亮的感觉呢... Vue-Router导航守卫 有的时候,我们需要通过路由来进行一些操作,比如最常见的登录权限验证,当用户满足条件时,才让其进入导航,否则就取消跳转,并跳到登录页面让其登录. 为此我们有很多种方法可以植入路由的导航过程: 全局

  • vue 自定义指令directives及其常用钩子函数说明

    目录 自定义指令directives及常用钩子函数 说明 钩子函数 vue 全局定义 局部定义(vue-cli) 钩子函数里面的参数 vue 自定义指令 directives选项 directives选项中定义 指令 自定义指令directives及常用钩子函数 说明 除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令 使用的地方:有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令 钩子函数 inserted:被绑定元素插

  • Vue指令的钩子函数使用方法

    在Vue 中可以把一系列复杂的操作包装为一个指令. 什么是复杂的操作? 我的理解是:复杂逻辑功能的包装.违背数据驱动的 DOM 操作以及对一些 Hack 手段的掩盖等.我们总是期望以操作数据的形式来实现功能逻辑. 钩子函数 对于自定义指令的定义,Vue2 有 5 个可选的钩子函数. bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作. inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中).

  • vue中的生命周期及钩子函数

    目录 1.什么是生命周期 2.vue 的生命周期 3.生命周期钩子函数 1.什么是生命周期 Vue 实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载 Dom.渲染 → 更新 → 渲染.卸载等一系列过程,我们称这是 Vue 的生命周期.通俗说就是 Vue 实例从创建到销毁的过程,就是生命周期. 在 Vue 的整个生命周期中,它提供了一系列的事件,可以让我们在事件触发时注册 js 方法,可以让我们用自己注册的 js 方法控制整个大局,在这些事件响应方法中的 this 直接指向的

  • Vue生命周期中的八个钩子函数相机

    目录 1.beforeCreate和created函数 2.beforeMount和mounted函数 3.beforeUpdate和updated函数 4.beforeDestroy和destroyed函数 总结 1.beforeCreate和created函数 beforeCreate和created以初始化:数据监测.数据代理为分界线. 在执行beforeCreate()之前,将初始化生命周期.时间,但数据代理还没有开始. (1)beforeCreate():在初始化数据监测.数据代理之前

  • 十个有用的自定义Vue钩子函数总结

    目录 useWindowResize useStorage useNetworkStatus useCopyToClipboard useTheme usePageVisibility useViewport useOnClickOutside useScrollToBottom useTimer Vue 是我使用的第一个 JS 框架.可以说,Vue 是我进入JavaScript世界的第一道门之一.目前,Vue 仍然是一个很棒的框架.随着 composition API 的出现,Vue 只会有更

  • VUE中的自定义指令钩子函数讲解

    目录 自定义指令钩子函数 自定义指令 先上官方解释 小贴士 钩子函数运行顺序 自定义指令钩子函数 自定义指令 除了VUE 内置指令外,VUE也支持我们自定义注册指令,分为局部和全局注册 但这些想必大家都不陌生,其中官方API也是写的明明白白 官方API点这里 而且自定义指令也会极大程度上帮助我们日常的编程,但这是很有意思的事情出现了,就是钩子函数,很多老铁都弄不明白这五个函数的具体区别 先上官方解释 bind:只调用一次,指令第一次绑定到元素时调用.在这里可以进行一次性的初始化设置. inser

  • 详解Vue的钩子函数(路由导航守卫、keep-alive、生命周期钩子)

    前言 说到Vue的钩子函数,可能很多人只停留在一些很简单常用的钩子(created,mounted),而且对于里面的区别,什么时候该用什么钩子,并没有仔细的去研究过,且Vue的生命周期在面试中也算是比较高频的考点,那么该如何回答这类问题,让人有眼前一亮的感觉呢... Vue-Router导航守卫: 有的时候,我们需要通过路由来进行一些操作,比如最常见的登录权限验证,当用户满足条件时,才让其进入导航,否则就取消跳转,并跳到登录页面让其登录. 为此我们有很多种方法可以植入路由的导航过程:全局的, 单

  • vue.js动画中的js钩子函数的实现

    在transition中还可以通过设置javascript钩子函数,实现自定义动画效果. 以实现击球效果为例: 击球 代码解析: <!-- 定义js的钩子函数 --> <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" > <img v-show="flag" class="ba

  • 解决Vue中mounted钩子函数获取节点高度出错问题

    遇到的问题 最近在开发一个Vue的项目,好几个页面都有用到一个 页面楼层滑动的组件,我就直接封装成了一个,但是遇到一个bug,就是我需要得到这个组件的offsetTop,然后页面滚动到这个位置的时候,就设置position属性为fixed,让他固定在屏幕上.问题是当我在mounted钩子函数中获取offsetTop的时候,在新开的页签中打开页面,会得到错误的offsetTop,但是在当前页面刷新,就不会有问题. 定位问题 后来查到问题,就是加载的问题,新窗口打开图片,默认是没有带缓存的,图片是G

  • vue动画—通过钩子函数实现半场动画操作

    注意: 1.起始位置设置了一个(0,0)在第一遍执行时,是没有作用的.在一次入场动画执行完成之后,在最终位置停下来并不在起始位置,通过这里的位置的设置可以将入场动画结束时的位置调到这里 2.理解enter()函数的el的指代对象和done()指代的回调函数 3.理解this.show = !this.show,这句话有两个作用.一是:控制显示和隐藏,二是:false -> true为半场动画,true->false又是为另半场动画.这样就能完成一直循环执行半场动画的效果了. HTML代码: &

  • 理解Vue2.x和Vue3.x自定义指令用法及钩子函数原理

    目录 Vue2.x用法 全局注册 局部注册 使用 钩子函数 钩子函数的参数 Vue3.x用法 全局注册 局部注册 使用 钩子函数 较 Vue2.x 相比, 钩子函数有变化 Vue2.x用法 全局注册 Vue.directive( 指令名, { 自定义指令生命周期 } ) 局部注册 directives: { 指令名, { 自定义指令生命周期 } } 使用 v-指令名: 属性名.修饰符="value值" 钩子函数 bind - 自定义指令绑定到 DOM 后调用. 只调用一次, 注意: 只

随机推荐