vue自定义指令监听元素是否进入父元素视窗内

简介: 一般涉及 dom 的操作,我们都可以通过自定义指令来实现,比如点击文本直接复制到粘贴板、按钮权限的判断(无权限时隐藏或禁用)...这一点一般通过指令钩子函数的第一个参数 el 就能实现

需求背景

一个每行3列的列表布局,列表中的每一项有一个已读/未读状态,只要展现在了用户的视窗内就算已读状态了。

想到的方案:

  • 直接监听滚动高度,根据滚动距离来计算是否展现在页面内
  • 借助第三方插件,找到一个 vue-check-view,不过只能监听整个 window 视窗的页面滚动,如果想监听某个元素的内部滚动是否可见没法实现

刚开始直接用的 vue-check-view,但是因为项目是用 electron 开发的桌面应用,布局上需要在列表父盒子上实现滚动。然后想到h5里新出的监听元素是否进入视口的 IntersectionObserver,一看好像可以满足,在借助 vue 的自定义指令来封装成一个自定义指令使用。

除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。

一般涉及 dom 的操作,我们都可以通过自定义指令来实现,比如点击文本直接复制到粘贴板、按钮权限的判断(无权限时隐藏或禁用)...这一点一般通过指令钩子函数的第一个参数 el 就能实现。

但是,有时我们除了对 dom 的操作外,还需要实现对 vue 页面 data 数据的修改、methods 里方法的调用,或者一些额外的参数需要传到指令里来进行判断的...这时我们就可以借助第二个参数 binding 来实现,binding.value 就是我们写在指令 = 后面的东西,可以传递函数、对象、数值、字符串、布尔任意类型(注意和 binding.expression 的区别)。

监听元素是否进入某个视口自定义指令

监听元素是否进入某个视口自定义指令,可以通过 root 参数传入父视口的选择器,不传就默认是相对于浏览器window窗口。适用于元素懒加载、埋点上报、查看了修改状态。

viewport.js

export default {
   
  inserted(el, binding, vnode) {
   
    const value = binding.value
    const isObject = Object.prototype.toString.call(value) === '[object Object]'
    const func = isObject ? value.callback : value
    const isFunc = func && typeof func === 'function'

    const selector = isObject ? value.root : null
    const threshold = isObject ? value.threshold : 1
    const options = {
   
      root: selector ? document.querySelector(selector) : null, // 指定根(root)元素,未指定或 null 则默认为浏览器视窗
      threshold: threshold || 1, // 监听目标与边界盒交叉区域的比例值 0-1
    }

    const observer = new IntersectionObserver(entries => {
   
      entries.forEach(entry => {
   
        if (entry.isIntersecting) {
   
          // 执行回调方法
          isFunc && func()

          // 停止监听
          observer.unobserve(el)
        }
      })
    }, options)

    // 开始监听元素
    observer.observe(el)
  },
}
AI 代码解读

使用方式

  • 使用方式一:v-viewport="handleViewport" 直接绑定一个回调方法
  • 使用方式二:v-viewport="{callback: handleViewport, root: '#scroll', threshold: 0.8}" 绑定一个对象自定义各项配置
<template>
  <div class="list">
    <div
      v-for="(item, index) in 100"
      :key="index"
      class="item"
      v-viewport="handleViewport(index)"
    >
      我是第 {
  { index }} 个
    </div>
  </div>
</template>
<script>
import viewport from 'xx/viewport.js'
export default {
  directives: {
    viewport
  },
  methods: {
    handleViewport(i) {
      console.log(`第${i}个进入视窗内`)
    }
  }
}
</script>
<style>
.list {
  height: 400px;
  overflow-y: auto;
}

.item {
  height: 100px;
  background: green;
  margin-bottom: 10px;
}
</style>
AI 代码解读
相关文章
Vue实现动态数据透视表(交叉表)
Vue实现动态数据透视表(交叉表)
75 13
极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图
本文介绍了使用 Vue Flow 绘制流程图的方法与技巧。Vue Flow 是一个灵活强大的工具,适合自定义复杂的流程图。文章从环境要求(Node.js v20+ 和 Vue 3.3+)、基础入门案例、自定义功能(节点与连线的定制、事件处理)到实际案例全面解析其用法。重点强调了 Vue Flow 的高度灵活性,虽然预定义内容较少,但提供了丰富的 API 支持深度定制。同时,文中还分享了关于句柄(handles)的使用方法,以及如何解决官网复杂案例无法运行的问题。最后通过对比 mermaid,总结 Vue Flow 更适合需要高度自定义和复杂需求的场景,并附带多个相关技术博客链接供进一步学习。
属性描述符初探——Vue实现数据劫持的基础
属性描述符还有很多内容可以挖掘,比如defineProperty与Proxy的区别,比如vue2与vue3实现数据劫持的方式有什么不同,实现效果有哪些差异等,这篇博文只是入门,以后有时间再深挖。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
4月前
|
vue使用iconfont图标
vue使用iconfont图标
187 1
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。
ry-vue-flowable-xg:震撼来袭!这款基于 Vue 和 Flowable 的企业级工程项目管理项目,你绝不能错过
基于 Vue 和 Flowable 的企业级工程项目管理平台,免费开源且高度定制化。它覆盖投标管理、进度控制、财务核算等全流程需求,提供流程设计、部署、监控和任务管理等功能,适用于企业办公、生产制造、金融服务等多个场景,助力企业提升效率与竞争力。
131 12
Vue中的class和style绑定
在 Vue 中,class 和 style 绑定是基于数据驱动视图的强大功能。通过 class 绑定,可以动态更新元素的 class 属性,支持对象和数组语法,适用于普通元素和组件。style 绑定则允许以对象或数组形式动态设置内联样式,Vue 会根据数据变化自动更新 DOM。
Vue Router 简介
Vue Router 是 Vue.js 官方的路由管理库,用于构建单页面应用(SPA)。它将不同页面映射到对应组件,支持嵌套路由、路由参数和导航守卫等功能,简化复杂前端应用的开发。主要特性包括路由映射、嵌套路由、路由参数、导航守卫和路由懒加载,提升性能和开发效率。安装命令:`npm install vue-router`。
iframe嵌入页面实现免登录思路(以vue为例)
通过上述步骤,可以在Vue.js项目中通过 `iframe`实现不同应用间的免登录功能。利用Token传递和消息传递机制,可以确保安全、高效地在主应用和子应用间共享登录状态。这种方法在实际项目中具有广泛的应用前景,能够显著提升用户体验。
409 8