脚本和事件处理
你可以使用组件模板中的 <script> 标签向浏览器发送 JavaScript 代码,并为 Astro 组件添加功能。
¥You can send JavaScript to the browser and add functionality to your Astro components using <script> tags in the component template.
脚本可以为你的网站添加交互功能,例如处理事件或动态更新内容,而无需使用 React、Svelte 或 Vue 等 用户界面框架。这避免了加载框架 JavaScript 的开销,并且无需你了解任何其他框架即可创建功能齐全的网站或应用。
¥Scripts add interactivity to your site, such as handling events or updating content dynamically, without the need for a UI framework like React, Svelte, or Vue. This avoids the overhead of shipping framework JavaScript and doesn’t require you to know any additional framework to create a full-featured website or application.
¥Client-Side Scripts
脚本可用于添加事件监听器、发送分析数据、播放动画以及 JavaScript 可以在网络上执行的所有其他操作。
¥Scripts can be used to add event listeners, send analytics data, play animations, and everything else JavaScript can do on the web.
Astro 会自动增强 HTML 标准 <script> 标签,支持打包、TypeScript 等功能。详细信息请参见 Astro 如何处理脚本。
¥Astro automatically enhances the HTML standard <script> tag with bundling, TypeScript, and more. See how astro processes scripts for more details.
<button data-confetti-button>Celebrate!</button>
<script> // Import from npm package. import confetti from 'canvas-confetti';
// Find our component DOM on the page. const buttons = document.querySelectorAll('[data-confetti-button]');
// Add event listeners to fire confetti when a button is clicked. buttons.forEach((button) => { button.addEventListener('click', () => confetti()); });</script>¥Script processing
默认情况下,Astro 会按以下方式处理不包含任何属性(src 除外)的 <script> 标签:
¥By default, Astro processes <script> tags that contain no attributes (other than src) in the following ways:
-
TypeScript 支持:所有脚本默认使用 TypeScript。
-
导入打包:你可以导入本地文件或 npm 模块,它们将被打包在一起。
-
类型模块:已处理的脚本会自动转换为
type="module"。 -
去重:如果页面上多次使用包含
<script>的组件,则该脚本只会包含一次。 -
自动内联:如果脚本足够小,Astro 会将其直接内联到 HTML 中,以减少请求数量。
<script> // Processed! Bundled! TypeScript! // Importing local scripts and from npm packages works.</script>未处理的脚本
Section titled “未处理的脚本”¥Unprocessed scripts
如果 <script> 标签包含除 src 之外的任何属性,Astro 将不会处理该标签。
¥Astro will not process a <script> tag if it has any attribute other than src.
你可以添加 is:inline 指令来有意地选择不处理某个脚本。
¥You can add the is:inline directive to intentionally opt out of processing for a script.
<script is:inline> // Will be rendered into the HTML exactly as written! // Not transformed: no TypeScript and no import resolution by Astro. // If used inside a component, this code is duplicated for each instance.</script>在你的页面上包含 JavaScript 文件
Section titled “在你的页面上包含 JavaScript 文件”¥Include JavaScript files on your page
你可能希望将脚本编写为单独的 .js/.ts 文件,或者需要引用另一台服务器上的外部脚本。你可以通过在 <script> 标签的 src 属性中引用这些来完成此操作。
¥You may want to write your scripts as separate .js/.ts files or need to reference an external script on another server. You can do this by referencing these in a <script> tag’s src attribute.
导入本地脚本
Section titled “导入本地脚本”¥Import local scripts
何时使用这个:当你的脚本位于 src/ 内时。
¥When to use this: when your script lives inside of src/.
Astro 将根据 脚本处理规则 处理这些脚本。
¥Astro will process these scripts according to the script processing rules.
<!-- relative path to script at `src/scripts/local.js` --><script src="../scripts/local.js"></script>
<!-- also works for local TypeScript files --><script src="./script-with-types.ts"></script>加载外部脚本
Section titled “加载外部脚本”¥Load external scripts
何时使用这个:当你的 JavaScript 文件位于 public/ 内或 CDN 上时。
¥When to use this: when your JavaScript file lives inside of public/ or on a CDN.
要加载项目 src/ 文件夹外部的脚本,请包含 is:inline 指令。当你如上所述导入脚本时,此方法会跳过 Astro 提供的 JavaScript 处理、打包和优化。
¥To load scripts outside of your project’s src/ folder, include the is:inline directive. This approach skips the JavaScript processing, bundling, and optimizations that are provided by Astro when you import scripts as described above.
<!-- absolute path to a script at `public/my-script.js` --><script is:inline src="/my-script.js"></script>
<!-- full URL to a script on a remote server --><script is:inline src="https://my-analytics.com/script.js"></script>常见的脚本模式
Section titled “常见的脚本模式”¥Common script patterns
处理 onclick 和其他事件
Section titled “处理 onclick 和其他事件”¥Handle onclick and other events
一些 UI 框架使用自定义语法进行事件处理,例如 onClick={...} (React/Preact) 或 @click="..." (Vue)。Astro 更严格地遵循标准 HTML,并且不使用事件的自定义语法。
¥Some UI frameworks use custom syntax for event handling like onClick={...} (React/Preact) or @click="..." (Vue). Astro follows standard HTML more closely and does not use custom syntax for events.
相反,你可以在 <script> 标记中使用 addEventListener 来处理用户交互。
¥Instead, you can use addEventListener in a <script> tag to handle user interactions.
<button class="alert">Click me!</button>
<script> // Find all buttons with the `alert` class on the page. const buttons = document.querySelectorAll('button.alert');
// Handle clicks on each button. buttons.forEach((button) => { button.addEventListener('click', () => { alert('Button was clicked!'); }); });</script>如果页面上有多个 <AlertButton /> 组件,Astro 将不会多次运行脚本。脚本会被打包,并且每个页面仅包含一次。使用 querySelectorAll 可确保此脚本将事件监听器附加到页面上所有带有 alert 类的按钮。
¥If you have multiple <AlertButton /> components on a page, Astro will not run the script multiple times. Scripts are bundled and only included once per page. Using querySelectorAll ensures that this script attaches the event listener to every button with the alert class found on the page.
具有自定义元素的 Web 组件
Section titled “具有自定义元素的 Web 组件”¥Web components with custom elements
你可以使用 Web 组件标准创建具有自定义行为的自己的 HTML 元素。在 .astro 组件中定义 自定义元素 允许你构建交互式组件,而无需 UI 框架库。
¥You can create your own HTML elements with custom behavior using the Web Components standard. Defining a custom element in a .astro component allows you to build interactive components without needing a UI framework library.
在此示例中,我们定义了一个新的 <astro-heart> HTML 元素,用于跟踪你单击心形按钮的次数并使用最新计数更新 <span>。
¥In this example, we define a new <astro-heart> HTML element that tracks how many times you click the heart button and updates the <span> with the latest count.
<!-- Wrap the component elements in our custom element “astro-heart”. --><astro-heart> <button aria-label="Heart">💜</button> × <span>0</span></astro-heart>
<script> // Define the behaviour for our new type of HTML element. class AstroHeart extends HTMLElement { connectedCallback() { let count = 0;
const heartButton = this.querySelector('button'); const countSpan = this.querySelector('span');
// Each time the button is clicked, update the count. heartButton.addEventListener('click', () => { count++; countSpan.textContent = count.toString(); }); } }
// Tell the browser to use our AstroHeart class for <astro-heart> elements. customElements.define('astro-heart', AstroHeart);</script>在这里使用自定义元素有两个优点:
¥There are two advantages to using a custom element here:
-
你可以使用
this.querySelector(),而不是使用document.querySelector()搜索整个页面,它仅在当前自定义元素实例内搜索。这使得一次只处理一个组件实例的子组件变得更加容易。 -
虽然
<script>只运行一次,但浏览器每次在页面上找到<astro-heart>时都会运行我们自定义元素的connectedCallback()方法。这意味着你可以一次安全地为一个组件编写代码,即使你打算在一页上多次使用该组件。
将 frontmatter 变量传递给脚本
Section titled “将 frontmatter 变量传递给脚本”¥Pass frontmatter variables to scripts
在 Astro 组件中,前题 中的代码(位于 --- 代码块之间)在服务器端运行,无法在浏览器中访问。
¥In Astro components, the code in the frontmatter (between the --- fences) runs on the server and is not available in the browser.
要将服务器端变量传递给客户端脚本,请将它们存储在 HTML 元素的 data-* 属性 中。脚本随后可以使用 dataset 属性访问这些值。
¥To pass server-side variables to client-side scripts, store them in data-* attributes on HTML elements. Scripts can then access these values using the dataset property.
在此示例组件中,message 属性存储在 data-message 属性中,因此自定义元素可以读取 this.dataset.message 并在浏览器中获取该属性的值。
¥In this example component, a message prop is stored in a data-message attribute, so the custom element can read this.dataset.message and get the value of the prop in the browser.
---const { message = 'Welcome, world!' } = Astro.props;---
<!-- Store the message prop as a data attribute. --><astro-greet data-message={message}> <button>Say hi!</button></astro-greet>
<script> class AstroGreet extends HTMLElement { connectedCallback() { // Read the message from the data attribute. const message = this.dataset.message; const button = this.querySelector('button'); button.addEventListener('click', () => { alert(message); }); } }
customElements.define('astro-greet', AstroGreet);</script>现在我们可以多次使用我们的组件,并且每次都会收到不同的消息。
¥Now we can use our component multiple times and be greeted by a different message for each one.
---import AstroGreet from '../components/AstroGreet.astro';---
<!-- Use the default message: “Welcome, world!” --><AstroGreet />
<!-- Use custom messages passed as a props. --><AstroGreet message="Lovely day to build components!" /><AstroGreet message="Glad you made it! 👋" />组合脚本和 UI 框架
Section titled “组合脚本和 UI 框架”¥Combining scripts and UI Frameworks
执行 <script> 标记时,UI 框架渲染的元素可能尚不可用。如果你的脚本还需要处理 UI 框架组件,建议使用自定义元素。
¥Elements rendered by a UI framework may not be available yet when a <script> tag executes. If your script also needs to handle UI framework components, using a custom element is recommended.