当前位置: 首页 > 知识库问答 >
问题:

javascript - 如何在 Vue.js 中解决异步数据加载导致的布局偏移问题?

孟建木
2024-06-28

布局偏移该怎么解决?

初始加载页面的时候,需要先请求数据,然后再显示。此时就会出现一个问题,在请求未响应的时候数据为空,显示区域未空,当得到数据之后,显示区域数据扩充,这就造成了数据便宜。

该显示区域的大小由数据决定,不能设置一个固定的大小。
我想如果可以在挂载之前获取这个数据的话,应该可以避免这个布局偏移。但是获取数据的操作是异步的,不会等待获取完之后再挂载。或者说在路由跳转的时候获取这个数据。(这个数据不多)

image.png

共有4个答案

冀景明
2024-06-28

我的想法还是数据prefetch,有几种方案供参考:

  1. 用 SWR 库进行数据请求,可以一定程度减少数据请求耗时
const { data, error, isLoading, isValidating, mutate } = useSWR(key, fetcher, options)
  1. 用preload属性放html上,进行数据提前加载

    <link rel="preload" href="/api/data" as="fetch" crossorigin="anonymous">
  2. 将数据请求的代码单独抽离到一个prefetch.js文件里面,然后利用打包配置,分包到单独一个init chunk

    // webpack.config.js
    
    entry: {
      prefetch: './prefetch.js'
    }
    
    splitChunks: {
      cacheGroups: {
     common: {
        name: 'common',
        chunk: 'initial',
        minChunks: 2,
        minSize: 0
     }
      }
    }
    
  3. 终极解决方案就是上SSR了,在中间层获取数据后,放页面上,一起返回给浏览器。

其它方案ai Bot里面列出来了:

  1. 骨架屏、过渡动画
  2. before路由钩子里面获取。
傅毅然
2024-06-28

看你图例觉得是占位问题,不是位移。如果你觉得页面突然被撑开,用户体验不好,有两个办法

1、设置一个空状态或loading状态设置一个最小高度。

min-height:xxx

2、另外就是移动端或者pc端用的骨架屏,暂估你这个区域显示10条数据或20条等,骨架屏循环10条或20条就可以了。

参考:https://1x.antdv.com/components/skeleton-cn/


陆栋
2024-06-28

OP你的 布局偏移 指的是啥?是说一开始没数据,所以本来应该展示在第二屏的区域展示在第一屏了,然后数据回来之后会突然出现第一屏的内容的这个位移问题,还是指什么问题?

如果是这个的话,可以把第一屏的内容做 骨架屏 的处理。这样会在请求的数据响应之前保持一定的内容占位。

如果是其他的问题,那得OP你补充具体的问题描述了。

谢铭
2024-06-28

在 Vue.js 中解决异步数据加载导致的布局偏移问题,通常有以下几种策略:

  1. 骨架屏/占位符
    在数据加载之前,使用占位符或骨架屏来占据页面的空间。这样,即使数据还未加载完成,页面的布局也不会发生突然的变化。
  2. 条件渲染
    使用 v-ifv-show 指令来根据数据是否加载完成来渲染组件。这样,只有当数据加载完成后,相关的组件才会被渲染到页面上。
  3. Vue 的 v-cloak 指令
    这个指令用于在 Vue 实例编译结束前隐藏元素。结合 CSS,你可以隐藏正在加载的数据区域,直到数据加载完成。
  4. 异步组件和加载器
    对于大型组件,可以使用 Vue 的异步组件功能,结合 Webpack 的代码分割,来按需加载组件。同时,你可以显示一个加载器来提示用户数据正在加载。
  5. 路由守卫
    在 Vue Router 中使用路由守卫(如 beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave)来在路由跳转之前获取数据。这样,当路由切换时,数据已经准备好,可以直接渲染到页面上。
  6. 使用状态管理工具
    如果你的项目已经使用了 Vuex 或其他状态管理工具,你可以在这些工具中管理数据的加载状态。然后,在组件中根据这个状态来决定是否渲染数据。
  7. CSS 动画和过渡
    使用 CSS 动画和过渡来平滑地显示加载完成后的数据。这样,即使数据加载导致了布局变化,用户也不会感到突兀。

示例代码(使用条件渲染)

<template>
  <div>
    <!-- 使用 v-if 来根据数据是否加载完成来渲染组件 -->
    <div v-if="dataLoaded">
      <!-- 这里是显示数据的组件或模板 -->
      <div v-for="item in data" :key="item.id">
        {{ item.name }}
      </div>
    </div>
    <!-- 加载器或占位符 -->
    <div v-else>
      <p>数据正在加载...</p>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dataLoaded: false,
      data: [],
    };
  },
  async created() {
    // 在组件创建时获取数据
    const response = await fetchData(); // 假设 fetchData 是你的数据获取函数
    this.data = response.data;
    this.dataLoaded = true;
  },
};
</script>

在这个示例中,当数据还未加载完成时(dataLoadedfalse),只显示一个加载器或占位符。当数据加载完成后(dataLoaded 变为 true),才渲染显示数据的组件或模板。

 类似资料:
  • 一个select框组件,其中的数据是从后端返回的,打开这个组件时往里传入了value值,但是页面打开时也会显示这个value值,等后端结果返回才能显示对应的label值,如何让组件先不渲染value直接渲染label? 将请求的生命周期放在async created中没用

  • 本文向大家介绍Javascript vue.js表格分页,ajax异步加载数据,包括了Javascript vue.js表格分页,ajax异步加载数据的使用技巧和注意事项,需要的朋友参考一下 分页一般和表格一起用,分页链接作为表格的一部分,将分页链接封装成一个独立的组件,然后作为子组件嵌入到表格组件中,这样比较合理。 效果: 代码: 1.注册一个组件 js 模板: HTML: 当点击分页链接的时候

  • 本文向大家介绍vue.js 表格分页ajax 异步加载数据,包括了vue.js 表格分页ajax 异步加载数据的使用技巧和注意事项,需要的朋友参考一下 Vue.js是一个轻巧、高性能、可组件化的MVVM库,同时拥有非常容易上手的API。 分页一般和表格一起用,分页链接作为表格的一部分,将分页链接封装成一个独立的组件,然后作为子组件嵌入到表格组件中,这样比较合理。 1.注册一个组件 js 模板: H

  • 本文向大家介绍JavaScript异步加载问题总结,包括了JavaScript异步加载问题总结的使用技巧和注意事项,需要的朋友参考一下 同步加载的问题 默认的js是同步加载的,这里的“加载”可以理解成是解析、执行,而不是“下载”,在最新版本的浏览器中,浏览器对于代码请求的资源都是瀑布式的加载,而不是阻塞式的,但是js的执行总是阻塞的。这会引起什么问题呢?如果我的index页面要加载一些js,但是其

  • 主要内容:echarts_test_data.json 数据:,实例,实例,实例ECharts 通常数据设置在 setOption 中,如果我们需要异步加载数据,可以配合 jQuery等工具,在异步获取数据后通过 setOption 填入数据和配置项就行。 ECharts 通常数据设置在 setOption 中,如果我们需要异步加载数据,可以配合 jQuery等工具,在异步获取数据后通过 setOption 填入数据和配置项就行。 json 数据: echarts_test_

  • 我正在试着检查用户是在Iphone上还是在Android上 当我注释这行代码时,应用程序运行良好

  • 抱歉打扰你们了。我知道,这个问题已经问了好几遍了。然而,我就是无法解决我的问题。 所以,我一直在尝试创建一个网球计分系统,当你点击两个按钮之一,赢按钮或输按钮时,就会显示出分数。我有一个按钮,他们可以在那里添加他们的名字到计分系统。当一个选手赢了两盘,比赛就结束了。然后我试着印上他们的名字,上面写着,____赢了比赛。当我尝试使用打印它们名称的变量时,我得到的结果是:[objectHTMLButt

  • 一个名为专题报告的下拉框,点击下拉框后给后端发一个special_report/special_report/selectList的get请求,将获取到的数据展示在下拉框,当我第一次点击下拉框时,没有数据,之后点击数据就展示出来了,百度是因为fetch发的是异步请求,于是在fetch中添加一个Promise,但是无效,用async/await依然无效,求大佬指点!! 第一次点击: 之后点击: