amp-bind
描述
允许元素通过数据绑定和简单的类 JS 表达式来响应用户操作或数据更改进行变异。
所需的脚本
<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>
用法
amp-bind
组件允许在 AMP 页面上实现自定义的有状态交互。
为了提高性能并避免意外的内容跳跃风险,amp-bind
不会在页面加载时评估表达式。这意味着视觉元素应具有默认状态,而不是依赖 amp-bind
进行初始渲染。
amp-bind
有三个主要概念
- 状态:文档范围内的可变 JSON 状态。状态变量会响应用户操作进行更新。
amp-bind
不会在页面加载时评估表达式。视觉元素应定义其默认“状态”,而不是依赖amp-bind
进行初始渲染。 - 表达式:类 JavaScript 表达式,可以引用状态。
- 绑定:特殊属性,通过表达式将元素的属性链接到状态。通过将属性括在方括号中(以
[property]
的形式)来绑定属性。
未声明状态的示例
你好,世界
<p [text]="'Hello ' + foo">Hello World</p> <button on="tap:AMP.setState({foo: 'Interactivity'})"> Say "Hello Interactivity" </button>
在上面的示例中
- 状态开始时为空。
- 它在
<p>
元素上只有一个绑定到[text]
的绑定,即节点的文本内容。 [text]
值包含表达式,'Hello ' + foo
。此表达式将字符串“Hello ”和状态变量 foo 的值连接起来。
当用户点击/单击按钮时
- 它会触发
tap
事件。 tap
事件会调用AMP.setState()
方法。AMP.setState()
方法会将foo
状态变量设置为Interactivity
的值。- 状态不再为空,因此页面会将绑定属性更新到其状态。
AMP.setState()
可能会设置或更改页面上其他示例的状态。刷新此页面可查看 AMP.setState()
之前的示例。声明状态的示例
<style amp-custom> .greenBorder { border: 5px solid green; } .redBorder { border: 5px solid red; } </style> </head> <body> <amp-state id="theFood"> <script type="application/json"> { "cupcakes": { "style": "greenBorder", "text": "Just kidding, I want to eat cupcakes." }, "sushi": { "style": "redBorder", "text": "Actually, I want to eat sushi." } } </script> </amp-state> <div class="greenBorder" [class]="theFood[currentMeal].style"> <p>Each food has a different border color.</p> <p [text]="theFood[currentMeal].text">I want to eat cupcakes.</p> <button on="tap:AMP.setState({currentMeal: 'sushi'})">Set to sushi</button> <button on="tap:AMP.setState({currentMeal: 'cupcakes'})">Set to cupcakes</button> </div>
<amp-state>
组件使用 JSON 对象声明状态。它具有theFood
的id
,允许我们引用定义的数据。但是由于<amp-bind>
不会在电子邮件加载时评估<amp-state>
,因此状态为空。- 页面加载时具有视觉默认值。
<div>
元素已定义class="greenBorder"
。- 第二个
<p>
元素在标记内定义了“我想要纸杯蛋糕。”。 <amp-img>
src
指向一个 URL。- 可更改的元素具有指向表达式的绑定。
<div>
上的[class]
属性绑定到theFood[currentMeal].style
表达式。- 第二个
<p>
上的[text]
属性绑定到theFood[currentMeal].text
表达式。
如果用户单击“设置为寿司”按钮
tap
事件触发AMP.setState
操作。- setState 操作会将
currentMeal
转换为状态并将其设置为sushi
。 - AMP 会使用包含状态
currentMeal
的表达式评估绑定。 [class]="theFood[currentMeal].style
将class
更新为redBorder
。theFood[currentMeal].text
将第二个<p>
元素的内部文本更新为“实际上,我想吃寿司。”。
使用 [class]="theFood[currentMeal].style"
作为表达式语法评估的示例
[class]
是要更新的属性theFood
是<amp-state>
组件的 id。currentMeal
是状态名称。在theFood
的情况下,它将是cupcakes
或sushi
。style
是状态变量。它对应于匹配的 JSON 键,并将绑定属性设置为该键的值。
<amp-state>
规范
amp-state
元素必须包含一个子 <script>
元素。
<amp-state id="myLocalState"> <script type="application/json"> { "foo": "bar" } </script> </amp-state>
状态
每个使用 amp-bind
的 AMP 文档都具有文档范围内的可变 JSON 数据或状态。
大小
<amp-state>
元素的 JSON 数据最大大小为 100KB。
使用 <amp-state>
定义和初始化状态
表达式不会在页面加载时进行评估,但您可以定义初始状态。<amp-state>
组件包含不同的状态及其状态变量。虽然这定义了状态,但在用户交互之前,它不会反映在页面上。
<amp-state id="myDefinedState"> <script type="application/json"> { "foo": "bar" } </script> </amp-state> <p [text]="myDefinedState.foo"></p> <button on="tap:AMP.setState({})">See value of initialized state</button>
使用 表达式 引用状态变量。如果 JSON 数据未嵌套在 <amp-state>
组件中,请通过点语法引用状态。在上面的示例中,myState.foo
的计算结果为“bar”。
<amp-state>
元素还可以指定 CORS URL,而不是子 JSON 脚本。有关详细信息,请参阅 <amp-state>
规范。
<amp-state id="myRemoteState" src="/static/samples/json/websites.json"> </amp-state>
使用 AMP.setState()
更新状态变量
AMP.setState()
操作会将对象字面量合并到状态中。这意味着您可以更新已定义状态变量的值。
<amp-state id="myUpdateState"> <script type="application/json"> { "foo": "bar", "baz": "hello" } </script> </amp-state> <p [text]="myUpdateState.foo"></p> <p [text]="myUpdateState.baz"></p> <button on="tap:AMP.setState({})">See value of set state</button> <!-- Like JavaScript, you can reference existing variables in the values of the object literal. --> <button on="tap:AMP.setState({myUpdateState:{baz: myUpdateState.foo}})"> Set value of baz to value of foo </button> <button on="tap:AMP.setState({myUpdateState:{baz: 'world'}})"> Set value of baz to "world" </button>
在上面的示例中,触发第一个按钮上的 AMP.setState({})
操作会评估 [text]
绑定表达式。然后,它会将定义的状态变量的值插入到 <p>
标记中。
当单击第二个按钮时,使用 AMP.setState({myState:{baz: myState.foo}})
操作定义,它会深度合并“baz”状态变量的值,使其与“foo”状态变量的值相同。两个 <p>
标记都显示“bar”。
状态变量值可以更新为初始状态中未定义的值。当单击第三个按钮时,使用 "tap:AMP.setState({myState:{baz: 'world'}})"
操作定义,它会深度合并“baz”状态变量的值,将其覆盖为“world”。
在其他两个按钮之后单击第一个按钮会设置当前状态。没有任何变化。
状态变量会在页面刷新时恢复为 <amp-state>
中定义的 JSON。
事件触发和数据
当由某些事件触发时,AMP.setState()
可以访问 event
属性上的事件相关数据。
<!-- The "change" event of this <input> element contains a "value" variable that can be referenced via "event.value". --> <select on="change:AMP.setState({ option: event.value })"> <option value="0">No selection</option> <option value="1">Option 1</option> <option value="2">Option 2</option> </select> <div hidden [hidden]="option != 1"> Option 1 </div> <div hidden [hidden]="option != 2"> Option 2 </div>
更新嵌套变量
嵌套对象通常合并到最大深度 10。所有变量(包括在 <amp-state>
中定义的变量)都可以被覆盖。
<amp-state id="myState"> <script type="application/json"> { "foo": "bar", "first": { "a": "nested once", "ab": { "b": "nested twice", "bc": { "c": "nested three times", "cd": { "d": "nested four times", "de": { "e": "nested five times", "ef": { "f": "nested six times", "fg": { "g": "nested seven times", "gh": { "h": "nested nine times", "hi": { "i": "nested ten times" } } } } } } } } } } </script> </amp-state> <p [text]="myState.foo"></p> <p [text]="myState.first.ab.bc.cd.de.ef.fg.gh.hi.i"></p> <button on="tap:AMP.setState({})">See value of set state</button> <button on="tap:AMP.setState({ myState: {first: {ab: {bc: {cd: {de: {ef: {fg: {gh: {hi: {i:'this is as far as you should merge nested values'} } } } } } } } } } })" > Merge 10th nested object </button>
循环引用
如果 object
包含循环引用,则 AMP.setState(object)
会抛出错误。
删除变量
通过在 AMP.setState()
中将其值设置为 null
来删除现有状态变量。
<button on="tap:AMP.setState({removeMe: null})"></button>
使用 AMP.setState()
进行深度合并
调用 AMP.setState()
会将提供的对象字面量与当前状态深度合并。amp-bind
会将所有字面量直接写入状态,但嵌套对象除外,嵌套对象会递归合并。状态中的基本类型和数组始终被对象字面量中同名的变量覆盖。
姓名
年龄
车辆
<p [text]="employee.name">Name</p> <p [text]="employee.age">Age</p> <p [text]="employee.vehicle">Vehicle</p> <!-- Pressing this button changes state to: --> <button on="tap:AMP.setState({ employee: { name: 'John Smith', age: 47, vehicle: 'Car' } })" > Set employee to John Smith </button> <!-- Pressing this button recursively merges the object literal argument, --> <!-- `{employee: {age: 64}}`, into the existing state. --> <button on="tap:AMP.setState({ employee: { age: 64 } })" > Set employee age to 64 </button> <!-- The value updates from 47 to 64 at employee.age. --> <!-- No other values change. -->
表达式
amp-bind
使用可以引用状态的类 JavaScript 表达式。
与 JavaScript 的差异
- 表达式只能访问包含文档的 状态。
- 表达式不能访问
window
或document
。global
引用顶层状态。 - 仅可以使用
amp-bind
允许使用的函数和运算符。 允许使用箭头函数作为函数参数,例如[1, 2, 3].map(x => x + 1)
。- 不允许使用自定义函数、类和循环。
- 未定义的变量和数组索引超出范围返回
null
,而不是undefined
或抛出错误。 - 为了提高性能,当前单个表达式限制为 250 个操作数。如果这对您的用例来说不够,请与我们联系。
以下都是有效的表达式
<p [text]="myExpressionsState.foo"></p> <!-- 1 + '1'; // 11 --> <button on="tap:AMP.setState({myExpressionsState: {foo: 1 + '1'}})"> foo: 1 + "1" </button> <!-- 1 + +'1'; // 2 --> <button on="tap:AMP.setState({myExpressionsState: {foo: 1 + + '1'}})"> foo: 1 + + "1" </button> <!-- !0; // true --> <button on="tap:AMP.setState({myExpressionsState: {foo: !0}})">foo: !0</button> <!-- null || 'default'; // 'default' --> <button on="tap:AMP.setState({myExpressionsState: {foo: null || 'default'}})"> null || "default" </button> <!-- [1, 2, 3].map(x => x + 1); // 2,3,4 --> <button on="tap:AMP.setState({myExpressionsState: {foo: [1, 2, 3].map(x => x + 1)}})" > [1, 2, 3].map(x => x + 1) </button>
在 bind-expr-impl.jison 和 bind-expression.js 中查找完整的表达式语法和实现。
允许使用的函数
数组
单参数箭头函数不能有括号,例如使用 x => x + 1
而不是 (x) => x + 1
。sort()
和 splice()
返回修改后的副本,而不是原地操作。
concat: 1, 2, 3
filter: 过滤掉少于三个字母的单词
includes: "hello" 或 "world"
indexOf: "world"
join: 将所有单词用破折号连接
lastIndexOf: "amp-bind"
map: 将每个数字添加到前一个数字
reduce: 将数组中的所有数字相加
slice: 返回索引为 1 和 3 的单词
some: 某些数字小于 2
sort: 将单词按字母顺序排列
splice: 在索引 2 处插入 "amp-bind"
<amp-state id="myArrayState"> <script type="application/json"> { "foo": [1, 2, 3], "bar": ["hello", "world", "bar", "baz"], "baz": "Hello world, welcome to amp-bind" } </script> </amp-state> <p [text]="'concat: ' + myArrayState.foo.concat(4)">concat: 1, 2, 3</p> <p [text]="'filter: ' + myArrayState.bar.filter(word => word.length > 3)"> filter: words with less than three letter </p> <p [text]="'includes: ' + myArrayState.bar.includes('hello' || 'world')"> includes: "hello" or "world" </p> <p [text]="'indexOf: ' + myArrayState.bar.indexOf('world')">indexOf: "world"</p> <p [text]="'join: ' + myArrayState.bar.join('-')"> join: all words with a dash </p> <p [text]="'lastIndexOf: ' + myArrayState.baz.lastIndexOf('amp-bind')"> lastIndexOf: "amp-bind" </p> <p [text]="'map: ' + myArrayState.foo.map((x, i) => x + i)"> map: add each number to previous number </p> <p [text]="'reduce: ' + myArrayState.foo.reduce((x, i) => x + i)"> reduce: add all numbers in array together </p> <p [text]="'slice: ' + myArrayState.bar.slice(1,3)"> slice: return words at index 1 and 3 </p> <p [text]="'some: ' + myArrayState.foo.some(x => x < 2)"> some: some numbers are less than 2 </p> <p [text]="'sort: ' + myArrayState.bar.sort()"> sort: place words in alphabetical order </p> <p [text]="'splice: ' + myArrayState.bar.splice(2, 0, 'amp-bind')"> splice: place "amp-bind" at index 2 </p> <button on="tap:AMP.setState({})">Evaluate</button>
数字
toExponential: 将 100 转换为 5 次方的指数形式
toFixed: 将 1.99 四舍五入并保留一位小数
toPrecision: 将 1.234567 作为字符串返回,保留三位有效数字
toString: 将 3.14 作为字符串返回
<p [text]="'toExponential: ' + (100).toExponential(5)"> toExponential: 100 to the exponent of 5 </p> <p [text]="'toFixed: ' + (1.99).toFixed(1)"> toFixed: 1.99 rounded and fixed to first decimal </p> <p [text]="'toPrecision: ' + (1.234567).toPrecision(3)"> toPrecision: 1.234567 returned as a string to the third digit </p> <p [text]="'toString ' + (3.14).toString()"> toString: 3.14 returned as a string </p> <button on="tap:AMP.setState({})">Evaluate</button>
字符串
charAt: 索引为 6 的字符
charCodeAt: 索引为 6 的字符的 UTF-16 代码单元
concat: 合并 foo 和 bar
lastIndexOf: "w" 的索引
replace: 将 "world" 替换为 "amp-bind"
slice: 提取前 5 个字符
split: 在空格处拆分单词并作为数组返回
toLowerCase: 将所有字母转换为小写
toUpperCase: 将所有字母转换为大写
<amp-state id="myStringState"> <script type="application/json"> { "foo": "Hello world", "bar": ", welcome to amp-bind" } </script> </amp-state> <p [text]="'charAt: ' + myStringState.foo.charAt(6)"> charAt: The character at index 6 </p> <p [text]="'charCodeAt: ' + myStringState.foo.charCodeAt(6)"> charCodeAt: The UTF-16 code unit of the character at index 6 </p> <p [text]="'concat: ' + myStringState.foo.concat(myState.bar)"> concat: Combine foo and bar </p> <p [text]="'lastIndexOf: ' + myStringState.foo.lastIndexOf('w')"> lastIndexOf: The index of "w" </p> <p [text]="'replace: ' + myStringState.foo.replace('world', 'amp-bind')"> replace: Replace "world" with "amp-bind" </p> <p [text]="'slice: ' + myStringState.foo.slice(5)"> slice: Extract the first 5 characters </p> <p [text]="'split: ' + myStringState.foo.split(' ')"> split: Split words at space and return as array </p> <p [text]="'toLowerCase: ' + myStringState.foo.toLowerCase()"> toLowerCase: Make all letters lower case </p> <p [text]="'toUpperCase: ' + myStringState.foo.toUpperCase()"> toUpperCase: Make all letters upper case </p> <button on="tap:AMP.setState({})">Evaluate</button>
数学
静态函数没有命名空间,例如使用 abs(-1)
而不是 Math.abs(-1)
abs: 5 - 9 的绝对值
abs: 将 1.01 向上舍入到下一个最大的整数
floor: 将 1.99 向下舍入到整数
max: 返回最大的数字
min: 返回最小的数字
pow: 返回 5 的 3 次方
random: 返回一个大于 0 且小于 1 的数字
round: 将 1.51 四舍五入
sign: 判断正负
<p [text]="'abs: ' + abs(5 - 9)">abs: absolute number of 5 - 9</p> <p [text]="'ceil: ' + ceil(1.01)"> abs: round 1.01 up to the next largest whole number </p> <p [text]="'floor: ' + floor(1.99)">floor: round 1.99 down to a whole number</p> <p [text]="'max: ' + max(100, 4, 98)">max: return largest number</p> <p [text]="'min: ' + min(100, 4, 98)">min: return smalled number</p> <p [text]="'pow: ' + pow(5, 3)">pow: return 5 to the power of 3</p> <p [text]="'random: ' + random()"> random: return a number greater than 0 and less than 1 </p> <p [text]="'round: ' + round(1.51)">round: round 1.51</p> <p [text]="'sign: ' + sign(-9)">sign: evaluate if positive or negative</p> <button on="tap:AMP.setState({})">Evaluate</button>
对象
静态函数没有命名空间,例如使用 keys(Object)
而不是 Object.abs(Object)
keys: myObjectState JSON 对象的键
values: myObjectState JSON 对象的值
<amp-state id="myObjectState"> <script type="application/json"> { "hello": "world", "foo": "bar" } </script> </amp-state> <p [text]="'keys: ' + keys(myObjectState)"> keys: myObjectState JSON object keys </p> <p [text]="'values: ' + values(myObjectState)"> values: myObjectState JSON object values </p> <button on="tap:AMP.setState({})">Evaluate</button>
全局
encodeURI: 编码 URI 并忽略协议前缀
encodeURIComponent: 编码 URI
<p [text]="'encodeURI: ' + encodeURI('https://amp.org.cn/😉')"> encodeURI: Encode a URI and ignore protocol prefix </p> <p [text]="'encodeURIComponent: ' + encodeURIComponent('https://amp.org.cn/😉')"> encodeURIComponent: Encode a URI </p> <button on="tap:AMP.setState({})">Evaluate</button>
使用 amp-bind-macro
定义宏
通过定义 amp-bind-macro
重用 amp-bind
表达式片段。amp-bind-macro
元素允许一个表达式接受零个或多个参数并引用当前状态。像函数一样调用 amp-bind-macros
,引用文档中任何位置的 id
属性值。
输入半径值
圆的面积为 0。
<amp-bind-macro id="circleArea" arguments="radius" expression="3.14 * radius * radius" ></amp-bind-macro> <p> Input a radius value </p> <input type="number" min="0" max="100" value="0" on="input-throttled:AMP.setState({myCircle:{radius: event.value}})" /> <p> The circle has an area of <span [text]="circleArea(myCircle.radius)">0</span>. </p>
宏还可以调用在自身之前定义的其他宏。宏不能递归调用自身。
绑定
绑定 是 [property]
形式的特殊属性,它将元素的属性链接到表达式。如果在 XML 中开发,请使用与 XML 兼容的替代语法。
当状态更改时,将评估与该状态绑定的表达式。与状态绑定的元素属性将使用新的表达式结果更新。
布尔表达式结果切换布尔属性。例如:<amp-video [controls]="expr"...>
。当 expr
计算结果为 true
时,<amp-video>
元素具有 controls
属性。当 expr
计算结果为 false
时,将删除 controls
属性。
此浏览器不支持 video 元素。
<amp-video [controls]="controls" width="640" height="360" layout="responsive" poster="/static/inline-examples/images/kitten-playing.png" > <source src="/static/inline-examples/videos/kitten-playing.webm" type="video/webm" /> <source src="/static/inline-examples/videos/kitten-playing.mp4" type="video/mp4" /> <div fallback> <p>This browser does not support the video element.</p> </div> </amp-video> <button on="tap:AMP.setState({ controls: true })"> Controls </button> <button on="tap:AMP.setState({ controls: false })"> No Controls </button>
React 和 XML 兼容性
如果使用 React 或 XML 进行开发,请使用替代的 data-amp-bind-property
语法。属性名称中的 [
和 ]
字符是无效的 XML,导致 [property]
语法不可用。
将 property
字段替换为您想要在 data-amp-bind-property
中定义的属性的名称。
例如,[text]="myState.foo"
将变为 data-amp-bind-text="myState.foo"
。
绑定类型
amp-bind
支持对五种类型的元素状态进行数据绑定。
使用 [text]
属性绑定 Node.textContent
。大多数文本元素都支持 [text]
属性。
<p [text]="'Hello ' + myState.foo">Hello World</p> <p></p>
CSS 类
使用 [class]
属性绑定元素的 class
。[class]
表达式必须生成以空格分隔的字符串。也就是说,如果要绑定多个类,请在名称之间使用空格。逗号或破折号将被评估为类名。
<head> <style amp-custom> .background-green { background: green; } .background-red { background: red; } .border-red { border-color: red; border-width: 5px; border-style: solid; } </style> </head> <body> <div class="background-red" [class]="myClass">Hello World</div> <!-- This button adds both classes --> <button on="tap:AMP.setState({ myClass: 'background-green border-red' })"> Working: Change Class </button> <!-- String arrays also work --> <button on="tap:AMP.setState({ myClass: ['background-green', 'border-red'] })" > Working string array: Change Class </button> <!-- This expression evaluates to class="background-green,border-red" --> <button on="tap:AMP.setState({ myClass: 'background-green,border-red' })"> Broken: Change Class </button> </body>
使用 [hidden]
属性隐藏和显示元素。[hidden]
表达式应为布尔表达式。
你好!
<p [hidden]="hiddenState">Hello there!</p> <button on="tap:AMP.setState({hiddenState: true})">Hide</button> <button on="tap:AMP.setState({hiddenState: false})">Show</button>
AMP 组件的大小
使用 [width]
和 [height]
属性更改 width
和 height
。
<amp-img src="https://unsplash.it/400/200" width="200" [width]="myImageDimension.width" height="100" [height]="myImageDimension.height" > </amp-img> <button on="tap:AMP.setState({ myImageDimension: { width: 400, height: 200 } })" > Change size </button>
辅助功能状态和属性
用于动态更新辅助技术(如屏幕阅读器)可用的信息。所有 [aria-*]
属性都是可绑定的。
AMP 组件特定属性和 HTML 属性
一些 AMP 组件和 HTML 元素具有特定的可绑定属性。它们列在下面。
AMP 组件特定属性
<amp-carousel type=slides>
[slide]
更改当前显示的幻灯片索引。
查看示例.
<amp-img>
[alt]
[attribution]
<amp-lightbox>
[open]
切换灯箱的显示。
on="lightboxClose: AMP.setState(...)"
在灯箱关闭时更新变量。
<amp-selector>
[selected]
更改当前选择的子元素,这些子元素由其option
属性值标识。支持以逗号分隔的值列表以进行多项选择。查看示例。[disabled]
[selected]
没有不可绑定的属性。如果使用 selected
,AMP 验证器将抛出错误。
<button>
[disabled]
[value]
请参阅相应的 button 属性。
<details>
[open]
请参阅相应的 details 属性。
<fieldset>
[disabled]
启用或禁用字段集。
<image>
[xlink:href]
请参阅相应的 image 属性。
<input>
[autocomplete]
[disabled]
[height]
[max]
[maxlength]
[multiple]
[pattern]
[placeholder]
[readonly]
[required]
[size]
[spellcheck]
[step]
[value]
[width]
请参阅相应的 input 属性。
<option>
[disabled]
[label]
[selected]
[value]
请参阅相应的 option 属性。
<optgroup>
[disabled]
[label]
请参阅相应的 optgroup 属性。
<section>
[data-expand]
更改amp-accordion
中section
的展开。
<select>
[disabled]
[multiple]
[required]
[size]
请参阅相应的 select 属性。
<textarea>
[autocomplete]
[cols]
[disabled]
[defaultText]
[maxlength]
[minlength]
[placeholder]
[readonly]
[required]
[rows]
[spellcheck]
[wrap]
使用 [defaultText]
更新初始文本,使用 [text]
更新当前文本。请参阅相应的 textarea 属性。
不允许的绑定
出于安全原因,不允许绑定到 innerHTML
。
所有属性绑定都会清理不安全的值(例如,javascript:
)。
调试
通过将电子邮件保存为 HTML 文件在开发模式下进行测试。通过在 URL 末尾添加片段 #development=1
在浏览器中进行测试。这会在开发期间突出显示浏览器控制台中的警告和错误,并授予对特殊调试函数的访问权限。
警告
在开发模式下,当绑定属性的默认值与其相应的表达式的初始结果不匹配时,amp-bind
将发出警告。这有助于防止由于其他状态变量的更改而导致意外的突变。例如
<!-- The element's default class value ('def') doesn't match the expression result for [class] ('abc'), so a warning will be issued in development mode. --> <p [class]="'abc'" class="def"></p>
在开发模式下,当取消引用未定义的变量或属性时,amp-bind
也会发出警告。这也有助于防止由于 null
表达式结果而导致意外的突变。例如
<amp-state id="myAmpState"> <script type="application/json"> {"foo": 123} </script> </amp-state> <!-- The amp-state#myAmpState does not have a `bar` variable, so a warning will be issued in development mode. --> <p [text]="myAmpState.bar">Some placeholder text.</p>
错误
下面概述了使用 amp-bind
时可能出现的错误类型。
类型 | 消息 | 建议 |
---|---|---|
无效绑定 | 不允许绑定到 <P> 上的 [foo]. | 仅使用允许列表中的绑定。 |
语法错误 | 表达式编译错误,在... | 验证表达式是否有拼写错误。 |
不在允许列表中的函数 | 不支持 alert 函数。 | 仅使用允许列表中的函数。 |
已清理的结果 | "javascript:alert(1)" 不是 [href] 的有效结果。 | 避免被禁止的 URL 协议或会使 AMP 验证器失败的表达式。 |
CSP 违规 | 拒绝从 'blob:...' 创建 worker,因为它违反了以下内容安全策略指令... | 将 default-src blob: 添加到您的域的内容安全策略。amp-bind 将耗时的任务委托给专用 Web Worker,以确保良好的性能。 |
调试状态
使用 AMP.printState()
将当前状态打印到控制台。要使此功能正常工作,您需要启用开发模式。
表达式语法
amp-bind
表达式的类 BNF 语法
expr:
operation
| invocation
| member_access
| '(' expr ')'
| variable
| literal
;
operation:
'!' expr
| '-' expr %prec UMINUS
| '+' expr %prec UPLUS
| expr '+' expr
| expr '-' expr
| expr '*' expr
| expr '/' expr
| expr '%' expr
| expr '&&' expr
| expr '||' expr
| expr '<=' expr
| expr '<' expr
| expr '>=' expr
| expr '>' expr
| expr '!=' expr
| expr '==' expr
| expr '?' expr ':' expr
;
invocation:
NAME args
| expr '.' NAME args
| expr '.' NAME '(' arrow_function ')'
| expr '.' NAME '(' arrow_function ',' expr ')'
;
arrow_function:
'(' ')' '=>' expr
| NAME '=>' expr
| '(' params ')' '=>' expr
;
params:
NAME ',' NAME
| params ',' NAME
;
args:
'(' ')'
| '(' array ')'
;
member_access:
expr member
;
member:
'.' NAME
| '[' expr ']'
;
variable:
NAME
;
literal:
primitive
| object_literal
| array_literal
;
primitive:
STRING
| NUMBER
| TRUE
| FALSE
| NULL
;
array_literal:
'[' ']'
| '[' array ']'
| '[' array ',' ']'
;
array:
expr
| array ',' expr
;
object_literal:
'{' '}'
| '{' object '}'
| '{' object ',' '}'
;
object:
key_value
| object ',' key_value
;
key_value:
key ':' expr
;
key:
NAME
| primitive
| '[' expr ']'
;
您已经阅读过本文档十几次,但它并没有真正涵盖您的所有问题?也许其他人也有同感:在 Stack Overflow 上联系他们。
转到 Stack Overflow 发现错误或缺少功能?AMP 项目强烈鼓励您的参与和贡献!我们希望您成为我们开源社区的持续参与者,但我们也欢迎您为自己特别热衷的问题做出一次性贡献。
转到 GitHub