">文档:<amp-bind> - amp.dev - AMP 框架
AMP

amp-bind

用法

amp-bind 组件为 AMP 页面启用了自定义状态交互。

为了提高性能并避免意外内容跳动的风险,amp-bind 不会在页面加载时计算表达式。这意味着可视元素应具有默认状态,而不应依赖 amp-bind 进行初始渲染。

观看此视频以了解 amp-bind 简介。

amp-bind 有三个主要概念

  1. 状态:文档范围的可变 JSON 状态。状态变量会根据用户操作进行更新。amp-bind 不会在页面加载时计算表达式。可视元素应定义其默认“状态”,而不应依赖 amp-bind 进行初始渲染。
  2. 表达式:可引用状态的类似 JavaScript 的表达式。
  3. 绑定:通过表达式将元素的属性链接到状态的特殊属性。通过以 [property] 的形式将其括在方括号内来绑定属性。

未声明状态的示例

Hello World

<p [text]="'Hello ' + foo">Hello World</p>

<button on="tap:AMP.setState({foo: 'Interactivity'})">
  Say "Hello Interactivity"
</button>
在 playground 中打开此代码段

在上面的示例中

  • 状态最初为空。
  • 它在 <p> 元素上对 [text](节点的文本内容)有一个单一的绑定
  • [text] 值包含表达式 'Hello ' + foo。此表达式连接字符串“Hello ”和状态变量 foo 的值。

当用户点击/单击按钮时

  1. 它会触发 tap 事件。
  2. tap 事件调用 AMP.setState() 方法。
  3. AMP.setState() 方法将 foo状态变量设置为 Interactivity 的值。
  4. 状态不再为空,因此页面会将绑定的属性更新为其状态。

在某些示例中调用 AMP.setState() 可能会设置或更改页面上其他示例的状态。刷新此页面以查看 AMP.setState() 之前的示例。

声明状态的示例

<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>
在 playground 中打开此代码段

使用 表达式 来引用状态变量。如果 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>
在 playground 中打开此代码段

在上面的示例中,对第一个按钮触发 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>
在 playground 中打开此代码段

更新嵌套变量

嵌套对象通常会合并到最大深度 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>
在 playground 中打开此代码段

循环引用

如果 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. -->
在 playground 中打开此代码段

表达式

amp-bind 使用可引用状态的类似 JavaScript 的表达式。

与 JavaScript 的差异

  • 表达式只能访问包含文档的 状态
  • 表达式无法访问 windowdocumentglobal 引用顶级状态。
  • 只能使用 已列入白名单的函数 和运算符。可以使用箭头函数作为函数参数,例如 [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>
在 playground 中打开此代码段

bind-expr-impl.jisonbind-expression.js 中查找完整的表达式语法和实现。

允许列出的函数

数组

单参数箭头函数不能带括号,例如使用 x => x + 1 而不是 (x) => x + 1sort()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>
在 playground 中打开此代码段

数字

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>
在 playground 中打开此代码段

字符串

charAt:索引 6 处的字符

charCodeAt:索引 6 处字符的 UTF-16 代码单元

concat:合并 foo 和 bar

lastIndexOf:字母“w”的索引

replace:用“amp-bind”替换“world”

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>
在 playground 中打开此代码段

数学

静态函数没有命名空间,例如,使用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>
在 playground 中打开此代码段

对象

静态函数没有命名空间,例如,使用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>
在 playground 中打开此代码段

全局

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>
在 playground 中打开此代码段

使用 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>
在 playground 中打开此代码段

宏还可以调用其他宏在宏自身之前定义。宏无法递归调用自身。

绑定

绑定是一种特殊属性,形式为 [property],它将元素的属性链接到表达式。如果在 XML 中开发,请使用备用与 XML 兼容的语法。

状态更改时,将计算与该状态绑定的表达式。与状态绑定的元素属性将使用新的表达式结果进行更新。

布尔表达式结果切换布尔属性。例如:<amp-video [controls]="expr"...>。当 expr 计算为 true 时,<amp-video> 元素具有 controls 属性。当 expr 计算为 false 时,controls 属性将被移除。

此浏览器不支持视频元素。

<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>
在 playground 中打开此代码段

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 支持对五种类型的元素状态进行数据绑定。

Node.textContent

使用 [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>
在 playground 中打开此代码段

hidden 属性

使用 [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>
在 playground 中打开此代码段

AMP 组件 的大小

使用 [width][height] 属性更改 widthheight

<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>
在 playground 中打开此代码段

辅助功能状态和属性

用于动态更新辅助技术(例如屏幕阅读器)可用的信息。所有 [aria-*] 属性 都可绑定。

AMP 组件特定和 HTML 属性

一些 AMP 组件和 HTML 元素具有特定的可绑定属性。它们如下所示。

特定于 AMP 组件的属性

<amp-carousel type=slides>

  • [slide] 更改当前显示的幻灯片索引。

查看示例.

<amp-lightbox>

  • [open] 切换灯箱显示。

使用 on="lightboxClose: AMP.setState(...)" 在关闭灯箱时更新变量。

<details>

  • [open]

请参阅相应的 details 属性

<fieldset>

  • [disabled] 启用或禁用 fieldset。

<image>

  • [xlink:href]

请参阅相应的 image 属性

<option>

  • [disabled]
  • [label]
  • [selected]
  • [value]

请参阅相应的 option 属性

<optgroup>

  • [disabled]
  • [label]

请参阅相应的 optgroup 属性

<section>

不允许的绑定

出于安全原因,不允许绑定到 innerHTML

所有属性绑定都已针对不安全值(例如 javascript:)进行了清理。

调试

警告

在开发模式下,当绑定的属性的默认值与其对应的表达式的初始结果不匹配时,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
发现了一个 bug 或缺少某个功能?

AMP 项目强烈鼓励您参与和做出贡献!我们希望您成为我们开源社区的持续参与者,但我们也欢迎您为特别热衷的问题做出一次性贡献。

转到 GitHub