最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue使用<Suspense/>實(shí)現(xiàn)圖片加載組件

 更新時(shí)間:2026年01月25日 10:44:37   作者:咸魚翻身更入味  
Suspense是Vue的內(nèi)置組件,用于管理異步組件的加載狀態(tài),包括等待、出錯(cuò)和最終渲染,它通過兩個(gè)插槽(default和fallback)來實(shí)現(xiàn)這一功能,感興趣的可以了解一下

什么是Suspense?

SuspenseVue的內(nèi)置組件,能讓你管理組件加載時(shí)的等待、出錯(cuò)和最終渲染邏輯。

主要配合異步組件、async/await 版的 setup() 使用。

它提供兩個(gè)插槽:

  • default(默認(rèn)插槽):要渲染的異步內(nèi)容
  • fallback:等待異步內(nèi)容加載時(shí)顯示的兜底內(nèi)容

話不多說,上代碼:

第一步,實(shí)現(xiàn)圖片異步組件

<template>
    <img 
    :src="props.src" 
    :alt="props.alt" 
    :style="{ 
      width: setWidth, 
      height: setHeight, 
      borderRadius: rounded, 
      objectFit: 'cover'
    }"
    />
</template>
// =================================== 此處為計(jì)算屬性邏輯 ================================
<script setup lang="ts">
import { computed, ref } from "vue";

// 圖片形狀可選項(xiàng)
type ShapeOption = "circle" | "square" | "roundRect";

interface ILazyImage {
  src: string;
  width:string|number;
  height:string|number;
  delay?:number;//延遲執(zhí)行?
  timeout?:number;//超時(shí)時(shí)間?
  shape?:ShapeOption;//圖片形狀
  alt?:string;
}

const props = defineProps<ILazyImage>();

//計(jì)算超時(shí)
const timeoutSet = computed(() => {
    let time = Number(props.timeout) || 5;
    return time * 1000;
});

//計(jì)算延遲
const delayTime = computed(() => {
    let time = Number(props.delay) || 0.1;
    return time * 1000;
});


//計(jì)算寬度
const setWidth = computed(() => {
    const val = parseFloat(props.width)
    if(!val) return '100px'
    return val  + "px";
});

//計(jì)算高度
const setHeight = computed(() => {
    const val = parseFloat(props.Height)
    if(!val) return '100px'
    return val  + "px";
});

// 計(jì)算圓角
const rounded = computed(() => {
    switch (props.shape) {
        case "circle":
            return "50%";
        case "square":
            return "0";
        case "roundRect":
            return "10px";
        default:
            return "10px";
    }
});

//========================實(shí)現(xiàn)異步加載圖片==================================

const loadImage = (src: string) => {
    return new Promise((resolve, reject) => {
    // 創(chuàng)建一個(gè)AbortController,用于取消請求
        const controller = new AbortController();
        const signal = controller.signal;

        const timeoutId = setTimeout(() => {
        // 超時(shí)時(shí)取消請求
            controller.abort();
            reject(new Error("圖片加載超時(shí)"));
        }, timeoutSet.value);

        setTimeout(() => {
            const image = new Image();
            image.src = src;
            image.onload = () => {
                clearTimeout(timeoutId);
                resolve(src);
            };
            image.onerror = () => {
                clearTimeout(timeoutId);
                reject(new Error("圖片加載失敗"));
            };
        }, delayTime.value);
    });
};

// 執(zhí)行圖片加載(async/await 觸發(fā) Suspense 等待)
await loadImage(props.src);

</script>

第二步:實(shí)現(xiàn)懶加載組件

  • default(默認(rèn)插槽):要渲染的異步內(nèi)容
  • fallback:等待異步內(nèi)容加載時(shí)顯示的兜底內(nèi)容
  • 使用v-bind()綁定屬性

<Suspense></Suspense>中直接使用異步組件即可,<template #fallback></template>則是加載時(shí)顯示

<template>
    <div>
        <Suspense>
            <template #default>
                <div class="image">
                    <Image v-bind="{ ...props }"></Image>
                </div>
            </template>
            <template #fallback>
                <div class="skeleton"></div>
            </template>
        </Suspense>
    </div>
</template>

<script setup lang="ts">
import { computed } from "vue";
import Image from "./Image.vue";
// 圖片形狀可選項(xiàng)
type ShapeOption = "circle" | "square" | "roundRect";

interface ILazyImage {
  src: string;
  width:string|number;
  height:string|number;
  delay?:number;//延遲執(zhí)行?
  timeout?:number;//超時(shí)時(shí)間?
  shape?:ShapeOption;//圖片形狀
  alt?:string;
}

const props = defineProps<ILazyImage>();

//計(jì)算超時(shí)
const timeoutSet = computed(() => {
    let time = Number(props.timeout) || 5;
    return time * 1000;
});

//計(jì)算延遲
const delayTime = computed(() => {
    let time = Number(props.delay) || 0.1;
    return time * 1000;
});


//計(jì)算寬度
const setWidth = computed(() => {
    const val = parseFloat(props.width)
    if(!val) return '100px'
    return val  + "px";
});

//計(jì)算高度
const setHeight = computed(() => {
    const val = parseFloat(props.Height)
    if(!val) return '100px'
    return val  + "px";
});

// 計(jì)算骨架屏動(dòng)畫:遮罩寬度(取容器寬度的 40%) 
const setSeletonWidth = computed(() => { 
    // 提取寬度數(shù)值(兼容 px 單位) 
    const widthNum = parseFloat(setWidth.value) || 100; 
    return `${widthNum * 0.4}px`;
}); 


// 骨架屏動(dòng)畫起始位置(從容器左側(cè)外 30% 開始)
const setSeletonStartRight = computed(() => { 
    const widthNum = parseFloat(setWidth.value) || 100; 
    return `-${widthNum * 1.3}px`;  // 起始在容器左側(cè)外
});

// 骨架屏動(dòng)畫結(jié)束位置(到容器右側(cè)外 30%) 
const setSeletonEndRight = computed(() => { 
    const widthNum = parseFloat(setWidth.value) || 100; return `${widthNum * 1.3}px`;
    // 結(jié)束在容器右側(cè)外
});

// 計(jì)算圓角
const rounded = computed(() => {
    switch (props.shape) {
        case "circle":
            return "50%";
        case "square":
            return "0";
        case "roundRect":
            return "10px";
        default:
            return "10px";
    }
});
</script>

<style scoped>
.image {
    overflow: hidden;
}

.skeleton {
    width: v-bind(setWidth);
    height: v-bind(setHeight);
    background-color: #dfe4ea;
    overflow: hidden;
    position: relative;

    border-radius: v-bind(rounded);
}

.skeleton::before {
    content: "";
    display: block;
    background-color: #ced6e0;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
    position: absolute;
    top: 0;
    right: v-bind(setSeletonStartRight);
    width: v-bind(setSeletonWidth);
    height: v-bind(setHeight);
    transform: skewX(-30deg);
    animation: ping 1s infinite ease-out;
    filter: blur(10px);
}

@keyframes ping {
    from {
        right: v-bind(setSeletonStartRight);
    }

    to {
        right: v-bind(setSeletonEndRight);
    }
}
</style>

補(bǔ)充

  • 代碼內(nèi)有些重復(fù)的內(nèi)容,可使用另外的ts來聲明或?qū)崿F(xiàn)。
  • 其中可能有些變量或?qū)崿F(xiàn)過程有誤,此文章僅供參考。

到此這篇關(guān)于Vue使用&lt;Suspense/&gt;實(shí)現(xiàn)圖片加載組件的文章就介紹到這了,更多相關(guān)Vue &lt;Suspense/&gt;圖片加載內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

营山县| 平顺县| 桐梓县| 南汇区| 龙海市| 新巴尔虎左旗| 益阳市| 道孚县| 定陶县| 安图县| 连州市| 当涂县| 神池县| 临桂县| 肥东县| 保山市| 藁城市| 曲阳县| 土默特右旗| 万宁市| 宁安市| 邯郸市| 浦东新区| 东阿县| 莎车县| 景洪市| 台东县| 金山区| 宜川县| 安庆市| 新闻| 沾益县| 鹿邑县| 修武县| 石阡县| 宜黄县| 洱源县| 铜山县| 连州市| 甘谷县| 平顶山市|