jQuery 選擇器全解析與正則實戰:打造一個 Smarty 風格模板引擎
本文前半部系統梳理 jQuery 核心選擇器(基礎、層次、過濾、表單、屬性),後半部結合正則表達式實現一個輕量級模板引擎,展示前端模板編譯的核心思想。
第一部分:jQuery 選擇器速查表
1. 基礎選擇器
| 選擇器 | 說明 | 示例 |
#id | ID 選擇(唯一) | $("#header") |
element | 標籤選擇 | $("div") |
.class | 類選擇 | $(".highlight") |
* | 全選(慎用,性能差) | $("form *") |
sel1,sel2,selN | 群組選擇 | $(".red,.green") |
2. 層次選擇器
| 選擇器 | 關係 | 示例 |
ancestor descendant | 後代(子孫皆含) | $("div span") |
parent > child | 直接子元素 | $("ul > li") |
prev + next | 緊鄰的下一個同輩 | $("label + input") |
prev ~ siblings | 其後所有同輩 | $("h2 ~ p") |
3. 過濾選擇器(以冒號開頭)
| 選擇器 | 功能 |
:first / :last | 首個/最後一個匹配元素 |
:eq(index) | 指定索引(0 基) |
:contains(text) | 包含指定文本 |
:has(selector) | 包含指定後代元素 |
:hidden / :visible | 不可見/可見元素 |
:first-child / :last-child | 各父容器下的首個/末個子元素 |
4. 表單選擇器
| 選擇器 | 匹配類型 |
:input | 所有表單元素(input/select/textarea/button) |
:text / :password | 文本框 / 密碼框 |
:radio / :checkbox | 單選 / 復選框 |
:submit / :image / :button | 提交按鈕 / 圖像按鈕 / 普通按鈕 |
:checked / :selected | 被選中的 radio/checkbox / option |
:enabled / :disabled | 啟用 / 禁用狀態 |
5. 屬性選擇器
| 選擇器 | 匹配規則 |
[attr] | 擁有該屬性 |
[attr=value] | 屬性值精確等於 |
[attr!=value] | 屬性值不等於 |
[attr^=value] | 屬性值以 value 開頭 |
[attr$=value] | 屬性值以 value 結尾 |
[attr*=value] | 屬性值包含 value |
第二部分:正則驅動的輕量模板引擎(Smarty 風格)
核心思路:模板文件 → 正則編譯 → PHP 代碼 → 執行輸出。使用 {#$var#} 作為變量標記,避免與原生 {$var} 衝突。
目錄結構
project/
├── template.class.php # 引擎核心類
├── index.php # 測試入口
├── source/ # 模板源文件目錄
│ └── index.html
└── compiled/ # 編譯緩存目錄(需寫入權限)
template.class.php 核心代碼
<?php
class Template {
private $tplDir, $cmpDir, $leftTag = '{#', $rightTag = '#}';
private $currentTpl = '', $outputHtml = '', $varPool = [];
public function __construct($tplDir, $cmpDir, $leftTag = null, $rightTag = null) {
$this->tplDir = rtrim($tplDir, '/') . '/';
$this->cmpDir = rtrim($cmpDir, '/') . '/';
if ($leftTag) $this->leftTag = $leftTag;
if ($rightTag) $this->rightTag = $rightTag;
}
// 註冊模板變量
public function assign($key, $val) { $this->varPool[$key] = $val; }
// 讀取模板源文件
public function load($name, $ext = '.html') {
$this->currentTpl = $name;
$path = $this->tplDir . $name . $ext;
if (!is_file($path)) throw new Exception("模板不存在:$path");
$this->outputHtml = file_get_contents($path);
}
// 核心編譯:正則替換標記為 PHP 代碼
public function compile($name = null, $ext = '.html') {
$name = $name ?: $this->currentTpl;
// 匹配 {#$var#} → getVar('var'); ?>
$pattern = '/' . preg_quote($this->leftTag, '/') . '\$(\w+)' . preg_quote($this->rightTag, '/') . '/';
$this->outputHtml = preg_replace($pattern, '<?php echo $this->getVar(\'$1\'); ?>', $this->outputHtml);
// 寫入編譯緩存(以 md5 命名避免衝突)
$cmpFile = $this->cmpDir . md5($name) . $ext;
file_put_contents($cmpFile, $this->outputHtml);
}
// 輸出渲染
public function display($name = null, $ext = '.html') {
$name = $name ?: $this->currentTpl;
$cmpFile = $this->cmpDir . md5($name) . $ext;
if (!is_file($cmpFile)) $this->compile($name, $ext);
include $cmpFile; // 直接執行編譯後的 PHP
}
protected function getVar($key) { return $this->varPool[$key] ?? ''; }
}
source/index.html 模板示例
<!DOCTYPE html>
<html><head><title>{#$pagetitle#}</title></head>
<body>
<h1>歡迎,{#$test#}</h1>
<p>當前時間:{#$now#}</p>
</body></html>
index.php 入口調用
<?php
require_once 'template.class.php';
$base = str_replace('\\', '/', dirname(__FILE__));
$tpl = new Template($base.'/source', $base.'/compiled');
$tpl->assign('pagetitle', '山寨版 Smarty 測試');
$tpl->assign('test', 'iMooc 女神');
$tpl->assign('now', date('Y-m-d H:i:s'));
$tpl->load('index');
$tpl->display();
關鍵技術點總結
- 正則邊界控制:使用
preg_quote 轉義自定義標記,防止特殊字符破壞正則;
- 子模式引用:
$1 對應 (\w+) 捕獲的變量名;
- 編譯緩存:避免重複正則解析,生產環境只需檢查源文件修改時間決定是否重編譯;
- 安全性:輸出時建議配合
htmlspecialchars() 防 XSS,引擎可擴展 {#$var|escape#} 過濾器語法。
這個微型引擎雖簡單,卻完整展示了「模板編譯 → PHP 執行」的核心機制,是理解 Smarty、Blade、Twig 等主流引擎原理的最佳切入點。