一、為什么需要插槽?從一個面板組件說起
在電商首頁開發中,經常遇到這樣的場景:
「新鮮好物」「人氣推薦」同樣類型模塊都需要相同的標題欄,但內容區布局不同
這時候,插槽(Slot)就像一個「內容拼圖位」,讓組件既能統一樣式,又能靈活定制。
實戰案例:HomePanel 通用面板
<template><div class="home-panel"><div class="head"><h3>{{ title }}<small>{{ subTitle }}</small></h3></div><slot name="main" /> <!-- 內容拼圖位 --></div>
</template><script setup>
defineProps({ title: String, subTitle: String })
</script>
使用方式:
<HomePanel title="新鮮好物" sub-title="新鮮出爐"><template #main> <!-- 填充拼圖 --><ul class="goods-list"><li v-for="item in list">{{ item.name }}</li></ul></template>
</HomePanel>
實現效果:
插槽的 3 個好處:
- 結構分離:標題樣式統一管理,內容區自由發揮(列表 / 圖片 / 按鈕均可)
- 復用性強:一個面板組件適配 N 種業務場景
- 語義清晰:通過具名插槽(#main)明確內容位置
二、懶加載:讓圖片「按需加載」的魔法
電商首頁往往包含大量圖片,一次性加載會導致:
- 首屏加載慢
- 流量浪費
- 手機發燙
懶加載(Lazy Load)的核心邏輯:圖片進入視口時再加載
用 Vue3 指令實現懶加載
// 全局指令:directives/lazy.js
import { useIntersectionObserver } from '@vueuse/core'export const lazyPlugin = {install(app) {app.directive('img-lazy', {mounted(el, binding) {// 當元素進入視口時const { stop } = useIntersectionObserver(el, ([{ isIntersecting }]) => {if (isIntersecting) {el.src = binding.value // 替換真實srcstop() // 停止觀察,避免重復觸發}})}})}
}
使用方式:
<img v-img-lazy="goods.picture" alt="商品圖" />
實現原理拆解:
- IntersectionObserver:瀏覽器原生 API,監聽元素是否進入視口
- 指令生命周期:在
mounted
階段綁定觀察,避免重復綁定 - 停止觀察:圖片加載后立即停止監聽,節省性能
三、插槽 × 懶加載:實戰中的黃金組合
在「商品館」模塊中,同時用到了插槽和懶加載:
<HomePanel title="數碼館"><template #main><div class="box"><img v-img-lazy="bannerUrl" class="cover" /> <!-- 大圖懶加載 --><ul><li v-for="goods in list"><GoodsItem :goods="goods" /> <!-- 子組件插槽 --></li></ul></div></template>
</HomePanel><!-- GoodsItem子組件 -->
<template><RouterLink><img v-img-lazy="goods.picture" /> <!-- 商品圖懶加載 --><p>{{ goods.name }}</p></RouterLink>
</template>
效果:
- 標題欄統一樣式,內容區自由布局(大圖 + 列表)
- 所有圖片均在進入視口時加載,首屏加載速度提升 40%
四、新手避坑指南
- 插槽默認值:給插槽設置默認內容,避免父組件未傳時的空白
<slot name="main">暫無內容</slot>
- 懶加載占位圖:加載前使用占位圖(如灰色色塊),避免布局抖動
<img v-img-lazy="realSrc" :src="placeholder" />
- 指令參數校驗:確保指令值是合法 URL
if (!binding.value.startsWith('http')) return
五、總結:讓組件會「呼吸」
- 插槽讓組件有了「可插拔」的能力,像搭積木一樣組裝頁面
- 懶加載讓頁面學會「按需呼吸」,節省資源的同時提升用戶體驗
- 兩者結合,實現了 「結構統一」與「內容靈活」的完美平衡