textare区域或者其他输入位置内容更新页面会发生偏移现象

具体说明:是公司的一个低代码平台,在一个textarea区域里可以配置json文件,但是当编辑完json文件之后不管是自动保存还是command+是(我是mac)或者是说上面的保存按钮都会使页面向上偏移一段距离(页面跳一下然后位置发生变化)

代码:

我采用了比较笨的方法就是控制滚动条的位置

javascript 复制代码
<template>
  <div class="json-editor" @mouseleave="mouseleave">
    <textarea ref="textarea" />
  </div>
</template>
<script>
    scrollCursor() {
      const scrollInfo = this.jsonEditor.getScrollInfo()
      this.jsonEditor.scrollTo(scrollInfo.left, scrollInfo.top)
    },
    mouseleave() {
      const scrollInfo = this.jsonEditor.getScrollInfo()
      const val = this.jsonEditor.getValue()
      this.$emit('input', val)
      this.$nextTick(() => {
        this.jsonEditor.scrollTo(scrollInfo.left, scrollInfo.top)
      })
    }
  }
</script>

写了一个scrollCursor 方法,调取了this.jsonEditor 这个对象的getScrollInfo()方法来获取当前编辑器的滚动信息。

getScrollInfo是一个对象通常包含以下信息:

  • left:编辑器当前的水平滚动位置,即相对于编辑器左边缘的偏移量。
  • top:编辑器当前的垂直滚动位置,即相对于编辑器顶部的偏移量。
  • width:编辑器的宽度。
  • height:编辑器的高度。
  • clientWidth:编辑器可视区域的宽度。
  • clientHeight:编辑器可视区域的高度。

然后设置滚动位置:

kotlin 复制代码
this.jsonEditor.scrollTo(scrollInfo.left, scrollInfo.top);

但是这个方法只有在command+s保存的情况下有用,对用mouseleave这个方法并没有用,经过排查是

kotlin 复制代码
this.$emit('input', val)

这一行代码导致的页面偏移(保存的按钮在父组件里面)可能是组件之间的信息传递导致父组件可能会重新渲染。这可能会导致编辑器在重新渲染后重置滚动位置,从而出现偏移现象。

也有可能是因为父组件在接收到 input 事件后,可能会对编辑器的值进行一些处理或操作,这些处理操作可能间接影响了编辑器的滚动位置。

解决办法:

kotlin 复制代码
 mouseleave() {
      const scrollInfo = this.jsonEditor.getScrollInfo()
      const val = this.jsonEditor.getValue()
      this.$emit('input', val)
      this.$nextTick(() => {
        this.jsonEditor.scrollTo(scrollInfo.left, scrollInfo.top)
      })
    }
    //或者
  mouseleave() {
  const val = this.jsonEditor.getValue();
  this.$emit('input', val);

  setTimeout(() => {
    this.scrollCursor();
  }, 0); // 延迟执行 scrollCursor 方法
}

使用 this.$nextTick 可以防止页面偏移,原因在于 this.$nextTick 的执行时机和 Vue 的响应式更新机制。具体来说,这个方法在更新 DOM 后执行,使得滚动位置调整是在 DOM 更新完成后进行,避免了页面偏移问题

使用 setTimeout(() => { this.scrollCursor(); }, 0); 可以避免页面偏移,主要是因为它将 scrollCursor 方法的执行推迟到 JavaScript 事件队列中的下一个周期。这给 Vue.js 足够的时间来处理 this.$emit('input', val) 引发的响应式更新

那为什么这段代码:

kotlin 复制代码
mouseleave() {
const val = this.jsonEditor.getValue(); 
this.$emit('input', val); 
}

就是会引起页面偏移呢?

没有 this.$nextTick 或 setTimeout 的代码执行顺序如下:

  1. 获取当前编辑器的值 val。
  2. 触发 input 事件,导致父组件或其他地方的响应式数据更新。
  3. 响应式数据更新后,可能触发 DOM 的重新渲染和重新布局。

因为 mouseleave 事件的处理程序在 Vue 完成 DOM 更新之前立即触发并执行,所以在数据更新过程中可能引起滚动位置的变化。

使用 this.$nextTick 或 setTimeout 的不同

当使用 this.$nextTick 或 setTimeout 时,实际上是在延迟执行滚动位置的恢复操作,直到 Vue 完成其内部的 DOM 更新。这样可以确保滚动位置的调整发生在 DOM 变化之后,避免了页面偏移的问题。

相关推荐
鬼手点金2 小时前
nanoGPT/nanochat 能做出 DeepSeek/Qwen 这样的大模型吗?
服务器·前端·javascript·bug·openclaw
蛋蛋的就会顺顺的3 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
程序员Sunday3 小时前
TypeScript 的 any、unknown、never 有什么区别?
前端·面试·typescript
朱涛的自习室3 小时前
70 美金的 Beyond Compare,我让 Gemini 4 和 DeepSeek 造个开源免费版(Day 2)
android·前端·人工智能
码艺-Alimjan4 小时前
Tauri 源码备份 · 打包 & 解压 总结,源码收集之路
前端·javascript·vue.js
小马不起床4 小时前
零基础玩转 FastAPI_11:前端后台管理页面
前端·状态模式·fastapi
子非鱼a5 小时前
【文件上传】一个普普通通的edu16
前端
美狐美颜SDK开放平台6 小时前
直播APP如何实现美白滤镜功能?视频美颜SDK技术开发方案详解
前端·数据库·人工智能·音视频·美颜sdk·直播美颜sdk·视频美颜sdk
pride.li6 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
屏什么录7 小时前
电脑如何录屏幕视频和声音?从工具到代码,7 种方案帮你彻底搞定
前端·音视频开发