vue-加载效果没反应?让我来瞅瞅~

在网页开发中,当数据还没加载出来时,部分组件可能会呈现空白状态。所以为了提升用户体验,我们通常会添加加载效果,让用户知道页面此时正在加载中。而在Vue中,就可以通过Element Plus提供的v-loading指令来实现这一效果:

<div class="main-container"  v-loading="loading" 
element-loading-text="加载中..." element-loading-background="rgba(0,0,0,0)"> 

</div>

然后在组件逻辑中,我们需要控制loading状态:

<script setup>
const loading = ref(false) // 添加loading状态

//....其他代码

onMounted(() => {
  loading.value = true
  // 初始化数据
  initializeData()
  loading.value = false
})

</script>

但是,这段代码并没有按预期工作,加载效果显示不出来。为什么呢?这个问题的关键就在于 JavaScript 的异步执行和 Vue 的响应式系统了。

【知识点强行插入:小葵花课堂开课了!!!】


JavaScript的单线程与事件循环

JavaScript是一种单线程语言,这意味着它一次只能执行一个任务。许多操作(如网络请求、文件读取等)都是异步的,这些操作不会立即完成,而是会在未来的某个时间点完成。

当主线程按顺序执行代码时,一旦遇到异步操作,就会将其放入任务队列,然后继续执行主线程代码。当主线程空闲之后,才会从任务队列中取出任务执行。这就是JavaScript的事件循环(Event Loop)机制。为了处理异步操作,JavaScript提供了几种方法:

1. 回调函数

回调函数是最早用于处理异步操作的方式。通过将函数作为参数传递给异步操作,当操作完成时,该函数会被调用。

function fetchData(callback) {
  setTimeout(() => {
    const data = { name: '示例数据' }
    callback(data)
  }, 1000)
}

fetchData((data) => {
  console.log(data) // 1秒后打印: { name: '示例数据' }
})
 但回调函数容易导致"回调地狱",使代码难以维护。

2. Promise

Promise是一种表示异步操作最终完成(或失败)及其结果值的对象。它有三种状态:pending(进行中)、fulfilled(已完成)和rejected(已失败)。

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const data = { name: '示例数据' }
      resolve(data)
      // 如果出错: reject(new Error('获取数据失败'))
    }, 1000)
  })
}

fetchData()
  .then(data => console.log(data))
  .catch(error => console.error(error))

3. async/await

async/await是基于Promise的语法糖,使异步代码看起来更像同步代码。使用async声明一个函数时,该函数会返回一个Promise。使用await关键字可以暂停代码的执行,直到Promise完成。

async function getData() {
  try {
    const data = await fetchData()
    console.log(data)
  } catch (error) {
    console.error(error)
  }
}

getData()

回到我们的问题

在最初的代码中,initializeData()是一个异步函数,它返回一个Promise。问题出在以下代码片段:

onMounted(() => {
  loading.value = true
  initializeData() // 异步操作
  loading.value = false // 这行代码会立即执行,不会等待异步操作完成
})

因为JavaScript的单线程特性,代码会按顺序执行:

  1. 设置loading.value = true
  2. 调用initializeData(),这是一个异步操作,会被放入任务队列
  3. 立即执行loading.value = false,不等待异步操作完成
  4. 此时Vue会重新渲染,由于loading已经是false,所以加载效果不会显示

整个过程发生得太快,以至于用户根本看不到加载效果。要正确实现加载效果,我们需要确保在异步操作完成后才将loading设置为false。有几种方法可以实现:

第一种:使用Promise的then方法

onMounted(() => {
  loading.value = true
  initializeData()
    .then(() => {
      loading.value = false
    })
    .catch(error => {
      console.error(error)
      loading.value = false
    })
})

第二种:使用async/await(更推荐)

onMounted(async () => {
  loading.value = true
  try {
    await initializeData()
  } catch (error) {
    console.error(error)
  } finally {
    loading.value = false
  }
})

//使用async/await使代码更加清晰易读。
//finally块确保无论操作成功还是失败,loading都会被设置为false。

ok,问题解决了,那我们接着继续来讲一下“Vue的响应式系统”:

【知识点强行插入:小葵花课堂又开课了!!!】


Vue的响应式系统

在Vue中,响应式数据(如使用ref创建的loading变量)的变化会触发组件的重新渲染。当我们修改loading.value时,Vue会检测到这个变化,并更新DOM以反映新的状态。

然而,如果在同一个同步代码块中连续修改响应式数据,Vue会批量处理这些更新,只在当前事件循环结束时进行一次DOM更新。这就是为什么在我们的原始代码中看不到加载效果的另一个原因:

// 在同一个同步代码块中
loading.value = true
// ... 代码 ...
loading.value = false

Vue只会看到最终的状态(loading = false),而忽略中间状态。


ps:处理多个异步操作

在实际应用中,我们可能需要处理多个异步操作。例如,同时获取用户信息和文章列表:

onMounted(async () => {
  loading.value = true
  try {
    // 并行执行多个异步操作
    const [userInfo, articles] = await Promise.all([
      fetchUserInfo(),
      fetchArticles()
    ])
    
    // 处理获取到的数据
    processUserInfo(userInfo)
    processArticles(articles)
  } catch (error) {
    console.error('加载数据失败:', error)
  } finally {
    loading.value = false
  }
})

使用Promise.all可以并行执行多个异步操作,只有当所有操作都完成后,才会设置loading.value = false。

总结

在Vue中实现加载效果时,需要正确理解JavaScript的异步执行机制和Vue的响应式系统:

  1. JavaScript是单线程的,异步操作会被放入任务队列
  2. 在处理异步操作时,应使用Promise或async/await
  3. 确保在异步操作完成后再更改loading状态
  4. Vue的响应式系统会批量处理在同一个事件循环中的状态更新

通过正确实现加载效果,我们可以显著提升用户体验,让用户清楚地知道应用正在处理数据,而不是出现了故障。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值