5 个可以加速开发的 VueUse 函数库

大厂光环
• 阅读 6012

VueUse 是 Anthony Fu 的一个开源项目,它为 Vue 开发人员提供了大量适用于 Vue 2 和 Vue 3 的基本 Composition API 实用程序函数。

它有几十个解决方案,适用于常见的开发者用例,如跟踪Ref变化、检测元素可见性、简化常见的Vue模式、键盘/鼠标输入等。这是一个真正节省开发时间的好方法,因为你不必自己添加所有这些标准功能。

我喜欢VueUse库,因为它在决定提供哪些实用工具时真正把开发者放在第一位,而且它是一个维护良好的库,因为它与Vue的当前版本保持同步。

VueUse 有哪些实用程序?

如果你想看到每一个实用程序的完整列表,我绝对建议你去看看官方文档。但总结一下,VueUse中有9种类型的函数。

  1. Animation——包含易于使用的过渡、超时和计时功能。
  2. Browser——可用于不同的屏幕控制、剪贴板、偏好等。
  3. Component——提供了不同组件方法的简写。
  4. Formatters——提供响应时间格式化功能。
  5. Sensors——用来监听不同的DOM事件、输入事件和网络事件。
  6. State——管理用户状态(全局、本地存储、会话存储)。
  7. Utility——不同的实用函数,如 getter、条件、引用同步等。
  8. Watch——更多高级类型的观察器,如可暂停的观察器、退避的观察器和条件观察器。
  9. Misc——不同类型的事件、WebSockets和web workers 的功能

这些类别中的大多数都包含几个不同的功能,所以VueUse对于你的使用情况来说是很灵活的,可以作为一个很好的地方来快速开始构建Vue应用程序。

在本教程中,我们将看一下5个不同的VueUse函数,这样你就可以了解在这个库中工作是多么容易。

但首先,让我们将其添加到Vue项目中!

将 VueUse 安装到你的 Vue 项目中

VueUse的最大特点之一是,它只用一个软件包就能同时兼容Vue 2和Vue 3!

安装VueUse有两种选择npm或CDN

npm i @vueuse/core # yarn add @vueuse/core
<script src="https://unpkg.com/@vueuse/shared"></script>
<script src="https://unpkg.com/@vueuse/core"></script>

我建议使用NPM,因为它使用法更容易理解,但如果我们使用CDN,VueUse将在应用程序中通过 window.VueUse 访问。

对于NPM的安装,所有的功能都可以通过使用标准的对象重构从 @vueuse/core 中导入,像这样访问。

import { useRefHistory } from '@vueuse/core'

好了,现在我们已经安装了VueUse,让我们在应用程序中使用它!

useRefHistory 跟踪响应式数据的更改

useRefHistory 跟踪对Ref所做的每一个改变,并将其存储在一个数组中。这使我们能够轻松地为我们的应用程序提供撤销和重做功能。

让我们看一个示例,其中我们正在构建一个我们希望能够撤消的文本区域。

第一步是在不使用 VueUse 的情况下创建我们的基本组件——使用 ref、textarea 和用于撤消和重做的按钮。

<template>
  <p> 
    <button> Undo </button>
    <button> Redo </button>
  </p>
  <textarea v-model="text"/>
</template>

<script setup>
import { ref } from 'vue'
const text = ref('')
</script>

<style scoped>
  button {
    border: none;
    outline: none;
    margin-right: 10px;
    background-color: #2ecc71;
    color: white;
    padding: 5px 10px;;
  }
</style>

然后,让我们通过导入 useRefHistory 函数,然后从我们的文本 ref 中提取history、undo 和 redo 属性来添加 VueUse。这就像调用 useRefHistory 并传递我们的 ref 一样简单。

import { ref } from 'vue'
import { useRefHistory } from '@vueuse/core'

const text = ref('')
const { history, undo, redo } = useRefHistory(text)

每次我们的 ref 更改时,这都会触发一个观察者——更新我们刚刚创建的 history 属性。

然后,为了让我们能真正看到发生了什么,让我们打印出模板内的历史记录,同时在点击相应的按钮时调用我们的 undoredo 函数。

<template>
  <p> 
    <button @click="undo"> Undo </button>
    <button @click="redo"> Redo </button>
  </p>
  <textarea v-model="text"/>
  <ul>
    <li v-for="entry in history" :key="entry.timestamp">
      {{ entry }}
    </li>
  </ul>
</template>

<script setup>
import { ref } from 'vue'
import { useRefHistory } from '@vueuse/core'
const text = ref('')
const { history, undo, redo } = useRefHistory(text)
</script>

<style scoped>
  button {
    border: none;
    outline: none;
    margin-right: 10px;
    background-color: #2ecc71;
    color: white;
    padding: 5px 10px;;
  }
</style>

好的,让我们运行它。当我们输入时,每个字符都会触发历史数组中的一个新条目,如果我们点击undo/redo,我们会转到相应的条目。

5 个可以加速开发的 VueUse 函数库

还有不同的选项可以为此功能添加更多功能。例如,我们可以深入跟踪反应对象并限制这样的历史条目的数量。

const { history, undo, redo } = useRefHistory(text, {
  deep: true,
  capacity: 10,
})

有关完整的选项清单,请务必查看文档。

onClickOutside 关闭模态

onClickOutside 检测在一个元素之外的任何点击。根据我的经验,这个功能最常见的使用情况是关闭任何模式或弹出窗口。

通常情况下,我们希望我们的模态挡住网页的其他部分,以吸引用户的注意力并限制错误。然而,如果他们真的点击了模态之外的内容,我们希望它能够关闭。

只需两个步骤即可完成此操作:

  1. 为我们要检测的元素创建一个模板引用
  2. 使用此模板引用运行 onClickOutside

这是一个使用 onClickOutside 的带有弹出窗口的简单组件。

<template>
  <button @click="open = true"> Open Popup </button>
  <div class="popup" v-if='open'>
    <div class="popup-content" ref="popup">
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Corporis aliquid autem reiciendis eius accusamus sequi, ipsam corrupti vel laboriosam necessitatibus sit natus vero sint ullam! Omnis commodi eos accusantium illum?
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { onClickOutside } from '@vueuse/core'
const open = ref(false) // state of our popup
const popup = ref() // template ref
// whenever our popup exists, and we click anything BUT it
onClickOutside(popup, () => {
  open.value  = false
})
</script>

<style scoped>
  button {
    border: none;
    outline: none;
    margin-right: 10px;
    background-color: #2ecc71;
    color: white;
    padding: 5px 10px;;
  }
  .popup {
    position: fixed;
    top: ;
    left: ;
    width: 100vw;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(, , , 0.1);
  }
  .popup-content {
    min-width: 300px;
    padding: 20px;
    width: 30%;
    background: #fff;
  }
</style>

结果是这样的,我们可以用我们的按钮打开弹出窗口,然后在弹出内容窗口外点击关闭它。

5 个可以加速开发的 VueUse 函数库

useVModel 简化了 v-model 绑定

Vue 开发人员的一个常见用例是为组件创建自定义 v-model 绑定。这意味着我们的组件接受一个值作为 prop,并且每当该值被修改时,我们的组件都会向父级发出更新事件。

5 个可以加速开发的 VueUse 函数库

useVModel函数将其简化为只使用标准的 ref 语法。假设我们有一个自定义的文本输入,试图为其文本输入的值创建一个 v-model。 通常情况下,我们必须接受一个值的prop,然后emit一个变化事件来更新父组件中的数据值。

我们可以使用useVModel,把它当作一个普通的ref,而不是使用ref并调用 props.valueupdate:value。这有助于减少我们需要记住的不同语法的数量!

<template>
  <div>
    <input 
           type="text" 
           :value="data"
           @input="update"
           />
  </div>
</template>

<script>
import { useVModel } from '@vueuse/core'
export default {
  props: ['data'],
  setup(props, { emit }) {
    const data = useVModel(props, 'data', emit)
    console.log(data.value) // equal to props.data
    data.value = 'name' // equal to emit('update:data', 'name')
    const update = (event) => {
        data.value = event.target.value
    }
    return {
        data,
        update
    }
  },
}
</script>

每当我们需要访问我们的值时,我们只需调用 .value,useVModel将从我们的组件props中给我们提供值。而每当我们改变对象的值时,useVModel会向父组件发出一个更新事件

下面是一个快速的例子,说明该父级组件可能是什么样子...

<template>
  <div>
    <p> {{ data }} </p>
    <custom-input 
      :data="data" 
      @update:data="data = $event"
    />
  </div>
</template>

<script>
import CustomInput from './components/CustomInput.vue'
import { ref } from 'vue'
export default {
  components: {
    CustomInput,
  },
  setup () {
    const data = ref('hello')
    return {
      data
    }
  }
}

结果看起来像这样,我们在父级中的值始终与子级中的输入保持同步。

5 个可以加速开发的 VueUse 函数库

使用IntersectionObserver 跟踪元素可见性

在确定两个元素是否重叠时,Intersection Observers 非常强大。一个很好的用例是检查元素当前是否在视口中可见。

本质上,它检查目标元素与根元素/文档相交的百分比。如果该百分比超过某个阈值,它会调用一个回调来确定目标元素是否可见。

useIntersectionObserver 提供了一个简单的语法来使用IntersectionObserver API。我们所需要做的就是为我们想要检查的元素提供一个模板ref。默认情况下,IntersectionObserver将以文档的视口为根基,阈值为0.1——所以当这个阈值在任何一个方向被越过时,我们的交集观察器将被触发。

这个例子的代码可能是这样的:我们有一个假的段落,只是在我们的视口中占据了空间,我们的目标元素,然后是一个打印语句,打印我们元素的可见性。

<template>
  <p> Is target visible? {{ targetIsVisible }} </p>
  <div class="container">
    <div class="target" ref="target">
      <h1>Hello world</h1>
    </div>
  </div>
</template>

<script>
import { ref } from 'vue'
import { useIntersectionObserver } from '@vueuse/core'
export default {
  setup() {
    const target = ref(null)
    const targetIsVisible = ref(false)
    const { stop } = useIntersectionObserver(
      target,
      ([{ isIntersecting }], observerElement) => {
        targetIsVisible.value = isIntersecting
      },
    )
    return {
      target,
      targetIsVisible,
    }
  },
}
</script>

<style scoped>
.container {
  width: 80%;
  margin:  auto;
  background-color: #fafafa;
  max-height: 300px;
  overflow: scroll;
}
.target {
  margin-top: 500px;
  background-color: #1abc9c;
  color: white;
  padding: 20px;
}
</style>

当我们运行并滚动它时,我们会看到它正确地更新了。

5 个可以加速开发的 VueUse 函数库

我们还可以为 Intersection Observer 指定更多选项,例如更改其根元素、边距(用于计算交点的根边界框的偏移量)和阈值级别。

const { stop } = useIntersectionObserver(
  target,
  ([{ isIntersecting }], observerElement) => {
    targetIsVisible.value = isIntersecting
  },
  {
    // root, rootMargin, threshold, window
    // full options in the source: https://github.com/vueuse/vueuse/blob/main/packages/core/useIntersectionObserver/index.ts
    threshold: 0.5,
  }
)

同样重要的是,这个方法返回一个 stop 函数,我们可以调用这个函数来停止观察交叉点。如果我们只想追踪一个元素在屏幕上第一次可见的时候,这就特别有用。

在这段代码中,一旦 targetIsVisible 被设置为 true,观察者就会停止,即使我们滚动离开目标元素,我们的值也会保持为true

const { stop } = useIntersectionObserver(
  target,
  ([{ isIntersecting }], observerElement) => {
    targetIsVisible.value = isIntersecting
    if (isIntersecting) {
      stop()
    }
  },
)

useTransition 在值之间过渡

useTransition 是整个veuse库中我最喜欢的函数之一。它允许我们在一行内平滑地转换数值。

我们有一个存储为ref的数字源和一个将在不同数值之间缓和的输出。例如,假设我们想建立一个计数器

5 个可以加速开发的 VueUse 函数库

我们可以通过三个步骤来做到这一点:

  • 创建我们的 count ref并将其初始化为零
  • 使用 useTransition 创建 output ref(设置持续时间和转换类型)
  • 更改 count 的值
<script setup>
import { ref } from 'vue'
import { useTransition, TransitionPresets } from '@vueuse/core'

const source = ref(0)

const output = useTransition(source, {
  duration: 3000,
  transition: TransitionPresets.easeOutExpo,
})

source.value = 5000

</script>

然后,在我们的模板中,我们希望显示 output 的值,因为它可以在不同值之间平滑过渡。

<template>
  <h2> 
    <p> Join over </p>
    <p> {{ Math.round(output) }}+ </p>
    <p>Developers </p>
  </h2>
</template>

<script setup>
import { ref } from 'vue'
import { useTransition, TransitionPresets } from '@vueuse/core'
const source = ref()
const output = useTransition(source, {
  duration: 3000,
  transition: TransitionPresets.easeOutExpo,
})
source.value = 5000
</script>

这就是结果!

5 个可以加速开发的 VueUse 函数库

我们还可以使用 useTransition 来过渡整个数字数组,这在处理位置或颜色时很有用。 处理颜色的一个绝招是使用一个计算属性将RGB值格式化为正确的颜色语法。

<template>
  <h2 :style="{ color: color } "> COLOR CHANGING </h2>
</template>

<script setup>
import { ref, computed } from 'vue'
import { useTransition, TransitionPresets } from '@vueuse/core'
const source = ref([, , ])
const output = useTransition(source, {
  duration: 3000,
  transition: TransitionPresets.easeOutExpo,
})
const color = computed(() => {
  const [r, g, b] = output.value
  return `rgb(${r}, ${g}, ${b})`
})
source.value = [255, , 255]
</script>

5 个可以加速开发的 VueUse 函数库

一些进一步定制的酷方法是使用任何内置的过渡预设或使用CSS缓动函数来定义我们自己的过渡。

最后的想法

这绝不是 VueUse 的完整指南,这些只是我发现 VueUse 库中最有趣的许多函数。

我喜欢所有这些实用功能对加快开发速度的帮助,因为它们中的每一个都是为了解决具体而又常见的用例。

我很想听听你是如何在自己的项目中实施VueUse的。请在下面留下任何评论。

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Peter20 Peter20
4年前
mysql中like用法
like的通配符有两种%(百分号):代表零个、一个或者多个字符。\(下划线):代表一个数字或者字符。1\.name以"李"开头wherenamelike'李%'2\.name中包含"云",“云”可以在任何位置wherenamelike'%云%'3\.第二个和第三个字符是0的值wheresalarylike'\00%'4\
Stella981 Stella981
3年前
Python+Selenium自动化篇
本篇文字主要学习selenium定位页面元素的集中方法,以百度首页为例子。0.元素定位方法主要有:id定位:find\_element\_by\_id('')name定位:find\_element\_by\_name('')class定位:find\_element\_by\_class\_name(''
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这