eee
This commit is contained in:
+267
-2
@@ -113,20 +113,32 @@ class BladeCompiler
|
|||||||
// 移除注释
|
// 移除注释
|
||||||
$content = $this->compileComments($content);
|
$content = $this->compileComments($content);
|
||||||
|
|
||||||
// 编译 Echo 语句
|
// 编译 Echo 语句(包括 @json)
|
||||||
$content = $this->compileEchos($content);
|
$content = $this->compileEchos($content);
|
||||||
|
|
||||||
// 编译指令
|
// 编译指令
|
||||||
$content = $this->compileDirectives($content);
|
$content = $this->compileDirectives($content);
|
||||||
|
|
||||||
|
// 编译条件判断语法糖
|
||||||
|
$content = $this->compileConditionalDirectives($content);
|
||||||
|
|
||||||
// 编译布局和继承(如果未跳过)
|
// 编译布局和继承(如果未跳过)
|
||||||
if (!$skipLayouts) {
|
if (!$skipLayouts) {
|
||||||
$content = $this->compileLayouts($content);
|
$content = $this->compileLayouts($content);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 编译包含
|
// 编译包含和组件
|
||||||
$content = $this->compileIncludes($content);
|
$content = $this->compileIncludes($content);
|
||||||
|
|
||||||
|
// 编译 @each 指令
|
||||||
|
$content = $this->compileEach($content);
|
||||||
|
|
||||||
|
// 编译栈和推送
|
||||||
|
$content = $this->compileStacks($content);
|
||||||
|
|
||||||
|
// 编译表单辅助
|
||||||
|
$content = $this->compileFormHelpers($content);
|
||||||
|
|
||||||
// 编译原始 PHP
|
// 编译原始 PHP
|
||||||
$content = $this->compilePhp($content);
|
$content = $this->compilePhp($content);
|
||||||
|
|
||||||
@@ -148,6 +160,7 @@ class BladeCompiler
|
|||||||
* 编译 Echo 语句
|
* 编译 Echo 语句
|
||||||
* {{ $var }} => <?php echo htmlspecialchars($var, ENT_QUOTES, 'UTF-8'); ?>
|
* {{ $var }} => <?php echo htmlspecialchars($var, ENT_QUOTES, 'UTF-8'); ?>
|
||||||
* {!! $var !!} => <?php echo $var; ?>
|
* {!! $var !!} => <?php echo $var; ?>
|
||||||
|
* @json($var) => JSON 编码输出
|
||||||
*
|
*
|
||||||
* @param string $content
|
* @param string $content
|
||||||
* @return string
|
* @return string
|
||||||
@@ -166,6 +179,12 @@ class BladeCompiler
|
|||||||
return "<?php echo {$expression}; ?>";
|
return "<?php echo {$expression}; ?>";
|
||||||
}, $content);
|
}, $content);
|
||||||
|
|
||||||
|
// 编译 @json 指令
|
||||||
|
$content = preg_replace_callback('/@json\s*\((.+?)\)/', function ($matches) {
|
||||||
|
$expression = trim($matches[1]);
|
||||||
|
return "<?php echo json_encode({$expression}, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,6 +233,25 @@ class BladeCompiler
|
|||||||
$content = preg_replace('/@break\b/', '<?php break; ?>', $content);
|
$content = preg_replace('/@break\b/', '<?php break; ?>', $content);
|
||||||
$content = preg_replace('/@continue\b/', '<?php continue; ?>', $content);
|
$content = preg_replace('/@continue\b/', '<?php continue; ?>', $content);
|
||||||
|
|
||||||
|
// 处理 @lang 指令(语言翻译)
|
||||||
|
$content = preg_replace_callback('/@lang\s*\([\'"](.+?)[\'"]\s*(?:,\s*\[(.+?)\])?\)/', function ($matches) {
|
||||||
|
$key = $matches[1];
|
||||||
|
$replace = $matches[2] ?? '[]';
|
||||||
|
return "<?php echo function_exists('__') ? __('{$key}', {$replace}) : '{$key}'; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// 处理 @class 指令(条件类名)
|
||||||
|
$content = preg_replace_callback('/@class\s*\((.+?)\)/', function ($matches) {
|
||||||
|
$conditions = trim($matches[1]);
|
||||||
|
return "<?php echo is_array({$conditions}) ? implode(' ', array_keys(array_filter({$conditions}))) : {$conditions}; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// 处理 @style 指令(条件样式)
|
||||||
|
$content = preg_replace_callback('/@style\s*\((.+?)\)/', function ($matches) {
|
||||||
|
$styles = trim($matches[1]);
|
||||||
|
return "<?php if (is_array({$styles})): echo 'style=\"' . implode('; ', array_map(function(\$k, \$v) { return \$k . ':' . \$v; }, array_keys({$styles}), {$styles})) . '\"'; else: echo 'style=\"' . {$styles} . '\"'; endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,6 +359,233 @@ class BladeCompiler
|
|||||||
}, $content);
|
}, $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编译 @each 指令
|
||||||
|
* @each('view', $items, 'item', 'empty')
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function compileEach(string $content): string
|
||||||
|
{
|
||||||
|
return preg_replace_callback('/@each\s*\([\'"](.+?)[\'"]\s*,\s*(.+?)\s*(?:,\s*[\'"](.+?)[\'"]\s*(?:,\s*[\'"](.+?)[\'"])?)?\)/', function ($matches) {
|
||||||
|
$view = $matches[1];
|
||||||
|
$items = trim($matches[2]);
|
||||||
|
$itemVar = $matches[3] ?? "'item'";
|
||||||
|
$emptyView = $matches[4] ?? null;
|
||||||
|
|
||||||
|
$itemVar = trim($itemVar, "'\"");
|
||||||
|
|
||||||
|
if ($emptyView) {
|
||||||
|
return "<?php if (count({$items}) > 0): foreach ({$items} as \${$itemVar}): echo \Kiri\Router\Blade\BladeHelper::include('{$view}', ['{$itemVar}' => \${$itemVar}]); endforeach; else: echo \Kiri\Router\Blade\BladeHelper::include('{$emptyView}', []); endif; ?>";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<?php foreach ({$items} as \${$itemVar}): echo \Kiri\Router\Blade\BladeHelper::include('{$view}', ['{$itemVar}' => \${$itemVar}]); endforeach; ?>";
|
||||||
|
}, $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编译条件判断语法糖
|
||||||
|
* @isset, @empty, @auth, @guest, @hasSection, @unless 等
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function compileConditionalDirectives(string $content): string
|
||||||
|
{
|
||||||
|
// @isset($var) ... @endisset
|
||||||
|
$content = preg_replace_callback('/@isset\s*\((.+?)\)\s*(.*?)\s*@endisset/s', function ($matches) {
|
||||||
|
$var = trim($matches[1]);
|
||||||
|
$body = $matches[2];
|
||||||
|
return "<?php if (isset({$var})): ?>{$body}<?php endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @empty($var) ... @endempty
|
||||||
|
$content = preg_replace_callback('/@empty\s*\((.+?)\)\s*(.*?)\s*@endempty/s', function ($matches) {
|
||||||
|
$var = trim($matches[1]);
|
||||||
|
$body = $matches[2];
|
||||||
|
return "<?php if (empty({$var})): ?>{$body}<?php endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @auth ... @endauth
|
||||||
|
$content = preg_replace_callback('/@auth\s*(?:\((.+?)\))?\s*(.*?)\s*@endauth/s', function ($matches) {
|
||||||
|
$guard = $matches[1] ?? '';
|
||||||
|
$body = $matches[2];
|
||||||
|
if ($guard) {
|
||||||
|
return "<?php if (auth('{$guard}')->check()): ?>{$body}<?php endif; ?>";
|
||||||
|
}
|
||||||
|
return "<?php if (function_exists('auth') && auth()->check()): ?>{$body}<?php endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @guest ... @endguest
|
||||||
|
$content = preg_replace_callback('/@guest\s*(?:\((.+?)\))?\s*(.*?)\s*@endguest/s', function ($matches) {
|
||||||
|
$guard = $matches[1] ?? '';
|
||||||
|
$body = $matches[2];
|
||||||
|
if ($guard) {
|
||||||
|
return "<?php if (!auth('{$guard}')->check()): ?>{$body}<?php endif; ?>";
|
||||||
|
}
|
||||||
|
return "<?php if (!function_exists('auth') || !auth()->check()): ?>{$body}<?php endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @hasSection('name') ... @endhasSection
|
||||||
|
$content = preg_replace_callback('/@hasSection\s*\([\'"](.+?)[\'"]\)\s*(.*?)\s*@endhasSection/s', function ($matches) {
|
||||||
|
$name = $matches[1];
|
||||||
|
$body = $matches[2];
|
||||||
|
return "<?php if (isset(\$__sections['{$name}'])): ?>{$body}<?php endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @sectionMissing('name') ... @endsectionMissing
|
||||||
|
$content = preg_replace_callback('/@sectionMissing\s*\([\'"](.+?)[\'"]\)\s*(.*?)\s*@endsectionMissing/s', function ($matches) {
|
||||||
|
$name = $matches[1];
|
||||||
|
$body = $matches[2];
|
||||||
|
return "<?php if (!isset(\$__sections['{$name}'])): ?>{$body}<?php endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @unless($condition) ... @endunless
|
||||||
|
$content = preg_replace_callback('/@unless\s*\((.+?)\)\s*(.*?)\s*@endunless/s', function ($matches) {
|
||||||
|
$condition = trim($matches[1]);
|
||||||
|
$body = $matches[2];
|
||||||
|
return "<?php if (!({$condition})): ?>{$body}<?php endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @can('permission') ... @endcan
|
||||||
|
$content = preg_replace_callback('/@can\s*\([\'"](.+?)[\'"]\s*(?:,\s*(.+?))?\)\s*(.*?)\s*@endcan/s', function ($matches) {
|
||||||
|
$permission = $matches[1];
|
||||||
|
$model = $matches[2] ?? '';
|
||||||
|
$body = $matches[3];
|
||||||
|
if ($model) {
|
||||||
|
return "<?php if (function_exists('can') && can('{$permission}', {$model})): ?>{$body}<?php endif; ?>";
|
||||||
|
}
|
||||||
|
return "<?php if (function_exists('can') && can('{$permission}')): ?>{$body}<?php endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @cannot('permission') ... @endcannot
|
||||||
|
$content = preg_replace_callback('/@cannot\s*\([\'"](.+?)[\'"]\s*(?:,\s*(.+?))?\)\s*(.*?)\s*@endcannot/s', function ($matches) {
|
||||||
|
$permission = $matches[1];
|
||||||
|
$model = $matches[2] ?? '';
|
||||||
|
$body = $matches[3];
|
||||||
|
if ($model) {
|
||||||
|
return "<?php if (!function_exists('can') || !can('{$permission}', {$model})): ?>{$body}<?php endif; ?>";
|
||||||
|
}
|
||||||
|
return "<?php if (!function_exists('can') || !can('{$permission}')): ?>{$body}<?php endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @forelse($items as $item) ... @empty ... @endforelse
|
||||||
|
$content = preg_replace_callback('/@forelse\s*\((.+?)\)\s*(.*?)\s*@empty\s*(.*?)\s*@endforelse/s', function ($matches) {
|
||||||
|
$loop = trim($matches[1]);
|
||||||
|
$body = $matches[2];
|
||||||
|
$empty = $matches[3];
|
||||||
|
return "<?php if (count({$loop}) > 0): ?><?php foreach ({$loop}): ?>{$body}<?php endforeach; ?><?php else: ?>{$empty}<?php endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @once ... @endonce (只执行一次)
|
||||||
|
$content = preg_replace_callback('/@once\s*(.*?)\s*@endonce/s', function ($matches) {
|
||||||
|
static $onceCounter = 0;
|
||||||
|
$onceCounter++;
|
||||||
|
$hash = md5($matches[0] . $onceCounter);
|
||||||
|
$body = $matches[1];
|
||||||
|
return "<?php if (!isset(\$__once_{$hash})): \$__once_{$hash} = true; ?>{$body}<?php endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @error('field') ... @enderror
|
||||||
|
$content = preg_replace_callback('/@error\s*\([\'"](.+?)[\'"]\)\s*(.*?)\s*@enderror/s', function ($matches) {
|
||||||
|
$field = $matches[1];
|
||||||
|
$body = $matches[2];
|
||||||
|
return "<?php if (function_exists('errors') && errors()->has('{$field}')): ?>{$body}<?php endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编译栈和推送 @push, @stack, @prepend
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function compileStacks(string $content): string
|
||||||
|
{
|
||||||
|
// @push('name') ... @endpush
|
||||||
|
$content = preg_replace_callback('/@push\s*\([\'"](.+?)[\'"]\)\s*(.*?)\s*@endpush/s', function ($matches) {
|
||||||
|
$name = $matches[1];
|
||||||
|
$body = $matches[2];
|
||||||
|
return "<?php \$__stacks['{$name}'][] = function() { ?>{$body}<?php }; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @prepend('name') ... @endprepend
|
||||||
|
$content = preg_replace_callback('/@prepend\s*\([\'"](.+?)[\'"]\)\s*(.*?)\s*@endprepend/s', function ($matches) {
|
||||||
|
$name = $matches[1];
|
||||||
|
$body = $matches[2];
|
||||||
|
return "<?php array_unshift(\$__stacks['{$name}'] ?? [], function() { ?>{$body}<?php }); ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @stack('name')
|
||||||
|
$content = preg_replace_callback('/@stack\s*\([\'"](.+?)[\'"]\)/', function ($matches) {
|
||||||
|
$name = $matches[1];
|
||||||
|
return "<?php if (isset(\$__stacks['{$name}'])): foreach (\$__stacks['{$name}'] as \$__stack): call_user_func(\$__stack); endforeach; endif; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编译表单辅助函数
|
||||||
|
* @csrf, @method, @old, @checked, @selected, @disabled
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function compileFormHelpers(string $content): string
|
||||||
|
{
|
||||||
|
// @csrf - CSRF token
|
||||||
|
$content = preg_replace('/@csrf/', '<?php echo function_exists("csrf_token") ? csrf_token() : ""; ?>', $content);
|
||||||
|
|
||||||
|
// @method('PUT') - HTTP method spoofing
|
||||||
|
$content = preg_replace_callback('/@method\s*\([\'"](.+?)[\'"]\)/', function ($matches) {
|
||||||
|
$method = strtoupper($matches[1]);
|
||||||
|
return "<input type=\"hidden\" name=\"_method\" value=\"{$method}\">";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @old('field', 'default')
|
||||||
|
$content = preg_replace_callback('/@old\s*\([\'"](.+?)[\'"]\s*(?:,\s*(.+?))?\)/', function ($matches) {
|
||||||
|
$field = $matches[1];
|
||||||
|
$default = $matches[2] ?? "''";
|
||||||
|
return "<?php echo function_exists('old') ? old('{$field}', {$default}) : {$default}; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @checked($condition)
|
||||||
|
$content = preg_replace_callback('/@checked\s*\((.+?)\)/', function ($matches) {
|
||||||
|
$condition = trim($matches[1]);
|
||||||
|
return "<?php echo ({$condition}) ? 'checked' : ''; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @selected($condition)
|
||||||
|
$content = preg_replace_callback('/@selected\s*\((.+?)\)/', function ($matches) {
|
||||||
|
$condition = trim($matches[1]);
|
||||||
|
return "<?php echo ({$condition}) ? 'selected' : ''; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @disabled($condition)
|
||||||
|
$content = preg_replace_callback('/@disabled\s*\((.+?)\)/', function ($matches) {
|
||||||
|
$condition = trim($matches[1]);
|
||||||
|
return "<?php echo ({$condition}) ? 'disabled' : ''; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @readonly($condition)
|
||||||
|
$content = preg_replace_callback('/@readonly\s*\((.+?)\)/', function ($matches) {
|
||||||
|
$condition = trim($matches[1]);
|
||||||
|
return "<?php echo ({$condition}) ? 'readonly' : ''; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// @required($condition)
|
||||||
|
$content = preg_replace_callback('/@required\s*\((.+?)\)/', function ($matches) {
|
||||||
|
$condition = trim($matches[1]);
|
||||||
|
return "<?php echo ({$condition}) ? 'required' : ''; ?>";
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编译原始 PHP @php ... @endphp
|
* 编译原始 PHP @php ... @endphp
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ class BladeView
|
|||||||
// 提取数据
|
// 提取数据
|
||||||
extract($this->data, EXTR_SKIP);
|
extract($this->data, EXTR_SKIP);
|
||||||
|
|
||||||
|
// 初始化栈和 section 数组
|
||||||
|
$__stacks = [];
|
||||||
|
$__sections = [];
|
||||||
|
|
||||||
// 开始输出缓冲
|
// 开始输出缓冲
|
||||||
ob_start();
|
ob_start();
|
||||||
|
|
||||||
|
|||||||
+39
-4
@@ -4,15 +4,50 @@
|
|||||||
|
|
||||||
## 功能特性
|
## 功能特性
|
||||||
|
|
||||||
|
### 基础功能
|
||||||
- ✅ 变量输出:`{{ $variable }}` 和 `{!! $variable !!}`
|
- ✅ 变量输出:`{{ $variable }}` 和 `{!! $variable !!}`
|
||||||
- ✅ 控制结构:`@if`, `@elseif`, `@else`, `@endif`
|
- ✅ JSON 输出:`@json($data)`
|
||||||
- ✅ 循环:`@foreach`, `@endforeach`, `@for`, `@endfor`, `@while`, `@endwhile`
|
- ✅ 控制结构:`@if`, `@elseif`, `@else`, `@endif`, `@unless`
|
||||||
- ✅ 布局继承:`@extends`, `@section`, `@yield`, `@endsection`
|
- ✅ 循环:`@foreach`, `@for`, `@while`, `@forelse` 及其结束指令
|
||||||
- ✅ 包含视图:`@include`
|
- ✅ Switch:`@switch`, `@case`, `@default`, `@endswitch`
|
||||||
|
- ✅ 布局继承:`@extends`, `@section`, `@yield`, `@endsection`, `@parent`
|
||||||
|
- ✅ 包含视图:`@include`, `@each`
|
||||||
- ✅ 注释:`{{-- comment --}}`
|
- ✅ 注释:`{{-- comment --}}`
|
||||||
- ✅ 原始 PHP:`@php ... @endphp`
|
- ✅ 原始 PHP:`@php ... @endphp`
|
||||||
- ✅ 编译缓存:自动缓存编译后的模板以提高性能
|
- ✅ 编译缓存:自动缓存编译后的模板以提高性能
|
||||||
|
|
||||||
|
### 条件判断语法糖
|
||||||
|
- ✅ `@isset` / `@endisset` - 检查变量是否存在
|
||||||
|
- ✅ `@empty` / `@endempty` - 检查变量是否为空
|
||||||
|
- ✅ `@auth` / `@endauth` - 检查用户是否已认证
|
||||||
|
- ✅ `@guest` / `@endguest` - 检查用户是否未认证
|
||||||
|
- ✅ `@hasSection` / `@endhasSection` - 检查 section 是否存在
|
||||||
|
- ✅ `@sectionMissing` / `@endsectionMissing` - 检查 section 是否缺失
|
||||||
|
- ✅ `@can` / `@endcan` - 权限检查
|
||||||
|
- ✅ `@cannot` / `@endcannot` - 反向权限检查
|
||||||
|
|
||||||
|
### 表单辅助
|
||||||
|
- ✅ `@csrf` - CSRF token
|
||||||
|
- ✅ `@method` - HTTP 方法伪装
|
||||||
|
- ✅ `@old` - 旧输入值
|
||||||
|
- ✅ `@checked` - 复选框选中状态
|
||||||
|
- ✅ `@selected` - 下拉框选中状态
|
||||||
|
- ✅ `@disabled` - 禁用状态
|
||||||
|
- ✅ `@readonly` - 只读状态
|
||||||
|
- ✅ `@required` - 必填状态
|
||||||
|
- ✅ `@error` / `@enderror` - 错误信息显示
|
||||||
|
|
||||||
|
### 栈和推送
|
||||||
|
- ✅ `@push` / `@endpush` - 推送到栈
|
||||||
|
- ✅ `@prepend` / `@endprepend` - 前置推送到栈
|
||||||
|
- ✅ `@stack` - 输出栈内容
|
||||||
|
|
||||||
|
### 其他语法糖
|
||||||
|
- ✅ `@once` / `@endonce` - 只执行一次
|
||||||
|
- ✅ `@lang` - 语言翻译
|
||||||
|
- ✅ `@class` - 条件类名
|
||||||
|
- ✅ `@style` - 条件样式
|
||||||
|
|
||||||
## 使用方法
|
## 使用方法
|
||||||
|
|
||||||
### 基本用法
|
### 基本用法
|
||||||
|
|||||||
@@ -0,0 +1,405 @@
|
|||||||
|
# Blade 语法糖参考手册
|
||||||
|
|
||||||
|
本文档列出了所有可用的 Blade 语法糖和指令。
|
||||||
|
|
||||||
|
## 变量输出
|
||||||
|
|
||||||
|
### 转义输出
|
||||||
|
```blade
|
||||||
|
{{ $variable }}
|
||||||
|
{{ $user->name }}
|
||||||
|
{{ $array['key'] }}
|
||||||
|
```
|
||||||
|
自动转义 HTML 特殊字符,防止 XSS 攻击。
|
||||||
|
|
||||||
|
### 原始输出
|
||||||
|
```blade
|
||||||
|
{!! $htmlContent !!}
|
||||||
|
```
|
||||||
|
不转义,直接输出原始 HTML(谨慎使用)。
|
||||||
|
|
||||||
|
### JSON 输出
|
||||||
|
```blade
|
||||||
|
@json($data)
|
||||||
|
```
|
||||||
|
将数据编码为 JSON 字符串输出。
|
||||||
|
|
||||||
|
## 控制结构
|
||||||
|
|
||||||
|
### 条件判断
|
||||||
|
|
||||||
|
#### @if / @elseif / @else / @endif
|
||||||
|
```blade
|
||||||
|
@if($user->isAdmin())
|
||||||
|
<p>管理员</p>
|
||||||
|
@elseif($user->isModerator())
|
||||||
|
<p>版主</p>
|
||||||
|
@else
|
||||||
|
<p>普通用户</p>
|
||||||
|
@endif
|
||||||
|
```
|
||||||
|
|
||||||
|
#### @unless / @endunless
|
||||||
|
```blade
|
||||||
|
@unless($user->isBanned())
|
||||||
|
<p>用户正常</p>
|
||||||
|
@endunless
|
||||||
|
```
|
||||||
|
等同于 `@if(!condition)`
|
||||||
|
|
||||||
|
#### @isset / @endisset
|
||||||
|
```blade
|
||||||
|
@isset($variable)
|
||||||
|
<p>{{ $variable }}</p>
|
||||||
|
@endisset
|
||||||
|
```
|
||||||
|
|
||||||
|
#### @empty / @endempty
|
||||||
|
```blade
|
||||||
|
@empty($items)
|
||||||
|
<p>列表为空</p>
|
||||||
|
@endempty
|
||||||
|
```
|
||||||
|
|
||||||
|
### 循环
|
||||||
|
|
||||||
|
#### @foreach / @endforeach
|
||||||
|
```blade
|
||||||
|
@foreach($users as $user)
|
||||||
|
<p>{{ $user->name }}</p>
|
||||||
|
@endforeach
|
||||||
|
```
|
||||||
|
|
||||||
|
#### @for / @endfor
|
||||||
|
```blade
|
||||||
|
@for($i = 0; $i < 10; $i++)
|
||||||
|
<p>Item {{ $i }}</p>
|
||||||
|
@endfor
|
||||||
|
```
|
||||||
|
|
||||||
|
#### @while / @endwhile
|
||||||
|
```blade
|
||||||
|
@while($condition)
|
||||||
|
<p>循环内容</p>
|
||||||
|
@endwhile
|
||||||
|
```
|
||||||
|
|
||||||
|
#### @forelse / @empty / @endforelse
|
||||||
|
```blade
|
||||||
|
@forelse($items as $item)
|
||||||
|
<p>{{ $item->name }}</p>
|
||||||
|
@empty
|
||||||
|
<p>没有项目</p>
|
||||||
|
@endforelse
|
||||||
|
```
|
||||||
|
|
||||||
|
#### @break 和 @continue
|
||||||
|
```blade
|
||||||
|
@foreach($items as $item)
|
||||||
|
@if($item->hidden)
|
||||||
|
@continue
|
||||||
|
@endif
|
||||||
|
<p>{{ $item->name }}</p>
|
||||||
|
@if($item->id > 100)
|
||||||
|
@break
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
```
|
||||||
|
|
||||||
|
### Switch 语句
|
||||||
|
|
||||||
|
```blade
|
||||||
|
@switch($status)
|
||||||
|
@case(1)
|
||||||
|
<p>待处理</p>
|
||||||
|
@break
|
||||||
|
@case(2)
|
||||||
|
<p>处理中</p>
|
||||||
|
@break
|
||||||
|
@default
|
||||||
|
<p>未知状态</p>
|
||||||
|
@endswitch
|
||||||
|
```
|
||||||
|
|
||||||
|
## 布局和继承
|
||||||
|
|
||||||
|
### @extends
|
||||||
|
```blade
|
||||||
|
@extends('layouts.app')
|
||||||
|
```
|
||||||
|
|
||||||
|
### @section / @endsection
|
||||||
|
```blade
|
||||||
|
@section('content')
|
||||||
|
<h1>页面内容</h1>
|
||||||
|
@endsection
|
||||||
|
```
|
||||||
|
|
||||||
|
### @yield
|
||||||
|
```blade
|
||||||
|
@yield('content')
|
||||||
|
@yield('title', '默认标题')
|
||||||
|
```
|
||||||
|
|
||||||
|
### @parent
|
||||||
|
在子视图的 section 中使用,输出父布局中对应 section 的内容。
|
||||||
|
|
||||||
|
### @hasSection / @endhasSection
|
||||||
|
```blade
|
||||||
|
@hasSection('sidebar')
|
||||||
|
@yield('sidebar')
|
||||||
|
@endhasSection
|
||||||
|
```
|
||||||
|
|
||||||
|
### @sectionMissing / @endsectionMissing
|
||||||
|
```blade
|
||||||
|
@sectionMissing('sidebar')
|
||||||
|
<p>没有侧边栏</p>
|
||||||
|
@endsectionMissing
|
||||||
|
```
|
||||||
|
|
||||||
|
## 包含和组件
|
||||||
|
|
||||||
|
### @include
|
||||||
|
```blade
|
||||||
|
@include('components.header')
|
||||||
|
@include('components.footer', ['year' => 2024])
|
||||||
|
```
|
||||||
|
|
||||||
|
### @each
|
||||||
|
```blade
|
||||||
|
@each('components.item', $items, 'item')
|
||||||
|
@each('components.item', $items, 'item', 'components.empty')
|
||||||
|
```
|
||||||
|
|
||||||
|
## 栈和推送
|
||||||
|
|
||||||
|
### @push / @endpush
|
||||||
|
```blade
|
||||||
|
@push('scripts')
|
||||||
|
<script src="/js/custom.js"></script>
|
||||||
|
@endpush
|
||||||
|
```
|
||||||
|
|
||||||
|
### @prepend / @endprepend
|
||||||
|
```blade
|
||||||
|
@prepend('scripts')
|
||||||
|
<script src="/js/jquery.js"></script>
|
||||||
|
@endprepend
|
||||||
|
```
|
||||||
|
|
||||||
|
### @stack
|
||||||
|
```blade
|
||||||
|
@stack('scripts')
|
||||||
|
```
|
||||||
|
|
||||||
|
## 表单辅助
|
||||||
|
|
||||||
|
### @csrf
|
||||||
|
```blade
|
||||||
|
<form method="POST">
|
||||||
|
@csrf
|
||||||
|
...
|
||||||
|
</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
### @method
|
||||||
|
```blade
|
||||||
|
<form method="POST">
|
||||||
|
@method('PUT')
|
||||||
|
...
|
||||||
|
</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
### @old
|
||||||
|
```blade
|
||||||
|
<input type="text" name="name" value="@old('name', '默认值')">
|
||||||
|
```
|
||||||
|
|
||||||
|
### @checked
|
||||||
|
```blade
|
||||||
|
<input type="checkbox" name="active" @checked($user->isActive())>
|
||||||
|
```
|
||||||
|
|
||||||
|
### @selected
|
||||||
|
```blade
|
||||||
|
<select name="status">
|
||||||
|
<option value="1" @selected($status == 1)>启用</option>
|
||||||
|
<option value="0" @selected($status == 0)>禁用</option>
|
||||||
|
</select>
|
||||||
|
```
|
||||||
|
|
||||||
|
### @disabled
|
||||||
|
```blade
|
||||||
|
<input type="text" @disabled($readonly)>
|
||||||
|
```
|
||||||
|
|
||||||
|
### @readonly
|
||||||
|
```blade
|
||||||
|
<input type="text" @readonly($readonly)>
|
||||||
|
```
|
||||||
|
|
||||||
|
### @required
|
||||||
|
```blade
|
||||||
|
<input type="text" @required($isRequired)>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 权限和认证
|
||||||
|
|
||||||
|
### @auth / @endauth
|
||||||
|
```blade
|
||||||
|
@auth
|
||||||
|
<p>欢迎,{{ auth()->user()->name }}</p>
|
||||||
|
@endauth
|
||||||
|
|
||||||
|
@auth('admin')
|
||||||
|
<p>管理员面板</p>
|
||||||
|
@endauth
|
||||||
|
```
|
||||||
|
|
||||||
|
### @guest / @endguest
|
||||||
|
```blade
|
||||||
|
@guest
|
||||||
|
<a href="/login">登录</a>
|
||||||
|
@endguest
|
||||||
|
```
|
||||||
|
|
||||||
|
### @can / @endcan
|
||||||
|
```blade
|
||||||
|
@can('edit', $post)
|
||||||
|
<a href="/posts/{{ $post->id }}/edit">编辑</a>
|
||||||
|
@endcan
|
||||||
|
```
|
||||||
|
|
||||||
|
### @cannot / @endcannot
|
||||||
|
```blade
|
||||||
|
@cannot('edit', $post)
|
||||||
|
<p>您没有编辑权限</p>
|
||||||
|
@endcannot
|
||||||
|
```
|
||||||
|
|
||||||
|
## 错误处理
|
||||||
|
|
||||||
|
### @error / @enderror
|
||||||
|
```blade
|
||||||
|
@error('email')
|
||||||
|
<p class="error">{{ $message }}</p>
|
||||||
|
@enderror
|
||||||
|
```
|
||||||
|
|
||||||
|
## 其他语法糖
|
||||||
|
|
||||||
|
### @once / @endonce
|
||||||
|
```blade
|
||||||
|
@once
|
||||||
|
<script src="/js/unique.js"></script>
|
||||||
|
@endonce
|
||||||
|
```
|
||||||
|
确保内容只输出一次。
|
||||||
|
|
||||||
|
### @lang
|
||||||
|
```blade
|
||||||
|
@lang('messages.welcome')
|
||||||
|
@lang('messages.greeting', ['name' => $user->name])
|
||||||
|
```
|
||||||
|
|
||||||
|
### @class
|
||||||
|
```blade
|
||||||
|
<div @class(['active' => $isActive, 'disabled' => $isDisabled])>
|
||||||
|
```
|
||||||
|
|
||||||
|
### @style
|
||||||
|
```blade
|
||||||
|
<div @style(['color' => 'red', 'font-size' => '14px'])>
|
||||||
|
```
|
||||||
|
|
||||||
|
### @php / @endphp
|
||||||
|
```blade
|
||||||
|
@php
|
||||||
|
$count = count($items);
|
||||||
|
$total = array_sum($prices);
|
||||||
|
@endphp
|
||||||
|
```
|
||||||
|
|
||||||
|
### 注释
|
||||||
|
```blade
|
||||||
|
{{-- 这是注释,不会输出到 HTML --}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
### 完整的页面模板
|
||||||
|
```blade
|
||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('title', '用户资料')
|
||||||
|
|
||||||
|
@push('styles')
|
||||||
|
<link rel="stylesheet" href="/css/profile.css">
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
@auth
|
||||||
|
<h1>欢迎,{{ auth()->user()->name }}</h1>
|
||||||
|
|
||||||
|
@if($user->isAdmin())
|
||||||
|
<p class="badge">管理员</p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<form method="POST" action="/profile">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<input type="text" name="name" value="@old('name', $user->name)">
|
||||||
|
@error('name')
|
||||||
|
<p class="error">{{ $message }}</p>
|
||||||
|
@enderror
|
||||||
|
|
||||||
|
<button type="submit" @disabled($readonly)>保存</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<h2>文章列表</h2>
|
||||||
|
@forelse($posts as $post)
|
||||||
|
<article>
|
||||||
|
<h3>{{ $post->title }}</h3>
|
||||||
|
<p>{{ $post->content }}</p>
|
||||||
|
</article>
|
||||||
|
@empty
|
||||||
|
<p>暂无文章</p>
|
||||||
|
@endforelse
|
||||||
|
@else
|
||||||
|
<p>请先登录</p>
|
||||||
|
@endauth
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script src="/js/profile.js"></script>
|
||||||
|
@endpush
|
||||||
|
```
|
||||||
|
|
||||||
|
### 布局文件
|
||||||
|
```blade
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>@yield('title', '默认标题')</title>
|
||||||
|
@stack('styles')
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
@include('components.header')
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
@yield('content')
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
@include('components.footer')
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
@stack('scripts')
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
Reference in New Issue
Block a user