【VueUse】超越基本功能的高级 Vue 元素操作

发布于:2024-05-04 ⋅ 阅读:(38) ⋅ 点赞:(0)

在vue开发中我们经常需要操作DOM元素,从简单的添加类到动态创建元素,这些操作都是不可避免的。而在VueUse库中,Elements相关API函数为我们提供了一系列强大而灵活的工具,帮助我们更轻松地处理DOM元素。无论是优雅地处理元素、动态渲染元素还是简化复杂的DOM操作,VueUse Elements都能够成为您的得力助手。

        在本文将带您深入探索VueUse Elements,揭示其背后的神秘面纱,并展示如何利用这些强大的API函数提升您的Vue项目至新的高度。让我们一起踏上这场关于VueUse Elements的探索之旅吧!

目录

useActiveElement(跟踪焦点元素)

useDocumentVisibility(跟踪文档可见状态)

useDraggable(拖拽元素)

useDropZone(拖放区域)

useElementBounding(响应边界数据)

useElementSize(获取指定元素宽高)

useResizeObserver(监听元素内容和边框尺寸变化)

useElementVisibility(跟踪元素可见性)

useIntersectionObserver(指定元素交集变化)

useMouseInElement(跟踪鼠标指定元素状态)

useMutationObserver(监听DOM树修改)

useWindowFocus(跟踪窗口焦点)

useWindowScroll(获取窗口的滚动位置)

useWindowSize(获取窗口尺寸)

最后总结


useActiveElement(跟踪焦点元素)

响应式 document.activeElement。什么意思呢?就是跟踪文档中当前处于焦点的元素。具体来说,useActiveElement函数会返回一个Ref对象,该对象的值为当前处于焦点的元素。这意味着,当用户在页面上点击、输入或以其他方式与页面交互时,useActiveElement将提供当前活动元素的信息。如下:

<template>
  <input v-for="i in 6" :key="i" type="text" :data-id="i" :placeholder="`${i}`"><br>
  当前聚焦的元素:{{ key }}
</template>

<script setup lang="ts">
import { watch, computed } from 'vue'
import { useActiveElement } from '@vueuse/core'

const activeElement = useActiveElement()
const key = computed(() => activeElement.value?.dataset?.id || 'null')

watch(activeElement, (el) => {
  console.log(activeElement.value?.dataset)
})
</script>

最终得到的结果如下:

useDocumentVisibility(跟踪文档可见状态)

响应式跟踪 document.visibilityState。什么意思呢?就是跟踪文档的可见性状态,允许开发者监测页面是否处于可见状态,从而可以根据不同的可见性状态来执行相应的操作。例如,在开发通知系统或者数据同步功能时,可以利用useDocumentVisibility函数来检测用户是否正在浏览页面,从而决定是否发送通知或执行数据同步操作,以避免在用户不可见时造成不必要的打扰或消耗额外的资源。如下:

<template>
  <div class="use-document-visibility">
    {{ hello }}
  </div>
</template>

<script lang="ts" setup>
import { ref, watch } from 'vue'
import { useDocumentVisibility } from '@vueuse/core'

const visibility = useDocumentVisibility()

const hello = ref('最小化页面或切换标签然后返回!')
watch(visibility, (current, previous) => {
  if (current === 'visible' && previous === 'hidden') {
    hello.value = '欢迎回家!'
  }
})
</script>

最终得到的结果如下:

useDraggable(拖拽元素)

使元素可拖拽。什么意思呢?就是使元素能够响应拖拽操作,允许开发者将其应用于某个元素,从而使该元素具有拖拽功能。一旦应用了该函数,用户便可以通过鼠标或触摸屏对元素进行拖拽操作,移动元素到所需位置。如下:

<template>
  <div class="use-draggable" ref="el" :style="style" style="position: fixed;">
    <div class="title">标题</div>
    我的位置:{{ x }}, {{ y }}
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useDraggable } from '@vueuse/core'

const el = ref(null)
const { x, y, style } = useDraggable(el, {
  initialValue: { x: 40, y: 40 }, // 初始位置

})
</script>

<style scoped lang="scss">
.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(拖放区域)

创建一个可以放置文件的区域。什么意思呢?就是让一个元素成为“拖放区域”,从而可以接收用户拖放的文件或其他数据。这个区域可以接收用户从文件系统或其他来源拖放过来的内容。通过这个函数,你可以监听各种拖放相关的事件,比如当用户开始拖拽、拖拽进入区域、拖拽在区域内移动以及拖放操作完成等。场景应用于文件上传组件、拖放式接口、图片管理工具等。如下:

<template>
  <div ref="dropZoneRef" class="drop-zone" :class="{ 'over': isOverDropZone }">
    拖拽文件到这个地方 {{ isOverDropZone }}
  </div>
  <ul v-if="state.name">
    <li>{{ state.name }}</li>
    <li>{{ state.size }}</li>
    <li>{{ state.type }}</li>
  </ul>
  <img src="./assets/1.jpg" alt="" style="width: 100px; height: 100px;">
</template>

<script lang="ts" setup>
import { ref, reactive } from 'vue'
import { useDropZone } from '@vueuse/core'

const dropZoneRef = ref<HTMLDivElement>()
let state = reactive({}) as any

function onDrop(files: any) {
  state = files[0]
  console.log(state)
}
const { isOverDropZone } = useDropZone(dropZoneRef, onDrop)
</script>

<style>
  .drop-zone {
    width: 500px;
    border: 2px dashed #ccc;
    padding: 20px;
    text-align: center;
  }
  .drop-zone.over {
    background-color: #f0f0f0;
  }
</style>

最终得到的结果如下:

useElementBounding(响应边界数据)

让HTML元素的bounding box 响应式。什么意思呢?就是可以获取指定元素的位置、宽度、高度等边界信息。这对于实现响应式布局或者对元素进行定位、动画等操作非常有用。当元素的边界发生变化时(例如窗口大小变化导致元素位置或尺寸变化),相关的响应式数据也会自动更新,从而保持界面的同步性。这里我们搭配上文讲解到的拖拽元素的API一起使用,如下:

<template>
  <div ref="el" class="use-element-bounding" :style="style" style="position: fixed;">
    位置信息:<br />
    x: {{ x }}<br />
    y: {{ y }}<br />
    top: {{ top }}<br />
    left: {{ left }}<br />
    right: {{ right }} <br />
    bottom: {{ bottom }}<br />
    width: {{ width }}<br/>
    height: {{ height }}<br/>
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import { useElementBounding, useDraggable } from '@vueuse/core'

const el = ref(null)

const { x, y, style } = useDraggable(el, {
  initialValue: { x: 40, y: 40 }, // 初始位置
})

const { top, right, bottom, left, width, height } = useElementBounding(el, {
  reset: true, // 组件卸载时重置边界信息
  windowResize: true, // 监听窗口大小调整事件
  windowScroll: true, // 监听窗口滚动事件
  immediate: true, // 组件挂载时立即调用
})
</script>

<style scoped>
.use-element-bounding {
  background: #e5e5e5;
  border: 1px solid #ccc;
  padding: 10px;
  border-radius: 4px;
  width: 200px;
  height: 200px;
  color: #333;
  user-select: none;
}
</style>

最终得到的结果如下:

useElementSize(获取指定元素宽高)

元素尺寸大小响应式。什么意思呢?就是获取指定元素的宽度和高度,这对于布局和样式计算非常有用。基于元素的尺寸信息,你可以根据需要动态地调整布局和样式。例如,可以根据元素的宽度和高度选择合适的样式或者调整其他元素的位置和大小。如下:

<template>
    <div>
      width: {{ width }}<br>
      height: {{ height }}
    </div>
  <textarea ref="el" class="use-element-size">
  </textarea>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import { useElementSize } from '@vueuse/core'

const el = ref(null)
const { width, height } = useElementSize(el)
</script>

<style scoped>
.use-element-size {
  background: #e5e5e5;
  border: 1px solid #ccc;
  padding: 10px;
  border-radius: 4px;
  width: 200px;
  height: 200px;
  color: #333;
}
</style>

最终得到的结果如下:

useResizeObserver(监听元素内容和边框尺寸变化)

监听元素内容和边框尺寸的变化。什么意思呢?就是用于观察指定元素的大小变化,并在大小变化时执行相应的回调函数。如下:

<template>
  <div>{{ text }}</div>
  <textarea class="use-resize-observer" ref="el"></textarea>
</template>

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

<style>
.use-resize-observer {
  width: 200px;
  height: 200px;
  background: #ccc;
}
</style>

最终得到的结果如下: 

useResizeObserver 和 useElementSize 都是 VueUse 中用于监测元素大小变化的函数,但它们之间有一些区别

实现原理

1)useElementSize 则是通过监听 window 的 resize 事件以及元素的 scroll 事件,并结合获取元素的 clientWidth 和 clientHeight 属性来计算元素的大小变化。

2)useResizeObserver 使用的是 Resize Observer API,它能够在元素大小变化时立即触发回调函数。
浏览器支持

1)useElementSize 的实现方式则更依赖于浏览器的 resize 和 scroll 事件,可能存在一些兼容性问题。
2)Resize Observer API 的支持程度较高,大多数现代浏览器都支持。

精确度

由于 Resize Observer API 是专门用于监测元素大小变化的 API,因此在性能和精确度上可能会优于通过 resize 和 scroll 事件计算大小的方法。

使用场景

1)如果你的项目需要考虑到一些老版本浏览器的兼容性,并且对性能要求不是特别高,可以考虑使用 useElementSize。

2)如果你需要在元素大小变化时立即触发回调函数,并且希望在现代浏览器中使用,则可以选择 useResizeObserver。

综上所述

useResizeObserver 更适合现代化的项目,并且提供了更好的性能和精确度,而 useElementSize 则更适合需要考虑兼容性和性能要求不那么严格的项目。

useElementVisibility(跟踪元素可见性)

跟踪元素在视口中的可见性。什么意思呢?就是用于检测元素的可见性,可以帮助你监听指定元素的可见状态,即当元素进入或离开视窗时,相关的可见性状态会被更新。通过检测元素的可见性,你可以延迟加载页面中的图片、视频或其他资源,从而提高页面的加载性能和用户体验。当元素进入视窗时,再开始加载相应的内容。

举个经典的例子,当你电脑浏览b站视频的时候,你想刷一下评论区,当你鼠标滚动,原本的视频离开可视窗口的那一瞬间,右下角会给你打开一个小窗口,当你回到原本的视频窗口后,小窗口就会消失,就是这个道理!

案例代码如下:

<template>
  <div class="use-element-visiblity">
    <div ref="target" class="target">向下滚动到可视区域</div>
    <div class="tips-zone">
      提示内容{{ targetIsVisible }}
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import { useElementVisibility } from '@vueuse/core'

const target = ref(null)
const targetIsVisible = useElementVisibility(target)
</script>

<style scoped lang="scss">
.use-element-visiblity {
  height: 100%;
  height: 200vh;
  background-color: #eee;
  .target {
    width: 200px;
    height: 200px;
    background-color: red;
  }
  .tips-zone {
    position: fixed;
    bottom: 20px;
    right: 20px;
    z-index: 9;
    border: 2px dashed #ccc;
    padding: 20px;
  }
}
</style>

最终得到的结果如下:

useIntersectionObserver(指定元素交集变化)

响应式监听目标元素的可见性。什么意思呢?就是监听指定元素与其祖先元素或视窗的交集变化。当元素进入或离开视窗,或者与祖先元素的交集变化时,相关的回调函数会被触发。如下:

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

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

<style scoped lang="scss">
.use-intersection-observer {
  width: 500px;
  .box {
    border: 2px dashed #ccc;
    height: 100px;
    overflow-y: auto;
    padding: 20px;
    .p1, .p3 {
      padding: 30px;
    }
    .p2 {
      margin-top: 100px;
    }
  }
}
</style>

最终得到的结果如下:

useMouseInElement(跟踪鼠标指定元素状态)

响应式获取鼠标相对于元素的位置。什么意思呢?就是用于跟踪鼠标在指定元素内的位置和状态,实时获取鼠标相对于指定元素的位置信息,包括水平和垂直方向的坐标,通过实时追踪鼠标在元素内的位置和状态,可以为用户提供更加灵活、智能的交互体验,从而增强用户对网页或应用的满意度。如下:

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

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

<style scoped lang="scss">
.use-mouse-in-element {
  background: #e5e5e5;
  border: 1px solid #ccc;
  padding: 10px;
  border-radius: 4px;
  width: 400px;
  color: #333;
  .content {
    color: #fff;
    background: #ddd;
    padding: 40px;
  }
}
</style>

最终得到的结果如下:

useMutationObserver(监听DOM树修改)

监听DOM树修改。什么意思呢?就是用于观察指定元素及其子元素的 DOM 变化,并在发生变化时执行相应的回调函数。如下:

<template>
  <div>
    <h2>DOM元素监视器</h2>
    <div ref="targetElement">
      监视的元素
    </div>
    <button @click="changeElement">改变元素</button>
    {{ messages }}
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import { useMutationObserver } from '@vueuse/core'

const targetElement = ref()
const messages = ref<any[]>([])

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 = 'red'
</script>

最终得到的结果如下: 

useWindowFocus(跟踪窗口焦点)

使用 window.onfocus 和 window.onblur 事件响应式跟踪窗口焦点。什么意思呢?就是实时监测浏览器窗口的焦点状态,即浏览器窗口是处于激活状态(获得焦点)还是非激活状态(失去焦点)。如下:

<template>
  <div>{{ message }}</div>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue'
import { useWindowFocus } from '@vueuse/core'

const startMessage = '💡单击文档之外的某个位置以取消聚焦。'
const message = ref(startMessage)
const focused = useWindowFocus()

watch(focused, (isFocused) => {
  if (isFocused)
    message.value = startMessage
  else
    message.value = 'ℹ 选项卡未聚焦'
})
</script>

最终得到的结果如下: 

useWindowScroll(获取窗口的滚动位置)

响应式获取窗口的滚动位置。什么意思呢?就是实时监测浏览器窗口的滚动位置,包括水平和垂直方向上的滚动距离,通过监听窗口的滚动事件,你可以实现一些响应式的效果,例如根据用户滚动位置展示或隐藏导航栏、懒加载页面内容、实现无限滚动加载等。如下:

<template>
  <div class="showTip">
    滚动值:<br>
    X轴{{ x }} - y轴{{ y }}
  </div>
  <div class="windowScroll"></div>
</template>

<script setup lang="ts">
import { useWindowScroll } from '@vueuse/core'
const { x, y } = useWindowScroll()
</script>

<style scoped lang="scss">
.showTip {
  width: 120px;
  height: 50px;
  background: #008c8c;
  position: fixed;
  bottom: 20px;
  right: 20px;
}
.windowScroll {
  width: 10000px;
  height: 200vh;
  background: #eee;
}
</style>

最终得到的结果如下: 

useWindowSize(获取窗口尺寸)

响应式获取窗口尺寸。什么意思呢?就是用于获取浏览器窗口的尺寸信息,通过监听窗口大小变化事件,你可以实现一些响应式的布局或样式,确保页面在不同设备或窗口尺寸下都能够正确展示。如下:

<template>
  <div class="use-window-size">
    width: {{ width }}, height: {{ height }}
  </div>
</template>

<script lang="ts" setup>
import { useWindowSize } from '@vueuse/core'

const { width, height } = useWindowSize()
</script>

最终得到的结果如下: 

最后总结

useActiveElement:监测和响应用户与页面的交互,自动聚焦输入框或执行验证操作。

useDocumentVisibility:管理页面的可见性状态,优化用户体验和应用程序性能。

useDraggable:实现元素的拖拽功能,从而增强了应用程序的交互性和可用性。

useDropZone:在 Vue 应用中实现拖放区域,从而提升应用的交互性和用户体验。

useElementBounding:获取和管理元素的边界信息,处理元素相关的操作和交互。

useElementSize:响应式的方式获取和管理元素的尺寸信息,处理元素相关的操作和交互。

useResizeObserver:监测元素大小的变化,并实时响应变化。

useElementVisibility:监测和响应元素的可见性变化,实现与可见性相关的功能和优化。

useIntersectionObserver:实现在元素可见状态变化时自动更新相关的界面内容或状态。

useMouseInElement:追踪和监测鼠标在指定元素内的位置和状态。

useMutationObserver:监测 DOM 变化,并实时响应变化。

useWindowFocus:监测浏览器窗口的焦点状态,实现一些交互效果改善用户体验。

useWindowScroll:实时监听浏览器窗口的滚动事件,实现一些响应式效果。

useWindowSize:实时获取和响应浏览器窗口的尺寸信息,实现响应式布局。


网站公告

今日签到

点亮在社区的每一天
去签到