PHP 怎么PHP 骨架屏

wen PHP项目 2

PHP 骨架屏实现方案

骨架屏(Skeleton Screen)是一种在页面内容加载完成前展示的占位图形,能提升用户体验,以下是几种在 PHP 项目中实现骨架屏的方案:

PHP 怎么PHP 骨架屏

服务端渲染骨架屏

<?php
// 骨架屏组件类
class SkeletonScreen {
    public static function render($type = 'card') {
        $skeleton = '';
        switch ($type) {
            case 'card':
                $skeleton = '
                <div class="skeleton-card">
                    <div class="skeleton-image skeleton-animation"></div>
                    <div class="skeleton-text skeleton-animation"></div>
                    <div class="skeleton-text skeleton-animation short"></div>
                </div>';
                break;
            case 'list':
                $skeleton = '
                <div class="skeleton-list">
                    <div class="skeleton-item">
                        <div class="skeleton-avatar skeleton-animation"></div>
                        <div class="skeleton-content">
                            <div class="skeleton-text skeleton-animation"></div>
                            <div class="skeleton-text skeleton-animation short"></div>
                        </div>
                    </div>
                </div>';
                break;
            case 'table':
                $skeleton = '
                <div class="skeleton-table">
                    <div class="skeleton-row">
                        <div class="skeleton-cell skeleton-animation"></div>
                        <div class="skeleton-cell skeleton-animation"></div>
                        <div class="skeleton-cell skeleton-animation"></div>
                    </div>
                    <div class="skeleton-row">
                        <div class="skeleton-cell skeleton-animation"></div>
                        <div class="skeleton-cell skeleton-animation"></div>
                        <div class="skeleton-cell skeleton-animation"></div>
                    </div>
                </div>';
                break;
        }
        return $skeleton;
    }
}
// 在页面中使用
$pageContent = getPageContent(); // 获取实际内容
$isLoading = empty($pageContent);
if ($isLoading) {
    echo SkeletonScreen::render('card');
} else {
    echo $pageContent;
}
?>

CSS 动画骨架屏

/* skeleton.css */
.skeleton-animation {
    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
    background-size: 200% 100%;
    animation: skeleton-loading 1.5s ease infinite;
    border-radius: 4px;
}
@keyframes skeleton-loading {
    0% {
        background-position: 200% 0;
    }
    100% {
        background-position: -200% 0;
    }
}
.skeleton-card {
    padding: 16px;
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.skeleton-image {
    width: 100%;
    height: 200px;
    margin-bottom: 16px;
}
.skeleton-text {
    width: 100%;
    height: 16px;
    margin-bottom: 8px;
}
.skeleton-text.short {
    width: 60%;
}
.skeleton-list {
    padding: 16px;
}
.skeleton-item {
    display: flex;
    align-items: center;
    margin-bottom: 12px;
}
.skeleton-avatar {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    margin-right: 12px;
}
.skeleton-content {
    flex: 1;
}
.skeleton-table {
    padding: 16px;
}
.skeleton-row {
    display: flex;
    margin-bottom: 8px;
}
.skeleton-cell {
    flex: 1;
    height: 20px;
    margin-right: 8px;
}

PHP 中间件实现

<?php
// 骨架屏中间件
class SkeletonMiddleware {
    public function handle($request, Closure $next) {
        $response = $next($request);
        // 检查是否需要显示骨架屏
        if ($this->shouldShowSkeleton($request)) {
            $content = $response->getContent();
            // 生成骨架屏 HTML
            $skeletonHtml = $this->generateSkeleton($request->getPath());
            // 替换内容容器
            $content = str_replace(
                '<div id="content-container"></div>',
                $skeletonHtml,
                $content
            );
            $response->setContent($content);
        }
        return $response;
    }
    private function shouldShowSkeleton($request) {
        // 判断条件:首次加载、API 请求中、缓存未命中等
        return !$request->isAjax() && !$request->has('no_skeleton');
    }
    private function generateSkeleton($path) {
        // 根据不同页面路径返回不同骨架屏
        $skeletons = [
            '/' => 'home',
            '/products' => 'list',
            '/users' => 'table',
        ];
        $type = $skeletons[$path] ?? 'card';
        return SkeletonScreen::render($type);
    }
}

结合 JavaScript 动态切换

<?php
// PHP 生成骨架屏 + JS 切换实际内容
class HybridSkeleton {
    public static function renderWithContent($content, $type = 'card') {
        $skeleton = SkeletonScreen::render($type);
        return <<<HTML
        <div id="skeleton-container" data-type="{$type}">
            {$skeleton}
        </div>
        <div id="content-container" style="display:none;">
            {$content}
        </div>
        <script>
            // 页面加载完成后,5秒后切换
            setTimeout(function() {
                document.getElementById('skeleton-container').style.display = 'none';
                document.getElementById('content-container').style.display = 'block';
            }, 5000);
            // 或者等实际内容加载完成后切换
            window.onload = function() {
                document.getElementById('skeleton-container').style.display = 'none';
                document.getElementById('content-container').style.display = 'block';
            };
        </script>
HTML;
    }
}

使用缓存提高性能

<?php
class CachedSkeleton {
    private $cacheDir = '/tmp/skeleton_cache/';
    public function getCachedSkeleton($page, $type) {
        $cacheFile = $this->cacheDir . md5($page . $type) . '.html';
        if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < 3600) {
            return file_get_contents($cacheFile);
        }
        $skeleton = SkeletonScreen::render($type);
        file_put_contents($cacheFile, $skeleton);
        return $skeleton;
    }
}

使用示例

<?php
// 在控制器中使用
class UserController {
    public function index() {
        $users = UserRepository::getAll();
        if (empty($users)) {
            // 显示骨架屏
            return SkeletonScreen::render('table');
        }
        // 显示实际内容
        return view('users.index', ['users' => $users]);
    }
}
// 或者在模板中使用
// 在 Blade 或 PHP 模板中:
@if($isLoading)
    {!! App\Helpers\SkeletonScreen::render('card') !!}
@else
    @foreach($items as $item)
        <div class="real-content">{{ $item->name }}</div>
    @endforeach
@endif

最佳实践建议

  1. 选择合适的骨架屏类型:根据不同页面内容选择卡片、列表、表格等类型
  2. 优化加载时机:在首次加载或异步请求时显示骨架屏
  3. 缓存骨架屏 HTML:减少重复生成的开销
  4. 支持多种屏幕尺寸:确保骨架屏在移动端和桌面端都显示良好
  5. 考虑无障碍性:给骨架屏元素添加 aria-hidden="true" 属性

这样可以在 PHP 项目中有效实现骨架屏,提升用户体验。

抱歉,评论功能暂时关闭!