• 作者:老汪软件技巧
  • 发表时间:2024-09-24 04:01
  • 浏览量:

先上效果

项目背景

客户定制需求,需要实现一个类表格数据项管理,每个表格项区分是文本输入还是数字输入,或者其他类型。其他类型呢,一个输入框或者一个选择框就可以搞定,但是文本不行。因为文本通常会有很多,以及换行,或者带有序标识,单一的文本框就不足以满足需求。所以最终采用多行文本域加定位的方式,支持内容编辑撑开自动响应位置,保证随处点开的编辑框能完全展示在页面可视区域内。

技术实现

vue3 + elementPlus + 客户代码中的 vxe-table

刚开始接到需求的时候,我想的特别简单,就是获取元素的位置,获取外容器滚动的距离,以及屏幕可视化区域的高度,一顿相加判定。没错,就实现了。

但是,我说但是,只是实现了20%。只是实现了在页面上部分出弹出框,往下滑动的时候弹窗跟随正常。

当元素从底部开始网上滑动的时候就不行了,因为 他们三者之间的关系真的很巧妙,一旦边界判定差一像素,文本框的位置都是失效的。

你们是不是也遇到过这种问题呢。我真的是肝了好长时间!

各种调试、删减代码,最后发现实际也就是关键位置的一个判定而已,瞬间茅塞顿开。

难点剖析

核心:实际也就是弹层输入框的高度, 页面触发块的位置, 可视区域的高度 三者之间的运算

// 当前触发块的位置
const currentCellReac = currentCell.value.getBoundingClientRect()
// 弹层输入框的位置
const _ref = editTextareaRef.value.$el.getBoundingClientRect()
// 可视区域的高度
const viewportHeight = window.innerHeight;
/*
如果弹层输入框的高度 > 视口的高度 - 页面触发块的top位置,代表着弹层输入框在两者之间已经放不下了,所以就需要根据视口位置定位在底部不可移动
反之,就需要跟随 页面触发块的位置 随之变化
*/
if (_ref.height > viewportHeight - currentCellReac.top) {
    textareaStyle.value.position = 'absolute';
    textareaStyle.value.bottom = '0';
    textareaStyle.value.top = 'auto';
} else {
    textareaStyle.value.position = 'fixed';
    textareaStyle.value.top = `${currentCellReac.top}px`;
    textareaStyle.value.bottom = 'auto';
}

_swiper仿臭美app滑动_仿臭美app滑动

图例展示

注意点

在弹层编辑的时候,页面的渲染与获取高度的时机,可能会有问题,虽然加比较大的 setTimeout 可以实现,但是页面效果会有明显的卡顿

所以小编在这里使用的是 requestAnimationFrame 进行帧校正渲染,可以优雅的解决这个问题。

插个广告,不熟悉 requestAnimationFrame 的小伙伴,可以看一下我的另一篇文章/post/741591…

requestAnimationFrame(() => {
    // 弹层输入框
    const _ref = editTextareaRef.value.$el.getBoundingClientRect()
    // 视口高度
    const viewportHeight = window.innerHeight;
	// 弹层加视口高度
    const _demo = _ref.height + rect.top
	
    if (_demo > viewportHeight) {
        textareaStyle.value.position = 'absolute';
        textareaStyle.value.bottom = '0';
        textareaStyle.value.top = 'auto';
    } else {
        textareaStyle.value.position = 'fixed';
        textareaStyle.value.top = `${rect.top}px`;
        textareaStyle.value.bottom = 'auto';
    }
	// 主动聚焦到弹层输入框
    if (editTextareaRef.value) editTextareaRef.value.focus()
})

因为 弹层 是文本编辑公用的,且是频繁更改的,vue 会代理这份数据,且下一次的弹层的位置数据会根据上一次的弹层最后关闭的位置信息,会有影响。

具体的体现就是,弹层的位置总是一次正确一次不正确,轮询展示。

总结一波源码部分

老生常谈,因为时间问题,就没有太细的提取封装,源码跟项目需求走,如有需要,自行提取。源码包含 类表格数据渲染部分

大家如果有什么更好的思路,欢迎在评论区讨论。