vue2/vue3 Composition Api 常用工具集, @vueuse/core 之核心函数 elements 实践
VueUse是一款基于组合式API的函数集合。
VueUse不是Vue.use,它是为Vue 2和3服务的一套Vue Composition API的常用工具集,是目前世界上Star最高的同类型库之一。它的初衷就是将一切原本并不支持响应式的JS API变得支持响应式,省去程序员自己写相关代码。
useActiveElement
响应式 document.activeElement
<script lang="ts" setup>
import { useActiveElement } from '@vueuse/core'
import { watch, ref } from 'vue'
const activeElement = useActiveElement()
const element: any = ref(null)
watch(activeElement, (el) => {
element.value = el
})
</script>
<template>
<div class="use-active-element">
<input id="1" value="1" />
<input id="2" value="2" /><br />
Active element is {{ element?.id }}
</div>
</template>
useDocumentVisibility
响应式跟踪 document.visibilityState
最大最小化页面或者切换浏览器页页签触发状态
<script lang="ts" setup>
import { useDocumentVisibility } from '@vueuse/core'
import { watch, ref, onUnmounted } from 'vue'
const visibility = useDocumentVisibility()
const hello = ref('最小化页面或切换标签然后返回!')
const unwatch = watch(visibility, (current, previous) => {
if (current === 'visible' && previous === 'hidden') {
hello.value = '欢迎回家!'
}
})
onUnmounted(() => {
unwatch()
})
</script>
<template>
<div class="use-document-visibility">
{{ hello }}
</div>
</template>
useDraggable
使元素可拖拽。
<script lang="ts" setup>
import { ref } from 'vue'
import { useDraggable } from '@vueuse/core'
const el = ref<HTMLElement | null>(null)
const { x, y, style } = useDraggable(el, {
initialValue: { x: 40, y: 40 },
})
</script>
<template>
<div class="use-draggable" ref="el" :style="style" style="position: fixed;">
<div class="title">标题</div>
我的位置:{{ x }}, {{ y }}
</div>
</template>
<style scoped lang="less">
.use-draggable {
border: 1px solid #e5e5e5;
border-radius: 4px;
background: #fff;
color: #333;
padding: 10px 20px;
.title {
line-height: 32px;
font-size: 14px;
font-weight: bold;
}
}
</style>
useDropZone
创建一个可以放置文件的区域。
<script lang="ts" setup>
import { useDropZone } from '@vueuse/core'
import { ref } from 'vue'
import stateVue from '../../../views/state.vue'
const dropZoneRef = ref<HTMLDivElement>()
const state = ref({})
function onDrop(files: File[] | null) {
state.value = files[0]
}
const { isOverDropZone } = useDropZone(dropZoneRef, onDrop)
</script>
<template>
<div class="drop-zone-container" ref="dropZoneRef">
拖拽文件放在这里
<br />
name: {{ state.name }}<br />
size: {{ state.size }}<br />
type: {{ state.type }}<br />
</div>
</template>
<style lang="less" scoped>
.drop-zone-container {
background: #e5e5e5;
border: 1px solid #ccc;
padding: 10px;
border-radius: 4px;
width: 200px;
height: 200px;
color: #333;
}
</style>
useElementBounding
让HTML元素的bounding box 响应式
<script lang="ts" setup>
import { ref } from 'vue'
import { useElementBounding } from '@vueuse/core'
const el = ref(null)
const options = {
reset: true, // 组件卸载时重置边界信息
windowResize: true, // 监听窗口大小调整事件
windowScroll: true, // 监听窗口滚动事件
immediate: true, // 组件挂载时立即调用
}
const {
x,
y,
top,
right,
bottom,
left,
width,
height,
} = useElementBounding(el, options)
</script>
<template>
<div ref="el" class="use-element-bounding">
位置信息:<br />
x: {{ x }}<br />
y: {{ y }}<br />
top: {{ top }}<br />
right: {{ right }} <br />
bottom: {{ bottom }}<br />
width: {{ width }}<br/>
height: {{ height }}<br/>
</div>
</template>
<style lang="less" scoped>
.use-element-bounding {
background: #e5e5e5;
border: 1px solid #ccc;
padding: 10px;
border-radius: 4px;
width: 200px;
height: 200px;
color: #333;
}
</style>
useElementSize
元素尺寸大小响应式. ResizeObserver MDN
大小默认不包含 padding、border
<script lang="ts" setup>
import { ref } from 'vue'
import { useElementSize } from '@vueuse/core'
const el = ref(null)
const {
width,
height,
} = useElementSize(el)
</script>
<template>
<div ref="el" class="use-element-size">
width: {{ width }}<br/>
height: {{ height }}<br/>
</div>
</template>
<style lang="less" scoped>
.use-element-size {
background: #e5e5e5;
border: 1px solid #ccc;
padding: 10px;
border-radius: 4px;
width: 200px;
height: 200px;
color: #333;
}
</style>
useElementVisibility
跟踪元素在视口中的可见性。
<script lang="ts" setup>
import { ref } from 'vue'
import { useElementVisibility } from '@vueuse/core'
const target = ref(null)
const targetIsVisible = useElementVisibility(target)
</script>
<template>
<div class="use-element-visiblity">
<div ref="target">向下滚动到可视区域</div>
<div class="tips-zone">
提示内容{{ targetIsVisible }}
</div>
</div>
</template>
<style lang="less">
.tips-zone {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9;
border: 2px dashed #ccc;
padding: 20px;
}
</style>
useIntersectionObserver
响应式监听目标元素的可见性。
<script lang="ts" setup>
import { ref } from 'vue'
import { useIntersectionObserver } from '@vueuse/core'
const target = ref(null)
const targetIsVisible = ref(false)
const { stop } = useIntersectionObserver(
target,
([{ isIntersecting }], observerElement) => {
targetIsVisible.value = isIntersecting
}
)
</script>
<template>
<div class="use-intersection-observer">
<div class="box">
<div class="p1">向下滚动</div>
<div class="p2" ref="target">
监听可视区域内容
</div>
<div class="p3">最底部</div>
</div>
<div class="tip">元素在窗口内 {{ targetIsVisible }}</div>
</div>
</template>
<style lang="less">
.use-intersection-observer {
.box {
border: 2px dashed #ccc;
height: 100px;
overflow-y: auto;
padding: 20px;
.p1, .p3 {
padding: 30px;
}
.p2 {
margin-top: 100px;
}
}
}
</style>
useMouseInElement
响应式获取鼠标相对于元素的位置
<script lang="ts" setup>
import { ref } from 'vue'
import { useMouseInElement } from '@vueuse/core'
const target = ref(null)
const {
x,
y,
sourceType,
elementX,
elementY,
elementPositionX,
elementPositionY,
elementHeight,
elementWidth,
isOutside
} = useMouseInElement(target)
</script>
<template>
<div ref="el" class="use-mouse-in-element">
<div ref="target" class="content">相对内容</div>
位置信息:<br />
x: {{ x }}<br />
y: {{ y }}<br />
sourceType: {{ sourceType }}<br />
elementX: {{ elementX }}<br />
elementY: {{ elementY }}<br />
elementPositionX: {{ elementPositionX }}<br />
elementPositionY: {{ elementPositionY }}<br />
elementHeight: {{ elementHeight }}<br />
elementWidth: {{ elementWidth }}<br />
isOutside: {{ isOutside }}<br />
</div>
</template>
<style lang="less" scoped>
.use-mouse-in-element {
background: #e5e5e5;
border: 1px solid #ccc;
padding: 10px;
border-radius: 4px;
width: 400px;
color: #333;
.content {
color: #fff;
background: #000;
padding: 40px;
}
}
</style>
useMutationObserver
监听DOM树修改 MutationObserver MDN
<script lang="ts" setup>
import { ref } from 'vue'
import { useMutationObserver } from '@vueuse/core'
const targetElement = ref(null)
const messages = ref([])
// 使用useMutationObserver自定义钩子
useMutationObserver(targetElement, (mutations) => {
console.log('DOM元素发生变化:', mutations)
if (mutations[0])
messages.value.push(mutations[0].attributeName)
}, {
attributes: true,
});
// 改变DOM元素的内容
const changeElement = () => {
targetElement.value.style.color = '#000'
}
</script>
<template>
<div>
<h2>DOM元素监视器</h2>
<div ref="targetElement" style="background-color: #ccc;">
监视的元素
</div>
<button @click="changeElement">改变元素</button>
{{ messages }}
</div>
</template>
useResizeObserver
监听元素内容和边框尺寸的变化。
<script lang="ts" setup>
import { ref } from 'vue'
import { useResizeObserver } from '@vueuse/core'
const el = ref(null)
const text = ref('')
useResizeObserver(el, (entries) => {
const entry = entries[0]
const { width, height } = entry.contentRect
text.value = `width: ${width}, height: ${height}`
})
</script>
<template>
<div class="use-resize-observer" ref="el">
{{ text }}
</div>
</template>
useWindowFocus
使用 window.onfocus
和 window.onblur
事件响应式跟踪窗口焦点。
离开窗口,切到其它页签触发
<script lang="ts" setup>
import { useWindowFocus } from '@vueuse/core'
const focused = useWindowFocus()
</script>
<template>
<div class="use-window-focus">
窗口是否聚焦 {{ focused }}
</div>
</template>
useWindowScroll
响应式获取窗口的滚动位置。
<script lang="ts" setup>
import { useWindowScroll } from '@vueuse/core'
const { x, y } = useWindowScroll()
</script>
<template>
<div class="use-window-scroll">
x: {{ x }}, y: {{ y }}
</div>
</template>
useWindowSize
响应式获取窗口尺寸
<script lang="ts" setup>
import { useWindowSize } from '@vueuse/core'
const { width, height } = useWindowSize()
</script>
<template>
<div class="use-window-size">
width: {{ width }}, height: {{ height }}
</div>
</template>