基于Vue插槽的ImageLoader组件图片加载失败后如何重新加载
ImageLoader 组件重新加载功能实现方案
不需要重载整个组件,最优方案是通过作用域插槽暴露重载方法,以下是具体实现:
实现步骤
步骤1:修改ImageLoader组件代码
首先修正原代码的一处笔误:watch监听中Status.Pending拼写错误,常量定义为全大写的Status.PENDING,需先修正避免运行报错。
之后在组件的methods中新增公开的reload方法,同时给error插槽添加作用域参数,将reload方法传递给插槽使用者:
<template> <div class="load-image"> <slot v-if="status === 'loaded'" name="image" /> <!-- 给error插槽传递reload方法 --> <slot v-else-if="status ==='failed'" name="error" :reload="reload"/> <slot v-else-if="status ==='loading'" name='preloader'/> </div> </template> <script> const Status = { PENDING: "pending", LOADING: "loading", LOADED: "loaded", FAILED: "failed" } export default { // 原有data、created、updated逻辑保持不变 watch: { src(value) { // 修正原拼写错误 this.status = value ? Status.LOADING : Status.PENDING; }, }, methods: { // 新增reload方法 reload() { if (!this.src) return this.status = Status.LOADING this.createLoader() }, // 原有方法保持不变 createLoader() { this.destroyLoader(); this.img= new Image(); this.img.onload = this.handleLoad; this.img.onerror = this.handleError; this.img.crossOrigin = this.crossOrigin; this.img.src = this.src; }, destroyLoader() { if (this.img){ this.img.onload = null; this.img.onerror = null; this.img = null } }, handleLoad() { this.destroyLoader(); this.status = Status.LOADED; this.$emit("onLoad"); }, handleError(error) { this.destroyLoader(); this.status = Status.FAILED; this.$emit("onError", error); console.log(error) } } } </script>
步骤2:使用组件时绑定重新加载按钮
使用作用域插槽拿到暴露的reload方法,绑定到按钮的点击事件即可:
<ImageLoader> <img slot="image" :src="image.path" /> <div slot="preloader" > <p>Image is loading!</p> </div> <!-- 用slot-scope获取插槽传递的reload方法 --> <div slot="error" slot-scope="{ reload }"> <p>Error! Image Didn't load</p> <button @click="reload">重新加载</button> </div> </ImageLoader>
为什么不需要重载整个组件
重载组件(比如通过动态修改key强制重新渲染)属于冗余操作,会触发组件完整的生命周期重建,产生不必要的DOM销毁和重建开销,还会丢失组件内部的临时状态,完全没有必要。
其他可选实现方案
如果不想修改ImageLoader组件的源码,可以选择以下方案:
- 父组件监听
onError事件,点击重新加载时给图片地址加随机时间戳后缀(比如image.path =${image.path}?t=${Date.now()}``),组件的watch会检测到src变化自动触发重新加载。该方案的缺点是会修改原始资源地址,可能影响缓存策略,部分有签名校验的CDN资源可能无法正常加载。 - 给ImageLoader加ref属性,父组件直接通过
this.$refs.xxx.createLoader()调用内部加载方法,该方案需要维护ref引用,多个组件实例使用时不够灵活。
内容的提问来源于stack exchange,提问作者StarPass
相关产品推荐
相关产品推荐

