VueUse官网翻译解读
指南
立即开始
VueUse是基于Compomit API的实用程序函数的集合。在继续之前,我们假设您已经熟悉组合API的基本思想。
安装
🎩 VueUse 通过vue-demi的强大功能在单个包中适用于 Vue 2 和 3!
npm i @vueuse/core
Vue 3 演示: Vite, Webpack / Vue 2 演示: Vue CLI
从 v6.0 开始,VueUse 需要 >= v3.2 或 >= v1.1
vue``@vue/composition-api
CDN
<script src="https://unpkg.com/@vueuse/shared"></script>
<script src="https://unpkg.com/@vueuse/core"></script>
它将暴露在全局作用域window.VueUse
Nuxt
从 v6.7.0 开始,我们发布了一个 Nuxt 模块,用于自动导入 Nuxt 3 和 Nuxt Bridge。
// nuxt.config.js
export default {
buildModules: [
'@vueuse/core/nuxt'
]
}
然后在Nuxt应用程序中的任何位置使用VueUse功能。例如:
<script setup lang="ts">
const { x, y } = useMouse()
</script>
<template>
<div>pos: {{x}}, {{y}}</div>
</template>
用法示例
只需从中导入所需的功能@vueuse/core
import { useMouse, usePreferredDark, useLocalStorage } from '@vueuse/core'
export default {
setup() {
// 跟踪鼠标位置
const { x, y } = useMouse()
// 用户喜欢黑色主题吗
const isDark = usePreferredDark()
// 在localStorage中持久化状态
const store = useLocalStorage(
'my-storage',
{
name: 'Apple',
color: 'red',
},
)
return { x, y, isDark, store }
}
}
有关更多详细信息,请参阅函数列表。
最佳实践
解构
VueUse 中的大多数函数都返回一个refs 对象,您可以使用ES6 的对象析构语法来获取所需的内容。例如:
import { useMouse } from '@vueuse/core'
// “x”和“y”是引用
const { x, y } = useMouse()
console.log(x.value)
const mouse = useMouse()
console.log(mouse.x.value)
如果您希望将它们用作对象属性样式,则可以使用 打开 ref 的包装。例如:reactive()
import { reactive } from 'vue'
import { useMouse } from '@vueuse/core'
const mouse = reactive(useMouse())
// "x"和"y"将自动展开, 不需要 `.value`
console.log(mouse.x)
配置
这些显示了 VueUse 中大多数函数的常规配置。
事件过滤器
从 v4.0 开始,我们提供了事件过滤器系统,以便灵活地控制何时触发事件。例如,您可以使用 并控制事件触发速率:throttleFilter``debounceFilter
import { throttleFilter, debounceFilter, useLocalStorage, useMouse } from '@vueuse/core'
// 更改将写入localStorage,并设置1s
const storage = useLocalStorage('my-key', { foo: 'bar' }, { eventFilter: throttleFilter(1000) })
// 鼠标位置将在鼠标空闲100ms后更新
const { x, y } = useMouse({ eventFilter: debounceFilter(100) })
此外,您可以利用暂时暂停某些事件。pausableFilter
import { pausableFilter, useDeviceMotion } from '@vueuse/core'
const motionControl = pausableFilter()
const motion = useDeviceMotion({ eventFilter: motionControl.eventFilter })
motionControl.pause()
// 运动更新停顿了一下
motionControl.resume()
// 运动更新恢复
无功时序
VueUse 的功能遵循 Vue 的反应性系统默认值,尽可能进行冲洗计时。
对于类似 -like 的可组合对象(例如,每当使用时暂停监视存储使用 RefHistory,默认值为 。这意味着它们将缓冲无效的效果并异步刷新它们。这可以避免在同一"tick"中发生多个状态突变时不必要的重复调用。watch``{ flush: 'pre' }
与 使用 的方式相同,VueUse 允许您通过传递以下选项来配置计时:watch``flush
const { pause, resume } = pausableWatch(
() => {
// 安全访问更新后的DOM
},
{ flush: 'post' }
)
刷新选项(默认:"pre")
'pre':在同一个"勾号"中缓冲无效效果,并在渲染之前刷新它们'post':像"pre"一样的异步,但在组件更新后触发,以便您可以访问更新的DOM'sync':强制效果始终同步触发
**注意:**对于类似可组合物(例如syncRef controlledComputed,当刷新计时可配置时,默认值更改为将它们与 Vue 中计算的引用的工作方式保持一致。computed``{ flush: 'sync' }
可配置的全局依赖关系
在 v4.0 中,访问浏览器 API 的函数将提供一个选项字段,供您指定全局依赖项(例如 、和 )。默认情况下,它将使用全局实例,因此在大多数情况下,您无需担心它。在使用 iframe 和测试环境时,此配置非常有用。window``document``navigator
// 访问父上下文中
const parentMousePos = useMouse({ window: window.parent })
const iframe = document.querySelect('#my-iframe')
// 接触子上下文
const childMousePos = useMouse({ window: iframe.contextWindow })
// 测试
const mockWindow = /* ... */
const { x, y } = useMouse({ window: mockWindow })
组件
在 v5.0 中,我们引入了一个新包,提供可组合函数的无渲染组件样式用法。@vueuse/components
例如onClickOutside而不是
<script setup>
import { ref } from 'vue'
import { onClickOutside } from '@vueuse/core'
const el = ref()
function close () {
/* ... */
}
onClickOutside(el, close)
</script>
<template>
<div ref="el">
Click Outside of Me
</div>
</template>
现在,您可以以组件方式使用它:
<script setup>
import { OnClickOutside } from '@vueuse/components'
function close () {
/* ... */
}
</script>
<template>
<OnClickOutside @trigger="close">
<div>
Click Outside of Me
</div>
</OnClickOutside>
</template>
同样,您也可以使用 以下命令访问返回值:v-slot
<UseMouse v-slot="{ x, y }">
x: {{ x }}
y: {{ y }}
</UseMouse>
<UseDark v-slot="{ isDark, toggleDark }">
<button @click="toggleDark()">
Is Dark: {{ isDark }}
</button>
</UseDark>
安装
$ npm i @vueuse/core @vueuse/components
有关组件样式的详细用法,请参阅每个函数的文档。
贡献
感谢您有兴趣为这个项目做出贡献!
发展#
设置
将此存储库克隆到本地计算机并安装依赖项。
pnpm install
我们使用 Vitepress 进行快速开发和记录。您可以通过以下方式在本地启动它
pnpm dev
贡献#
现有功能#
随意增强现有功能。请尽量不要引入重大更改。
新功能#
有关添加新函数的一些注意事项
- 在开始工作之前,最好先打开一个问题进行讨论。
- 实现应作为文件夹放置在下,并在
packages/core``index.ts - 在软件包中,尽量不要引入第三方依赖项,因为此软件包旨在尽可能轻量级。
core - 如果您想引入第三方依赖项,请为@vueuse/集成做出贡献或创建新的附加组件。
- 您可以在 函数文件夹 部分所述的 函数模板 下找到函数模板。
packages/core/_template/ - 在为函数编写文档时,and 将在生成时自动更新,因此不要觉得需要更新它们。
<!--FOOTER_STARTS-->``<!--FOOTER_ENDS-->
请注意,您不需要更新 或 软件包的 。它们是自动生成的。
indexes.json``index.ts
新的附加组件#
非常欢迎新的附加组件!
- 在 下创建一个新文件夹,将其命名为您的加载项名称。
packages/ - 在 中添加附加组件详细信息
scripts/packages.ts - 在该文件夹下创建。
README.md - 像向核心包中添加功能一样添加函数。
- 作为 PR 提交和提交。
项目结构#
莫诺雷波#
我们将 monorepo 用于多个软件包
packages
shared/ - shared utils across packages
core/ - the core package
firebase/ - the Firebase add-on
[...addons]/ - add-ons named
函数文件夹#
函数文件夹典型值包含以下 4 个文件:
您可以在下找到模板
packages/core/_template/
index.ts # function source code itself
demo.vue # documentation demo
index.test.ts # jest unit testing
index.md # documentation
因为您应该导出带有名称的函数。index.ts
// DO
export { useMyFunction }
// DON'T
export default useMyFunction
因为第一句话将显示为函数列表中的简短介绍,因此请尽量保持简短明了。index.md
# useMyFunction
This will be the intro. The detail descriptions...
阅读有关指南的更多信息。
代码样式#
只要安装开发依赖项,就不必担心代码样式。Git 钩子将在提交时为您格式化和修复它们。
谢谢
再次感谢您对这个项目感兴趣!你真棒!
指引
以下是 VueUse 函数的指南。您还可以将它们作为创作自己的可组合函数或应用程序的参考。
你还可以找到这些设计决策的一些原因,以及一些编写可组合函数的技巧,以及Anthony Fu关于VueUse的演讲:
常规
- 从以下位置导入所有 Vue API
"vue-demi" - 尽可能使用
ref代替reactive - 尽可能使用选项对象作为参数,以便为将来的扩展提供更灵活的操作。
- 当包装大量数据时,使用
shallowRef代替ref。 - 在使用全局变量时使用
configurableWindow(等等),比如window可以灵活地处理多个窗口、测试模拟和SSR。 - 当涉及尚未由浏览器广泛实现的 Web API 时,还会输出标志
isSupported - 在内部使用
watch或watchEffect时,也要尽可能配置immediate和flush选项 - 使用
tryOnUnmounted来优雅地清除副作用 - 避免使用控制台日志
另请阅读:最佳实践
浅引用
当包装大量数据时,使用shallowRef代替ref。
export function useFetch<T>(url: MaybeRef<string>) {
// 使用' shallowRef '来防止深层反应
const data = shallowRef<T | undefined>()
const error = shallowRef<Error | undefined>()
fetch(unref(url))
.then(r => r.json())
.then(r => data.value = r)
.catch(e => error.value = e)
/* ... */
}
可配置的全局变量
当使用全局变量如window或document时,在选项界面中支持configurableWindow或configurableDocument,以使该函数在多窗口、测试模拟和SSR等场景时更加灵活。
了解有关实施的更多信息:_configurable.ts
import { ConfigurableWindow, defaultWindow } from '../_configurable'
export function useActiveElement<T extends HTMLElement>(
options: ConfigurableWindow = {}
) {
const {
// defaultWindow = isClient ? window : undefined
window = defaultWindow
} = options
let el: T
// 在Node.js环境(SSR)中跳过
if (window) {
window.addEventListener('blur', () => {
el = window?.document.activeElement
}, true)
}
/* ... */
}
使用示例:
// 在iframe和绑定到父窗口
useActiveElement({ window: window.parent })
Watch选项
在内部使用watch或watchEffect时,也要尽可能配置立即和刷新选项。例如debouncedWatch
import { WatchOptions } from 'vue-demi'
// 扩展watch选项
export interface DebouncedWatchOptions extends WatchOptions {
debounce?: number
}
export function debouncedWatch(
source: any,
cb: any,
options: DebouncedWatchOptions = {},
): WatchStopHandle {
return watch(
source,
() => /* ... */,
options, // 通过watch选择
)
}
控制
我们使用controls选项,允许用户使用具有单个返回功能的简单用法,同时能够在需要时拥有更多的控制和灵活性。阅读更多: #362.
何时提供controls选项#
- 该功能更常用于单个或
ref - 示例:
useTimestampuseInterval
// 常见的使用
const timestamp = useTimestamp()
// 更多的灵活性控制
const { timestamp, pause, resume } = useTimestamp({ controls: true })
请参阅useTimestamp的源代码,以实现适当的 TypeScript 支持。
何时不提供controls选项#
- 该函数更常用于多次返回
- 示例
:useRafFnuseRefHistory
const { pause, resume } = useRafFn(() => {})
isSupported标志#
当涉及到尚未被浏览器广泛实现的Web api时,也输出isSupported标志。
例如 useShare
export function useShare(
shareOptions: MaybeRef<ShareOptions> = {},
options: ConfigurableNavigator = {}
) {
const { navigator = defaultNavigator } = options
const isSupported = navigator && 'canShare' in navigator
const share = async(overrideOptions) => {
if (isSupported) {
/* ...implementation */
}
}
return {
isSupported,
share,
}
}
Renderless组件#
- 使用渲染函数而不是 Vue SFC
- 将道具包裹reactive`中,以便轻松地将它们作为道具传递到插槽中
- 更喜欢将函数选项用作属性类型,而不是自己重新创建它们
- 仅当函数需要目标绑定到时,才将槽包装在 HTML 元素中
import { defineComponent, reactive } from 'vue-demi'
import { useMouse, MouseOptions } from '@vueuse/core'
export const UseMouse = defineComponent<MouseOptions>({
name: 'UseMouse',
props: ['touch', 'resetOnTouchEnds', 'initialValue'] as unknown as undefined,
setup(props, { slots }) {
const data = reactive(useMouse(props))
return () => {
if (slots.default)
return slots.default(data)
}
},
})
有时一个函数可能有多个参数,在这种情况下,您可能需要创建一个新接口,以将所有接口合并到组件属性的单个接口中。
import { useTimeAgo, TimeAgoOptions } from '@vueuse/core'
interface UseTimeAgoComponentOptions extends Omit<TimeAgoOptions<true>, 'controls'> {
time: MaybeRef<Date | number | string>
}
export const UseTimeAgo = defineComponent<UseTimeAgoComponentOptions>({...})