AMP

重要提示:此文档不适用于您当前选择的格式故事

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 的介绍。

amp-bind 有三个主要概念

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

未声明状态的示例

你好世界

<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 引用顶层状态。
  • 只能使用 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>
在 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:将 "amp-bind" 放置在索引 2 处

<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: 将 “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>
在 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 属性。

此浏览器不支持 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>
在 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
发现错误或缺少功能?

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

前往 GitHub