Vue3 圖片加載失敗回退為默認圖:最簡、健壯的兩種實現(含完整代碼)

先上結論:給 <img> 綁定 @error,在回調里將 src 切到默認頭像,并斷開二次觸發,配合 new URL(..., import.meta.url).href 解析靜態資源路徑,可靠、可維護。


場景與目標

  • 登錄用戶有頭像 URL,但可能 404/跨域/失效
  • 希望頭像加載失敗時自動展示本地默認圖
  • 方案要易用、無副作用、可復用

方案一:在組件內用 @error 兜底(最輕量)

核心點:

  • @error="setDefaultAvatar" 捕獲加載錯誤
  • event.target.src = defaultAvatar 切換默認圖
  • event.target.onerror = null 防止死循環
  • new URL(..., import.meta.url).href 解析本地靜態資源,避免相對路徑坑

示例(節選自 header.vue):

<template><div class="user-info"><!-- 未登錄 --><a href="javascript:;" class="loginBtn" @click="goLogin('/index')" v-if="!isLogin()"><img src="../../assets/logo/yonghutu.png" alt="" class="user-avatar" @error="setDefaultAvatar"></a><span class="user-name" v-if="!isLogin()" @click="goLogin('/index')">登錄</span><!-- 已登錄 --><a href="javascript:;" class="loginBtn" @click="router.push('/index')" v-if="isLogin()"><img :src="avatar" alt="" class="user-avatar" @error="setDefaultAvatar"></a><span class="user-name" v-if="isLogin()" @click="router.push('/index')">{{ userName }}</span></div>
</template><script setup>
import { ref } from 'vue'const defaultAvatar = new URL('../../assets/logo/yonghutu.png', import.meta.url).href
const avatar = ref(defaultAvatar)function setDefaultAvatar(event) {try {if (event && event.target) {event.target.src = defaultAvatar// 防止 onerror 死循環event.target.onerror = null}} catch (_) {}
}
</script>

為什么用 new URL

  • 構建工具(Vite/Rollup)會靜態分析并正確處理資源(hash、輸出目錄)
  • 避免相對路徑在不同目錄/構建模式下失效

注意點:

  • 一定要在回調里置空 onerror,否則默認圖異常也會循環觸發
  • 默認圖建議放 src/assets,構建時會被正確打包

方案二:抽成全局指令(全站任意 img 一把梭)

當全局大量使用圖片兜底時推薦。一次注冊,哪里需要哪里用。

指令定義(例如 src/directives/imgFallback.js):

export default {mounted(el, binding) {const fallbackSrc = binding.valueif (!fallbackSrc) returnel.addEventListener('error', function onErr() {el.src = fallbackSrcel.removeEventListener('error', onErr) // 防止死循環})},
}

在入口注冊(main.js):

import { createApp } from 'vue'
import App from './App.vue'
import imgFallback from './directives/imgFallback'const app = createApp(App)
app.directive('img-fallback', imgFallback)
app.mount('#app')

使用:

<img :src="user.avatar" v-img-fallback="defaultAvatar" alt="">

搭配 new URL

const defaultAvatar = new URL('@/assets/logo/yonghutu.png', import.meta.url).href

優點:

  • 一次注冊,全局可用
  • 模板更干凈,不用每次都寫 @error

可選增強:封裝組件 <AvatarImg />

當你想統一尺寸、圓角、占位 skeleton、裁剪模式時,用組件最舒服。

<!-- components/AvatarImg.vue -->
<template><img:src="currentSrc":alt="alt":style="style"@error="onErr"loading="lazy"decoding="async"/>
</template><script setup lang="ts">
import { ref, computed } from 'vue'interface Props {src?: stringfallback?: stringsize?: numberradius?: number | stringfit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'alt?: string
}
const props = withDefaults(defineProps<Props>(), {size: 28,radius: '50%',fit: 'cover',alt: 'avatar',
})const defaultFallback = new URL('@/assets/logo/yonghutu.png', import.meta.url).href
const currentSrc = ref(props.src || defaultFallback)function onErr(e: Event) {currentSrc.value = props.fallback || defaultFallbackconst target = e.target as HTMLImageElementtarget.onerror = null
}const style = computed(() => ({width: `${props.size}px`,height: `${props.size}px`,borderRadius: typeof props.radius === 'number' ? `${props.radius}px` : props.radius,objectFit: props.fit,
}))
</script>

使用:

<AvatarImg :src="user.avatar" :fallback="defaultAvatar" :size="32" />

踩坑提示(別跳)

  • 防死循環:兜底里務必 el.onerror = null 或移除監聽
  • 跨域:遠程頭像若無 CORS,不能 canvas 操作;兜底不受影響
  • Token 鑒權:需要帶 Header 的圖片建議走后端代理;兜底依然有效
  • CLS 問題:給 <img> 固定 width/height 或用包裹容器固定尺寸,避免布局抖動
  • SSR/靜態導出:new URL(..., import.meta.url) 在 Vite/SSR 里均可用,避免硬編碼路徑
  • 性能:加上 loading="lazy" decoding="async",滾動頁面更順暢

結論

  • 局部用法:@error + setDefaultAvatar,最簡單
  • 全局用法:自定義指令 v-img-fallback
  • 高級用法:封裝 <AvatarImg /> 統一樣式與行為

參考

  • Vue 官方文檔(指令與事件處理)https://vuejs.org/guide/essentials/template-syntax.html
  • Vite 資源處理 https://vitejs.dev/guide/assets.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/920442.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/920442.shtml
英文地址,請注明出處:http://en.pswp.cn/news/920442.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

VisionPro聯合編程控件導入WinFrom以及VS卡死問題

在工業自動化領域&#xff0c;C#和VisionPro都是備受矚目的工具。C#是一種功能強大的編程語言&#xff0c;廣泛應用于Windows平臺上的應用程序開發。而VisionPro則是一款視覺檢測軟件&#xff0c;廣泛應用于自動化生產線上的產品質量檢測。將C#與VisionPro結合使用&#xff0c;…

練習spring mvc

1. 項目結構總結 這個Spring MVC項目采用Maven管理&#xff0c;遵循標準的Web項目結構。以下是詳細的文件級別結構&#xff1a; 核心目錄結構 springmvc_helloword/ ├── .idea/ # IDEA項目配置目錄 │ ├── artifacts/ # 項目打包配置…

postgreSql遠程連接數據庫總是超時斷開?

問題&#xff1a;postgresql經常遇到連接中斷的情況&#xff0c;程序幾分鐘就會斷一次很難受。 pg的日志大量報錯&#xff1a; 2025-08-27 11:05:43.967 CST [26462] LOG: could not receive data from client: Connection reset by peer 2025-08-27 11:05:43.967 CST [2625…

【Java基礎】Java數據結構深度解析:Array、ArrayList與LinkedList的對比與實踐

Java數據結構深度解析&#xff1a;Array、ArrayList與LinkedList的對比與實踐 在Java編程中&#xff0c;數據存儲與操作是最基礎的能力要求。Array&#xff08;數組&#xff09;、ArrayList&#xff08;動態數組&#xff09;與LinkedList&#xff08;雙向鏈表&#xff09;作為最…

Flask測試平臺開發,登陸重構

概述我們在開篇的時候實現了簡單的登陸功能&#xff0c;也實現了一個前后端聯調的登陸功能&#xff0c;但是你有沒有發現&#xff0c;那個登陸只是一個簡單的登陸&#xff0c;且密碼在接口返回的過程中是銘文密碼&#xff0c;在生產環境中使用肯定是不行的&#xff0c;一般密碼…

tiny4412 Qt環境搭建

1.硬件環境PC端&#xff1a;ubuntu18.04 開發板硬件平臺&#xff1a;tiny4412 內核版本&#xff1a;linux3.5 交叉編譯器&#xff1a;arm-linux-gcc Qt版本&#xff1a;Qt5.62.搭建ubuntu下Qt編譯環境1.在用戶目錄下的src_pack目錄下解壓。 [wbyqwbyq src_pack]$ pwd /home/wby…

將本地jar包推到遠程倉庫

前提條件&#xff0c;手里有個jar包想推到maven遠程倉庫 1. 在maven項目中&#xff0c;輸入腳本執行 2. 在電腦中打開PowerShell以管理員身份運行&#xff0c;輸入腳本執行 # 使用 Maven 將本地 JAR 文件上傳到遠程 Maven 倉庫&#xff08;PowerShell 版本&#xff09; # 注…

企業級監控可視化系統 Prometheus + Grafana

警報&#xff08;Alerting&#xff09;&#xff1a;使用 Prometheus 的 Alertmanager 或 Grafana 的內置告警功能&#xff0c;在指標異常時發送通知&#xff08;郵件、Slack、釘釘等&#xff09;。 服務發現&#xff1a;在云環境中&#xff08;Kubernetes, Consul等&#xff09…

極簡風格PDF格式轉換解決方案

雖然PDF非常適合于閱讀和分享&#xff0c;但有時我們需要對文檔做一些調整&#xff0c;如增加注釋、高亮重點信息或者填寫表單字段。 它的的界面設計簡潔&#xff0c;它有強大的格式轉換功能&#xff0c;不單單是將PDF轉換成word文檔或者PDF轉換 excel&#xff0c;還能將PDF文…

Linux 把啟動腳本制作成系統服務(通過 systemctl start xxx 啟動)

描述 正常我們啟動某一個應用時&#xff0c;會新建一個sh腳本&#xff0c;每次調用起來和設置開機自啟會非常麻煩 所以把這個啟動文件制作成系統服務&#xff0c;每次啟動只需要輸入以下命令就可以啟動 systemctl start xxx也可以設置開機自啟 systemctl enable xxx接下來我拿R…

AI應用開發中的安全最佳實踐詳解

AI應用開發中的安全最佳實踐詳解 隨著大語言模型&#xff08;LLM&#xff09;及相關API服務的廣泛應用&#xff0c;內容安全成為開發者不可忽視的重要議題。本文將系統梳理在AI應用開發過程中保障安全的技術手段與最佳實踐&#xff0c;并結合像 https://api.aaaaapi.com 這樣成…

介紹智慧城管十大核心功能之一:風險預警系統

我們的風險預警系統系統包含&#xff1a;排水安全運行預測預警、環衛設施安全運行預測預警、內澇安全運行預測預警、路面塌陷安全運行預測預警、人員密集場所安全運行預測預警及運行統計分析。1. 排水安全運行預測預警1) 排水設施監測 a) 實時數據采集 支持實時采集排水管網的水…

初識Linux · 文件系統

目錄 前言&#xff1a; 簡單理解文件系統 細節理解 前言&#xff1a; 前文我們介紹了磁盤&#xff0c;介紹磁盤的原因是因為我們需要在理解文件系統之前&#xff0c;通過磁盤的了解&#xff0c;介紹一些文件相關的內容&#xff0c;比如文件是如何在磁盤里面存儲的&#xff…

前端數據庫 IndexedDB

前端數據庫 IndexedDB IndexedDB核心概念解析1. 數據庫&#xff08;Database&#xff09;2. 對象存儲&#xff08;Object Store&#xff09;3. 索引&#xff08;Index&#xff09;4. 事務&#xff08;Transaction&#xff09;5. 游標&#xff08;Cursor&#xff09; IndexDB的使…

Cesium入門教程(二)環境搭建(HTML版)

一、快速開始&#xff08;無需安裝依賴&#xff09; 1. 創建HTML文件 新建一個 .html 文件&#xff08;如 cesium-demo.html&#xff09;&#xff0c;粘貼以下代碼&#xff1a; <!DOCTYPE html> <html> <head><title>Cesium Quick Start</title&g…

數據分析學習筆記4:加州房價預測

一、實驗概述本實驗旨在利用機器學習技術&#xff0c;基于加州房價數據集&#xff08;California Housing Dataset&#xff09;構建一個房價預測模型。實驗涵蓋了從數據加載、探索性數據分析&#xff08;EDA&#xff09;、數據預處理到模型構建與評估的完整流程。核心任務是利用…

openEuler Embedded 的 Yocto入門 : 2. 構建一個Hello,world!

獲取BitBake 官方下載 git clone https://git.yoctoproject.org/poky cd poky/bitbake國內鏡像下載&#xff08;推薦&#xff09; git clone https://gitee.com/openeuler/yocto-poky.git -b v3.3.6 cd yocto-poky/bitbake配置BitBake環境 export PATH/path/to/bitbake/bin:$PA…

人工智能物聯網(AIoT)的技術邏輯、核心價值與典型應用場景解析

一、AIoT 技術&#xff1a;從 “連接” 到 “智能” 的底層邏輯 在企業數字化轉型過程中&#xff0c;“數據” 常被視為核心資產&#xff0c;但如何讓海量數據產生實際價值&#xff0c;卻成為多數組織的難題。根據 Gartner 2024 年發布的調查數據&#xff0c;87% 的組織商業智…

SpringBoot系列之實現高效批量寫入數據

Spring Boot 實現高效批量插入數據的實踐指南 在實際開發中&#xff0c;我們經常會遇到需要批量插入大量數據到數據庫的場景。如果使用傳統的單條插入方式&#xff0c;不僅效率低下&#xff0c;還會給數據庫帶來巨大壓力。本文將介紹如何使用 Spring Boot 實現高效 批量數據插入…

SQL語言基礎知識(2)

在學會創建數據庫之后&#xff0c;在數據庫中需要創建表&#xff08;實體以表的形式存在&#xff09;&#xff0c;以及對表中存儲的數據記錄進行定義&#xff0c;相當于 Java 語言中對類編寫其屬性。在定義前我們需要了解 SQL 語言有哪些數據類型。一、數據類型1.1 數據值類型1…