前端html用到花括号与PHP语法标签冲突怎么解决

创建时间:2019-11-09 15:46发布者:吃不胖点击次数:3316
例: <div class="particles-rect bg-primary d-none d-md-block" data-plugin-float-element data-plugin-options="{'startPos': 'top', 'speed': 4, 'transition': true}"></div>

因为div里绑定了JSON字符串属性,存在花括号,PHP当成变量解析然后报错。

前端用的插件是这种写法,应该很难在前端这边做修改,请问怎么解决。
回答 我也遇到这个问题(0)
由DouPHP官方技术于2019-11-09 19:19回答
以下信息来自帮助中心:“DouPHP模板语法概述”
# DouPHP DouView 模板引擎使用文档 > 本文档对应 DouPHP 自研编译式模板引擎 **DouView 1.0**(实现位于 `core/web/template`)。 > 引擎内置 DouPHP 专属的 `{url}`、`{list}`、`{category}` 数据标签,便于在模板中生成路由链接与按模块取数。 ## 基本语法 ### 定界符 默认左定界符 `{`、右定界符 `}`,可在引擎实例上配置(`leftDelimiter` / `rightDelimiter`)。 ### 模板变量输出 ``` {$变量名} ``` 示例:`{$title}`、`{$user.name}`、`{$arr[0]}`、`{$article.content nofilter}` 变量支持属性访问、数组下标、修饰器链、`nofilter` 标志与三元表达式,详见后续章节。 ### 注释 ``` {* 这是注释内容,编译后不输出 *} ``` 注释可跨行,编译期整体丢弃(仅保留位置用于吞行首换行)。 ### 保留定界符 ``` {ldelim} - 输出左定界符 { {rdelim} - 输出右定界符 } ``` 当需要在模板中输出字面 `{` / `}`(如 JS 对象字面量)时使用;更推荐用 `{literal}` 包裹整段。 ### 原样输出块 literal ``` {literal} if (a > 0) { console.log("ok"); } {/literal} ``` `{literal}...{/literal}` 块内内容原样输出,**不做任何模板解析**,用于保护 JavaScript / CSS 中含大量 `{` `}` 的代码段。 ## 变量与表达式 ### 属性 / 下标访问 | 写法 | 含义 | | ------------------ | ---------------------------------- | | `{$user.name}` | 等价 `$user['name']`(点号取键) | | `{$user.$field}` | 动态键名,等价 `$user[$field]` | | `{$arr[0]}` | 数字下标 | | `{$arr[$i]}` | 变量下标 | | `{$arr[$i.j]}` | 变量路径下标(编译为表达式) | > 对象成员访问 `->` 在模板中**不允许**(编译期报错),请控制器侧转数组后注入。 ### 双引号字符串插值 双引号字符串中可直接嵌入变量,引擎自动展开为拼接: ``` {assign var="greeting" value="你好,$name"} {* 或反引号形式 *} {assign var="greeting" value="你好,`$user.name`"} ``` 单引号字符串不做插值,按字面输出。 ### 算术运算 变量基串支持顶层算术运算(`+ - * / %`): ``` {$price * $count} {$total + 1} {$discount % 10} ``` ### 三元表达式 ``` {$user ? '已登录' : '游客'} {$count > 0 ? $count : '空'} ``` 条件部分可为变量或简单比较(`== != <> >= <= > <`),真/假分支为值表达式。 ### nofilter 标志(关闭自动转义) ``` {$article.content nofilter} ``` 当引擎开启全局自动 HTML 转义时,追加裸词 `nofilter` 可对该输出关闭转义,原样输出 HTML。`{url}` 标签同样支持 `nofilter`。 ## 变量修饰器 修饰器用于对变量进行格式化处理,使用管道符 `|` 分隔,参数用冒号 `:` 传递。 DouView 内置 **20 个**标准修饰器(注册于 `filter/StandardFilters.php`): ### 1. truncate — 截断字符串(UTF-8 安全) ``` {$变量|truncate:长度:省略符:是否断词:是否中间截断} ``` - 长度:截断后最大字符数(默认 80,按 UTF-8 字符计) - 省略符:默认 `...` - 是否断词:`false` 不在词中间断(默认),`true` 允许 - 是否中间截断:`false` 从末尾截(默认),`true` 从中间截 ``` {$content|truncate:100} {$content|truncate:50:"...更多":false} ``` ### 2. escape — 转义输出 ``` {$变量|escape:转义类型:字符集} ``` 转义类型(默认 `html`): - `html` — HTML 转义(`htmlspecialchars`,ENT_QUOTES) - `htmlall` — 所有 HTML 实体转义(`htmlentities`) - `url` — URL 编码(`rawurlencode`) - `urlpathinfo` — URL 路径编码(保留斜杠) - `quotes` — 转义单引号 - `hex` / `hexentity` / `decentity` — 十六进制 / 十六进制实体 / 十进制实体编码 - `javascript` — JavaScript 字符串转义 - `mail` — 邮箱地址保护显示(`@` → `[AT]`,`.` → `[DOT]`) - `nonstd` — 非标准字符(ASCII ≥ 126)转义为实体 ``` {$user_input|escape:"html"} {$url|escape:"url"} ``` > 若修饰器链中已含 `|escape`(或 `|escape:"html"`),则该输出**不再追加全局自动转义**,避免双重转义。 ### 3. nl2br — 换行符转 `
` ``` {$变量|nl2br} ``` ### 4. strip_tags — 去除 HTML 标签 ``` {$变量|strip_tags:是否替换为空格} ``` - 是否替换为空格:`true` 替换为空格(默认),`false` 直接删除 ``` {$html_content|strip_tags} {$html_content|strip_tags:false} ``` ### 5. capitalize — 首字母大写 ``` {$变量|capitalize:是否数字大写} ``` - 是否数字大写:`true` 数字开头的词也大写(默认 `false`) ``` {$title|capitalize} ``` ### 6. cat — 字符串连接 ``` {$变量|cat:"连接字符串"} ``` ``` {$name|cat:"先生"} ``` ### 7. count_characters — 统计字符数 ``` {$变量|count_characters:是否包含空格} ``` - 是否包含空格:`true` 含空格(默认 `false`) ### 8. count_paragraphs — 统计段落数 ``` {$变量|count_paragraphs} ``` ### 9. count_sentences — 统计句子数 ``` {$变量|count_sentences} ``` ### 10. count_words — 统计单词数 ``` {$变量|count_words} ``` ### 11. date_format — 日期格式化 ``` {$日期变量|date_format:格式字符串:默认日期} ``` 使用 `strftime` 占位符(PHP 8.1+ 自动映射为 `date()` 等价格式): - `%Y` 四位年份 / `%y` 两位年份 - `%m` 月份(01-12)/ `%d` 日期(01-31)/ `%e` 日期(不补零) - `%H` 24 小时制 / `%I` 12 小时制 / `%M` 分钟 / `%S` 秒 - `%a` 星期缩写 / `%A` 星期全称 / `%b` 月份缩写 / `%B` 月份全称 - `%p` AM/PM / `%R` `H:i` / `%T` `H:i:s` ``` {$timestamp|date_format:"%Y-%m-%d %H:%M:%S"} {$create_time|date_format:"%Y年%m月%d日"} ``` 输入可为时间戳、`YYYYMMDDHHMMSS` 串或 `strtotime` 可解析字符串。 ### 12. default — 默认值 ``` {$变量|default:"默认值"} ``` 当变量未设置或为空字符串时回退默认值。 ### 13. indent — 每行缩进 ``` {$变量|indent:缩进数:缩进字符} ``` - 缩进数:每行缩进字符数(默认 4) - 缩进字符:默认空格 ``` {$code|indent:8:" "} ``` ### 14. string_format — sprintf 格式化 ``` {$变量|string_format:"格式"} ``` ``` {$price|string_format:"%.2f"} ``` ### 15. strip — 多空白压缩 ``` {$变量|strip:替换字符} ``` 把连续空白压缩为单个字符(默认空格)。 ### 16. lower — 转小写 ``` {$变量|lower} ``` ### 17. upper — 转大写 ``` {$变量|upper} ``` ### 18. replace — 字符串替换 ``` {$变量|replace:"查找字符串":"替换字符串"} ``` ``` {$content|replace:"旧文本":"新文本"} ``` ### 19. spacify — 字符间插入分隔 ``` {$变量|spacify:分隔字符} ``` ``` {$word|spacify:"-"} ``` ### 20. wordwrap — 自动换行 ``` {$变量|wordwrap:行长度:换行符:是否截断单词} ``` - 行长度:默认 80 - 换行符:默认 `\n` - 是否截断单词:`true` 在词中间换行(默认 `false`) ### 修饰器链式组合 ``` {$content|truncate:100|nl2br|strip_tags} {$title|escape:"html"|default:"默认标题"} ``` ## 控制结构 控制结构包含条件判断与循环。循环标签除通用的 `{foreach}` 外,还有 DouPHP 专属的 `{list}` / `{category}`——后两者自动从 Portal 取数后按与 `{foreach}` 相同的方式循环,共享 `item` / `key` / `name` / `offset` 参数、`@property` 循环属性、`{break}` / `{continue}` 与空态分支。 ### if 条件判断 ``` {if $条件} ... {elseif $其他条件} ... {else} ... {/if} ``` #### 比较与逻辑运算符 | 符号形式 | 等价词 | 含义 | | -------------- | ---------------- | -------- | | `==` | `eq` | 等于 | | `!=`、`<>` | `ne` / `neq` | 不等于 | | `===` | — | 全等于 | | `!==` | — | 不全等于 | | `>` | `gt` | 大于 | | `<` | `lt` | 小于 | | `>=` | `ge` / `gte` | 大于等于 | | `<=` | `le` / `lte` | 小于等于 | | `&&` | `and` | 与 | | `\|\|` | `or` | 或 | | `!` | `not` | 非 | | `%` | `mod` | 取模 | 同时支持位运算 `& | ^ ~ << >>` 和算术 `+ - * /`,并允许括号分组。 ``` {if $count > 0 && $user.logged_in} {if $status eq 1} {if ($a + $b) % 2 eq 0} ``` ### foreach 循环 ``` {foreach from=$数组变量 item=值变量 [key=键变量] [name=循环名称] [limit=数量] [offset=起始位置]} ... {foreachelse} 数组为空时显示 {/foreach} ``` #### 参数说明 | 参数 | 必需 | 说明 | | ---------- | ---- | ----------------------------------------------------------------- | | `from` | 是 | 待遍历的数组或对象 | | `item` | 是 | 当前元素的值变量名(字面标识符) | | `key` | 否 | 当前元素的键变量名 | | `name` | 否 | 循环名称(用于 `$douview.foreach.NAME.*` 访问;省略时自动生成) | | `limit` | 否 | 最多循环次数(取数后切片,类似 `array_slice`) | | `offset` | 否 | 跳过的元素数量(从 0 开始) | #### 循环属性(@property 语法,推荐) 无需声明 `name`,直接在 `item` 变量后用 `@` 前缀访问循环元数据: | 属性 | 说明 | 示例输出 | | -------------- | ------------------------- | ------------ | | `@iteration` | 当前迭代序号(从 1 开始) | 1, 2, 3... | | `@index` | 当前索引(从 0 开始) | 0, 1, 2... | | `@total` | 循环总数 | 5 | | `@first` | 是否为第一个元素 | true / false | | `@last` | 是否为最后一个元素 | true / false | | `@show` | 循环是否有数据 | true / false | ``` {foreach from=$articles item=article} {if $article@first}【最新】{/if} {$article@iteration}. {$article.title} {if $article@last}(共{$article@total}篇){/if} {/foreach} ``` #### limit / offset 分页 ``` {* 只显示前 10 条 *} {foreach from=$news item=news limit=10}
  • {$news.title}
  • {/foreach} {* 跳过前 5 条,显示接下来的 10 条 *} {foreach from=$news item=news limit=10 offset=5}
  • {$news.title}
  • {/foreach} ``` #### 命名循环的 $douview.foreach.NAME.* 属性 声明 `name` 后可用 `$douview.foreach.NAME.*` 访问循环属性,支持 `index` / `first` / `last` / `show`: ``` {foreach from=$users item=user name=user_list} {$douview.foreach.user_list.index}: {$user.name} {/foreach} ``` > 推荐优先使用 `@property` 语法(`{$user@index}` 等),更简洁且 `iteration` / `total` 仅在该语法下可靠取值。 ### — 模块内容列表 按模块白名单自动从 Portal 取数,循环输出。仅对在配置 `module.column_module` / `module.single_module` 中声明且可列表的模块生效;模块未启用或不可列表时返回空数组,走 `{listelse}` 分支。 ``` {list module="模块名" item=值变量 [catId=分类ID] [limit=数量] [sort=排序] [excerpt=截字长度] [key=键变量] [name=循环名称] [offset=跳过数]} ... {listelse} 无数据时显示 {/list} ``` #### 参数说明 | 参数 | 说明 | | ------------------------------- | ---------------------------------------------------------------------- | | `module` | 模块名(**必须为字面标识符**,禁止运行时变量,防注入) | | `item` | 当前元素值变量名 | | `catId` | 分类 ID(仅栏目型模块);`ALL` / 空 = 不按分类过滤;其它值含子孙分类 | | `limit` | 取数条数(走 SQL `LIMIT`) | | `sort` | 排序,仅接受 `字段名 ASC\|DESC` 逗号序列,否则忽略走默认 `id DESC` | | `excerpt` | `description` 字段截字长度(默认 200,≤0 不截) | | `key` / `name` / `offset` | 同 `{foreach}`;`offset` 在取数后切片 | ``` {* 文章列表,取最新 10 条 *} {list module="article" limit=10 item=article}
  • {$article@iteration}. {$article.title|truncate:50}
  • {listelse}
  • 暂无文章
  • {/list} {* 指定分类下产品,跳过前 5 条取 12 条 *} {list module="product" catId=$cat_id limit=12 offset=5 item=product}
    {$product.name}
    {/list} ``` > 同一请求内相同 `module + props` 的 `{list}` 块结果会被缓存,重复块不重复查询。 ### — 分类树 仅栏目型模块(`module.column_module`)可用,输出分类嵌套树。支持两种模式: #### 模式一:纯分类树 ``` {category module="模块名" item=节点变量 [cur=当前分类ID] [key=键] [name=名称] [offset=跳过数]} ... {categoryelse} 无分类时显示 {/category} ``` #### 模式二:分类树 + 每类内容 ``` {category module="模块名" with="items" [perCat=每类条数] [children=是否含子节点] [excerpt=截字长度] item=节点变量} {* 节点结构:category_id / name / list(内容行数组)/ child(子节点数组或空) *} ... {categoryelse} 无分类时显示 {/category} ``` #### 参数说明 | 参数 | 说明 | | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | | `module` | 模块名(字面标识符) | | `with` | 仅接受字面量 `"items"`,启用「分类树 + 每类内容」模式 | | `perCat` | 每个分类附带的内容条数(默认 5,仅 `with="items"` 时生效) | | `children` | 是否递归挂载子节点(仅 `with="items"` 时生效) | | `cur` | 当前激活分类 ID(仅纯树模式生效;引擎据此给 id 匹配的节点打 `cur=true` 标记,便于模板高亮当前分类。`with="items"` 模式忽略此参数) | | `excerpt` | 内容行 `description` 截字长度(默认 200) | | `item` / `key` / `name` / `offset` | 同 `{foreach}` | ``` {* 纯分类树:cur=$cat_id 让匹配节点带上 cur=true 标记,模板直接据此高亮 *} {category module="article" cur=$cat_id item=cat} {$cat.cat_name} {categoryelse}
  • 暂无分类
  • {/category} {* 分类树 + 每类 5 条内容 *} {category module="article" with="items" perCat=5 item=cat}

    {$cat.cat_name}

      {foreach from=$cat.list item=row}
    • {$row.title}
    • {/foreach}
    {/category} ``` ### 与 可在 `{foreach}` / `{list}` / `{category}` 循环内使用,控制循环流程: ``` {foreach from=$list item=item} {if $item.status eq 0} {continue} {* 跳过未发布项 *} {/if} {if $item@iteration > 10} {break} {* 只显示前 10 条 *} {/if}

    {$item.title}

    {/foreach} ``` ## 内置标签 ### include — 包含子模板 ``` {include file="模板文件名" [变量1="值1" 变量2=$值2] [assign="变量名"]} ``` - `file`:要包含的模板资源名(必需) - `assign`:将包含结果赋值给指定变量而非直接输出(可选) - 其他属性:作为局部变量传递给子模板 ``` {include file="header.tpl" title=$page_title} {include file="inc/pager.tpl"} {include file="box.tpl" box=$box assign="box_html"} ``` > 模板文件扩展名白名单:`.tpl` / `.htm` / `.html` / `.dwt`。资源名禁止包含 `..` 或绝对路径,防止路径穿越。 ### — 生成路由 URL 把点分路由键编译为 `route()` 调用,是 DouPHP 模板生成链接的标准方式。 ``` {url link="路由键" [params=$数组] [page=$页码] [options=$选项] [nofilter] k1=$v1 k2=$v2 ...} ``` #### 保留属性 | 属性 | 说明 | | ------------ | ---------------------------------------------------------------- | | `link` | 点分路由键,如 `'article.show'`、`'admin.user.edit'`(必需) | | `params` | 路由参数数组(可选,与内联属性合并) | | `page` | 分页页码,并入 `options.page` | | `options` | 路由选项数组(如 `query`、`lang`) | | `nofilter` | 裸词标志,关闭自动 HTML 转义 | 除上述保留属性外,**其他内联属性自动并入 `params`**,作为路由参数。 ``` {* 基础用法 *} 文章 {* 带路径/查询参数 *} {$article.title} 编辑 {* 带分页 *} 订阅 {* 裸词参数值(非变量)*} 今日 ``` ### assign — 变量赋值 ``` {assign var="变量名" value="变量值"} ``` ``` {assign var="page_title" value="首页"} {assign var="user_level" value=$user.level} ``` ### strip — 压缩空白 ``` {strip}
    内容
    {/strip} ``` 去除块内 HTML 标签间的空白字符,压缩输出。常用于优化页面体积。 ### php — 禁用 ``` {php}...{/php} {* 编译期报错:php tags not permitted *} ``` DouView **禁止**在模板中嵌入原生 PHP 代码。模板文本中出现的 ``、`language=php` 也会被自动转义为字面输出,杜绝注入。 ## 内置变量 ### $douview 系统变量 ``` {$douview.now} 当前时间戳(time()) {$douview.template} 当前模板资源名 {$douview.version} 引擎版本号('1.0') {$douview.ldelim} 左定界符 {$douview.rdelim} 右定界符 ``` > `$douview.` 是 DouView 的规范命名,与应用变量命名空间(如模板中的 `$dou.auth`、`$dou.user`)物理隔离,互不冲突;`$smarty.` 作为兼容别名同等可用(如 `$smarty.now`、`$smarty.foreach.NAME.first`),旧模板无需改动。 ### foreach 循环变量 推荐使用 `@property` 语法(见 [foreach 循环](#foreach-循环));命名循环亦可用 `$douview.foreach.NAME.*`,支持 `index` / `first` / `last` / `show`。 ## 预过滤器(Prefilter) DouView 在编译前对模板源执行预过滤,前台 / 后台行为不同: ### 前台(FrontPrefilter) - 主题静态资源相对路径(`images/`、`css/`、`js/`)烘焙为绝对主题路径 - 移除旧式 `` 声明 - **还原 HTML 注释包裹的标签**:`` → `{tag}` ### 后台(AdminPrefilter) - 后台静态资源(`css/`、`js/`、`images/`)前缀 `{$admin_url}view/` - 裸 `index.php?route=` 链接绝对化(仅 `href` / `action` 属性) - 同样还原 `` → `{tag}` ### HTML 注释包裹标签 由于预过滤器会把 `` 还原为 `{标签}`,模板中可用 HTML 注释包裹模板标签,使模板在未渲染时(如直接用浏览器打开)仍保持合法 HTML 结构: ```html
    • {$item.title}
    ``` 这是 DouPHP 模板的常见写法,注释内的标签会被正常编译执行。 ## 自动转义与安全 ### 全局自动 HTML 转义 引擎可开启 `escapeHtml` 开关(`DouView::setEscapeHtml(true)`)。开启后: - 所有 `{$var}` 输出自动经 `htmlspecialchars(..., ENT_QUOTES, 'UTF-8')` 转义 - 已带 `|escape` 修饰器的输出**不重复转义** - 追加 `nofilter` 标志的输出**不转义**(如 `{$html nofilter}`) ### 安全约束 - `{php}` 标签编译期拒绝;文本中的 PHP 起止符自动转义 - 对象成员访问 `->` 禁止 - `{list}` / `{category}` 的 `module` 必须为字面标识符,禁止运行时变量 - `{list}` 的 `sort` 走白名单校验,仅接受 `字段 ASC|DESC` 序列,防 ORDER BY 注入 - `include` 的模板资源名禁止 `..`、绝对路径,扩展名须在白名单 - `{if}` 条件中禁止函数调用与变量函数调用 ## 注意事项 1. 所有模板标签必须正确闭合(`{if}`/`{/if}`、`{foreach}`/`{/foreach}` 等)。 2. 变量名区分大小写;`item` / `key` / `name` / `module` 必须为字面标识符,不可为表达式。 3. 修饰器参数使用冒号 `:` 分隔,字符串参数需加引号。 4. 修改主题或升级引擎后,编译缓存会按 `COMPILE_REVISION` 自动失效重编。 5. 模板文件扩展名限 `.tpl` / `.htm` / `.html` / `.dwt`。 ## 完整示例 ```html {$title|escape:"html"|default:"默认标题"} {include file="header.tpl" title=$page_title}

    {$title|capitalize}

    {if $user.logged_in}

    欢迎回来,{$user.name|escape:"html"}!

    {else}

    请先登录

    {/if}

    文章列表

    {list module="article" catId=$cat_id limit=10 item=article name=art}

    {$article@iteration}. {$article.title|truncate:50}

    {$article.description|truncate:200|nl2br}

    发布时间:{$article.publish_time|date_format:"%Y-%m-%d %H:%M"} 查看详情 {if $article@last}(共{$article@total}篇){/if}

    {listelse}

    暂无文章

    {/list}

    分类导航

      {category module="article" cur=$cat_id item=cat} {$cat.cat_name} {categoryelse}
    • 暂无分类
    • {/category}
    {include file="footer.tpl"} ```
    有用(0) 没用(0)
    由海誉_荷兰豆于2019-12-21 12:06回答
    如果使用开发编辑器时防止被代码整理修改代码,可以这样修改
    &lt;pre class=&quot;prettyprint lang-js&quot;&gt;
    {literal}
    &amp;lt;script language=&quot;JavaScript&quot;&amp;gt;
    这里面是JS代码
    &amp;lt;/script&amp;gt;&lt;/pre&gt;
    {/literal}
    有用(0) 没用(0)