ÿØÿà JFIF ÿá Exif MM * ÿÛ C
Server IP : 199.250.214.225 / Your IP : 3.15.151.183 Web Server : Apache System : Linux vps64074.inmotionhosting.com 3.10.0-1160.105.1.vz7.214.3 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : nicngo5 ( 1001) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /home/nicngo5/funds.upgrade.nicn.gov.ng/funds-upgraded/node_modules/alpinejs/ |
Upload File : |
# Alpine.js ![npm bundle size](https://img.shields.io/bundlephobia/minzip/alpinejs) ![npm version](https://img.shields.io/npm/v/alpinejs) [![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg?sanitize=true)](https://alpinejs.codewithhugo.com/chat/) Alpine.js æ供了 Vue 與 React ç‰å¤§æ¡†æž¶çš„互動å¼èˆ‡å®£å‘Šå¼çš„功能,而ä¸éœ€èŠ±è²»å¤ªå¤šæˆæœ¬ã€‚ 有了 Alpine.js å°±å¯ä»¥ç¹¼çºŒä½¿ç”¨ DOM,並在有需è¦çš„æ™‚å€™é€šéŽ Alpine.js å¢žåŠ åŠŸèƒ½ã€‚ å¯ä»¥æƒ³åƒæˆæ˜¯ JavaScript 版的 [Tailwind](https://tailwindcss.com/)。 > 備註:Alpine.js çš„æ ¼å¼å¹¾ä¹Žéƒ½æ˜¯å¾ž [Vue](https://vuejs.org/) åƒè€ƒè€Œä¾† (以åŠæ“´å……了 [Angular](https://angularjs.org/))。本人在æ¤ç”±è¡·æ„Ÿè¬é€™äº›å¥—件為 Web 環境帶來的貢ç»ã€‚ ## å®‰è£ **使用 CDN:** 將下列腳本新增至 `<head>` 末端。 ```html <script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js" defer></script> ``` 就這樣。Alpine.js 會自行åˆå§‹åŒ–。 在æ£å¼ç’°å¢ƒä¸ï¼Œå»ºè°åœ¨é€£çµä¸å›ºå®šç‰¹å®šç‰ˆæœ¬ï¼Œä»¥é¿å…新版本使功能無法使用。 如,è¦ä½¿ç”¨ `2.8.2` 版則å¯ä»¥é€™æ¨£å¯«ï¼š ```html <script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.8.2/dist/alpine.min.js" defer></script> ``` **使用 npm:** 從 npm 安è£å¥—件。 ```js npm i alpinejs ``` 在腳本ä¸å¼•å…¥ã€‚ ```js import 'alpinejs' ``` **è‹¥è¦æ”¯æ´ IE11** 請改用下列腳本。 ```html <script type="module" src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js"></script> <script nomodule src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine-ie11.min.js" defer></script> ``` 上述寫法使用了 [module/nomodule æ¨¡å¼ (英文)](https://philipwalton.com/articles/deploying-es2015-code-in-production-today/) ,這樣寫å¯ä»¥è®“ç¾ä»£ç€è¦½å™¨è‡ªå‹•è¼‰å…¥æ¨¡çµ„套件組åˆï¼Œè€Œ IE11 以åŠå…¶ä»–舊ç€è¦½å™¨ä¸å‰‡æœƒè‡ªå‹•è¼‰å…¥ IE11 模組套件。 ## 開始使用 **下拉é¸å–® Dropdownã€å¼·åˆ¶å›žæ‡‰è¦–窗 Modal** ```html <div x-data="{ open: false }"> <button @click="open = true">展開下拉é¸å–®</button> <ul x-show="open" @click.away="open = false" > 下拉é¸å–®å…§å®¹ </ul> </div> ``` **索引標籤 Tab** ```html <div x-data="{ tab: 'foo' }"> <button :class="{ 'active': tab === 'foo' }" @click="tab = 'foo'">Foo</button> <button :class="{ 'active': tab === 'bar' }" @click="tab = 'bar'">Bar</button> <div x-show="tab === 'foo'">索引標籤 Foo</div> <div x-show="tab === 'bar'">索引標籤 Bar</div> </div> ``` 也å¯ä»¥ç”¨åœ¨æ›´å¤šåœ°æ–¹ï¼š **éŠæ¨™åœç•™æ™‚é 先截å–下拉é¸å–®çš„ HTML** ```html <div x-data="{ open: false }"> <button @mouseenter.once=" fetch('/dropdown-partial.html') .then(response => response.text()) .then(html => { $refs.dropdown.innerHTML = html }) " @click="open = true" >顯示下拉é¸å–®</button> <div x-ref="dropdown" x-show="open" @click.away="open = false"> 載入ä¸é€²åº¦ç’°... </div> </div> ``` ## å¸ç¿’ 總共有 14 種å¯ç”¨çš„指示詞 (Directive): | 指示詞 | 說明 | | --- | --- | | [`x-data`](#x-data) | 宣告新元件定義範åœã€‚ | | [`x-init`](#x-init) | 模組åˆå§‹åŒ–後執行é‹ç®—å¼ã€‚ | | [`x-show`](#x-show) | ä¾æ“šé‹ç®—å¼ (true 或 false) æ–°å¢žæˆ–ç§»é™¤å…ƒç´ çš„ `display: none;`。 | | [`x-bind`](#x-bind) | 將屬性的值è¨ç‚º JS é‹ç®—å¼çš„執行çµæžœã€‚ | | [`x-on`](#x-on) | 將事件監è½å™¨é™„åŠ è‡³å…ƒç´ ä¸Šã€‚ç•¶äº‹ä»¶ç™¼å‡ºå¾ŒåŸ·è¡Œ JS é‹ç®—å¼ã€‚ | | [`x-model`](#x-model) | ç‚ºå…ƒç´ æ–°å¢žã€Œé›™å‘資料繫çµã€ã€‚ä¿æŒè¼¸å…¥å…ƒç´ 與元件資料間的åŒæ¥ã€‚ | | [`x-text`](#x-text) | 與 `x-bind` çš„é‹ä½œæ–¹å¼é¡žä¼¼ï¼Œä½†æ›´æ–°çš„æ˜¯å…ƒç´ çš„ `innerText`。 | | [`x-html`](#x-html) | 與 `x-bind` çš„é‹ä½œæ–¹å¼é¡žä¼¼ï¼Œä½†æ›´æ–°çš„æ˜¯å…ƒç´ çš„ `innerHTML`。 | | [`x-ref`](#x-ref) |å¾žå…ƒç´ ä¸å–得原始 DOM å…ƒç´ çš„ç°¡ä¾¿æ–¹æ³•ã€‚ | | [`x-if`](#x-if) | 從 DOM ä¸å®Œå…¨ç§»é™¤å…ƒç´ ã€‚å¿…é ˆåœ¨ `<template>` 標籤上使用。 | | [`x-for`](#x-for) | 為陣列ä¸çš„æ¯å€‹é …目建立新 DOM ç¯€é»žã€‚å¿…é ˆåœ¨ `<template>` 標籤上使用。 | | [`x-transition`](#x-transition) | ç”¨æ–¼åœ¨è½‰å ´çš„å„å€‹éšŽæ®µç‚ºå…ƒç´ è¨å®š Class 的指示詞。 | | [`x-spread`](#x-spread) | 為了更佳的å¯è¤‡ç”¨æ€§ï¼Œå¯å°‡åŒ…å« Alpine 指示詞的物件繫çµè‡³å…ƒç´ 上。 | | [`x-cloak`](#x-cloak) | 該屬性會在 Alpine åˆå§‹åŒ–後移除。é©åˆç”¨ä¾†éš±è—還未åˆå§‹åŒ–çš„ DOM。 | ä»¥åŠ 6 個é”法屬性: | é”法屬性 | 說明 | | --- | --- | | [`$el`](#el) | 截å–æ ¹å…ƒç´ çš„ DOM 節點。 | | [`$refs`](#refs) | 截å–å…ƒç´ ä¸ä»¥ `x-ref` 標記的 DOM å…ƒç´ ã€‚ | | [`$event`](#event) | 在事件監è½å™¨ä¸æˆªå–ç€è¦½å™¨çš„原生「Eventã€ç‰©ä»¶ã€‚ | | [`$dispatch`](#dispatch) | 建立 `CustomEvent` 並在內部以其 `.dispatchEvent()` 發é€è©² `CustomEvent`。 | | [`$nextTick`](#nexttick) | 在 Alpine 處ç†å¥½ DOM æ›´æ–° **之後** 執行給定的é‹ç®—å¼ã€‚ | | [`$watch`](#watch) | 當æ£åœ¨ã€Œç›£è½ - watchã€çš„屬性發生改動後,觸發給定的回呼函å¼ã€‚ | ## 贊助 <img width="33%" src="https://refactoringui.nyc3.cdn.digitaloceanspaces.com/tailwind-logo.svg" alt="Tailwind CSS"> **æƒ³åœ¨é€™è£¡é¡¯ç¤ºä½ çš„ Logo 嗎? [在 Twitter ä¸Šå‚³é€ DM](https://twitter.com/calebporzio)** ## VIP åƒèˆ‡è€… <table> <tr> <td align="center"><a href="http://calebporzio.com"><img src="https://avatars2.githubusercontent.com/u/3670578?v=4" width="100px;" alt="Caleb Porzio"/><br /><sub><b>Caleb Porzio</b></sub></a><br /><sub>(作者)</sub></td> <td align="center"><a href="https://github.com/HugoDF"><img src="https://avatars2.githubusercontent.com/u/6459679?v=4" width="100px;" alt="Hugo"/><br /><sub><b>Hugo</b></sub></a></td> <td align="center"><a href="https://github.com/ryangjchandler"><img src="https://avatars2.githubusercontent.com/u/41837763?v=4" width="100px;" alt="Ryan Chandler"/><br /><sub><b>Ryan Chandler</b></sub></a></td> <td align="center"><a href="https://github.com/SimoTod"><img src="https://avatars2.githubusercontent.com/u/8427737?v=4" width="100px;" alt="Simone Todaro"/><br /><sub><b>Simone Todaro</b></sub></a></td> </tr> </table> ### 指示詞 --- ### `x-data` **範例:** `<div x-data="{ foo: 'bar' }">...</div>` **çµæ§‹:** `<div x-data="[JSON 資料物件]">...</div>` `x-data` 宣告新的元件定義範åœã€‚使用 x-data 會告知 Alpine 以給定的資料物件來åˆå§‹åŒ–新的元件。 å¯æƒ³åƒæˆ Vue 元件ä¸çš„ `data` 屬性。 **æŠ½å‡ºå…ƒç´ é‚輯** å¯ä»¥å°‡è³‡æ–™ (與行為) 抽出æˆå¯é‡è¤‡ä½¿ç”¨çš„函å¼ï¼š ```html <div x-data="dropdown()"> <button x-on:click="open">é–‹å•Ÿ</button> <div x-show="isOpen()" x-on:click.away="close"> // 下拉é¸å–® </div> </div> <script> function dropdown() { return { show: false, open() { this.show = true }, close() { this.show = false }, isOpen() { return this.show === true }, } } </script> ``` > **å„ä½ Bundler 使用者**,請注æ„,Alpine.js å˜å–的函å¼éƒ½åœ¨å…¨åŸŸç¯„åœ (`window`),è¦åœ¨ `x-data` ä¸ä½¿ç”¨å‡½å¼æ™‚å¿…é ˆè¦é¡¯å¼å°‡å‡½å¼æŒ‡æ´¾è‡³ `window` 上。如 `window.dropdown = function () {}` (å› ç‚º Webpack, Rollup, Parcel …ç‰ä¸ï¼Œå®šç¾©çš„ `function` é è¨éƒ½åœ¨æ¨¡çµ„範åœå…§è€Œä¸æ˜¯ `window`)。 也å¯ä»¥ä½¿ç”¨ç‰©ä»¶è§£æ§‹ä¾†å°‡å¤šå€‹è³‡æ–™ç‰©ä»¶æ··åˆåœ¨ä¸€èµ·ï¼š ```html <div x-data="{...dropdown(), ...tabs()}"> ``` --- ### `x-init` **範例:** `<div x-data="{ foo: 'bar' }" x-init="foo = 'baz'"></div>` **çµæ§‹:** `<div x-data="..." x-init="[é‹ç®—å¼]"></div>` `x-init` æœƒåœ¨å…ƒç´ åˆå§‹åŒ–後執行é‹ç®—å¼ã€‚ 若想在 Alpine 將更新套用至 DOM **之後** æ‰åŸ·è¡Œç¨‹å¼ç¢¼çš„話 (é¡žä¼¼ VueJS ä¸çš„ `mounted()` Hook),å¯ä»¥å¾ž `x-init` ä¸å›žå‚³ä¸€å€‹å›žå‘¼å‡½å¼ï¼Œè©²å‡½å¼æœƒåœ¨å‡ºå¥—用至 DOM 後æ‰åŸ·è¡Œï¼š `x-init="() => { // æ¤è™•å¯å˜å– DOM åˆå§‹åŒ–完畢後的狀態 // }"` --- ### `x-show` **範例:** `<div x-show="open"></div>` **çµæ§‹:** `<div x-show="[é‹ç®—å¼]"></div>` `x-show` 會ä¾æ“šé‹ç®—å¼ç‚º `true` 或 `false` ä¾†åœ¨å…ƒç´ ä¸Šæœƒæ–°å¢žæˆ–ç§»é™¤ `display: none;` 樣å¼ã€‚ **x-show.transition** `x-show.transition` 是一個很方便的 API,å¯ä½¿ `x-show` 更與 CSS Transition é…åˆåœ°æ›´ä½³å®Œç¾Žã€‚ ```html <div x-show.transition="open"> 這裡的內容會轉æ›å…¥ã€è½‰æ›å‡ºã€‚ </div> ``` | 指示詞 | 說明 | | --- | --- | | `x-show.transition` | åŒæ™‚淡入淡出並縮放。 (opacity, scale: 0.95, timing-function: cubic-bezier(0.4, 0.0, 0.2, 1), duration-in: 150ms, duration-out: 75ms) | `x-show.transition.in` | 僅轉æ›å…¥ã€‚ | | `x-show.transition.out` | 僅轉æ›å‡ºã€‚ | | `x-show.transition.opacity` | 僅使用淡入淡出。 | | `x-show.transition.scale` | 僅使用縮放。 | | `x-show.transition.scale.75` | 自定 CSS ç¸®æ”¾è®Šæ› `transform: scale(.75)`. | | `x-show.transition.duration.200ms` | è¨å®šã€Œè½‰æ›å…¥ã€çš„變æ›ç‚º 200ms。轉æ›å‡ºå°‡è¨å®šç‚ºè©²å€¼çš„ä¸€åŠ (100ms). | | `x-show.transition.origin.top.right` | 自定 CSS 變æ›çš„起始 `transform-origin: top right`. | | `x-show.transition.in.duration.200ms.out.duration.50ms` | 為「轉æ›å…¥ã€èˆ‡ã€Œè½‰æ›å‡ºã€è¨å®šä¸åŒçš„æŒçºŒæ™‚間。 | > 備註:所有的轉æ›ä¿®é£¾è©žéƒ½å¯ä»¥äº’相組åˆä½¿ç”¨ã€‚å¯ä»¥é€™æ¨£ç”¨ (雖然很故æ„XD): `x-show.transition.in.duration.100ms.origin.top.right.opacity.scale.85.out.duration.200ms.origin.bottom.left.opacity.scale.95` > 備註:`x-show` 會ç‰å¾…所有å節點都完æˆè½‰æ›å¾Œã€‚若想跳éŽé€™å€‹è¡Œç‚ºï¼Œè«‹åŠ 上 `.immediate` 修飾詞: ```html <div x-show.immediate="open"> <div x-show.transition="open"> </div> ``` --- ### `x-bind` > 備註:也å¯ä»¥ä½¿ç”¨è¼ƒçŸçš„「:ã€èªžæ³•ï¼š `:type="..."` **範例:** `<input x-bind:type="inputType">` **çµæ§‹:** `<input x-bind:[屬性]="[é‹ç®—å¼]">` `x-bind` 將屬性值è¨ç‚º JavaScript é‹ç®—å¼çš„çµæžœã€‚é‹ç®—å¼ä¸å¯ä»¥å˜å–元件資料物件ä¸çš„所有索引éµï¼Œä¸”æ¯æ¬¡è³‡æ–™æœ‰æ›´æ–°æ™‚都更新。 > å‚™è¨»ï¼šå±¬æ€§ç¹«çµ **僅會** 在其相ä¾çš„值更新時æ‰æ›´æ–°ã€‚Alpine 框架會觀察資料的更改,並åµæ¸¬å“ªå€‹ç¹«çµèˆ‡è©²è³‡æ–™æœ‰é—œã€‚ **å°‡ `x-bind` 用在 Class 屬性** 當繫çµåœ¨ `class` 屬性時,`x-bind` çš„é‹ä½œæ¨¡å¼æœƒæœ‰é»žä¸åŒã€‚ å°æ–¼ Class,需è¦å‚³å…¥ä¸€å€‹ç‰©ä»¶ï¼Œå…¶ä¸ç‰©ä»¶çš„索引éµç‚º Class çš„å稱,而值則為布林é‹ç®—å¼ï¼Œç”¨ä¾†åˆ¤æ–·æ˜¯å¦è¦å¥—用該 Class å稱。 如: `<div x-bind:class="{ 'hidden': foo }"></div>` 在該例ä¸ï¼Œã€Œhiddenã€class åªæœƒåœ¨ `foo` 資料屬性的值為 `true` 時套用。 **å°‡ `x-bind` 用在布林屬性** `x-bind` 支æ´ä»¥èˆ‡æ•¸å€¼å±¬æ€§ç›¸åŒçš„æ–¹å¼ä¾†ç¹«çµå¸ƒæž—屬性,åªéœ€ä½¿ç”¨ä½œç‚ºåˆ¤æ–·æ¢ä»¶çš„變數或是任æ„å¯ä»¥è§£ç‚º `true` 或 `false` çš„ JavaScript é‹ç®—å¼å³å¯ã€‚ 如: ```html <!-- 如下程å¼: --> <button x-bind:disabled="myVar">點擊æ¤è™•</button> <!-- 當 myVar == true: --> <button disabled="disabled">點擊æ¤è™•</button> <!-- 當 myVar == false: --> <button>點擊æ¤è™•</button> ``` 該範例ä¸çš„程å¼æœƒä¾æ“š `myVar` 為 true 或 false 來新增或移除 disabled 屬性。 布林屬性的支æ´ä¿‚ä¾æ“š [HTML è¦æ ¼ (英文)](https://html.spec.whatwg.org/multipage/indices.html#attributes-3:boolean-attribute),如 `disabled`, `readonly`, `required`, `checked`, `hidden`, `selected`, `open` …ç‰ã€‚ **`.camel` 修飾詞** **範例:** `<svg x-bind:view-box.camel="viewBox">` 使用 `camel` 修飾詞會繫çµåˆ°å°æ‡‰é§å³°å‘½å法的屬性上。在上述例åä¸ï¼Œ `viewBox` 的值會被繫çµåˆ° `view-box` 所å°æ‡‰çš„ `viewBox` 屬性上。 --- ### `x-on` > 備註:也å¯ä»¥ä½¿ç”¨è¼ƒçŸçš„「@ã€èªžæ³•ï¼š`@click="..."` **範例:** `<button x-on:click="foo = 'bar'"></button>` **çµæ§‹:** `<button x-on:[事件]="[é‹ç®—å¼]"></button>` `x-on` 將事件監è½å™¨é™„åŠ è‡³å®£å‘Š `x-on` çš„å…ƒç´ ä¸Šã€‚ç•¶ç™¼å‡ºè©²äº‹ä»¶å¾Œï¼ŒåŸ·è¡Œè¨å®šç‚ºè©²äº‹ä»¶å€¼çš„å°æ‡‰ JavaScript é‹ç®—å¼ã€‚ 若在該é‹ç®—å¼ä¸æœ‰ä¿®æ”¹ä»»ä½•è³‡æ–™ï¼Œå‰‡å…¶ä»–ã€Œç¹«çµ Bindã€è©²è³‡æ–™å…ƒç´ 屬性也會一併更新。 > 備註:也å¯ä»¥æŒ‡å®šä¸€å€‹ JavaScript 函å¼å稱 **範例:** `<button x-on:click="myFunction"></button>` 與該程å¼ç¢¼ç›¸åŒ: `<button x-on:click="myFunction($event)"></button>` **`keydown` 修飾詞** **範例:** `<input type="text" x-on:keydown.escape="open = false">` å¯ä»¥å°‡æŒ‰éµé™„åŠ åˆ° `x-on:keydown` 指示詞後é¢ä¾†æŒ‡å®šè¦ç›£è½çš„按éµã€‚請注æ„,該修飾詞使用的是 `-` 號分隔命å (kebab-cased) 版本的 `Event.key` 值。 如: `enter`, `escape`, `arrow-up`, `arrow-down` > 備註:也å¯ä»¥ç›£è½ä½¿ç”¨ç³»çµ±ä¿®é£¾è©žçš„按éµçµ„åˆï¼Œå¦‚: `x-on:keydown.cmd.enter="foo"` **`.away` 修飾詞** **範例:** `<div x-on:click.away="showModal = false"></div>` 當有 `.away` 修飾詞時,將åªæœƒåœ¨ç”±éžè©²å…ƒç´ æˆ–è©²å…ƒç´ åç¯€é»žçš„å…¶ä»–å…ƒç´ ç™¼å‡ºäº‹ä»¶æ™‚åŸ·è¡Œäº‹ä»¶è™•ç†å¸¸å¼ã€‚ é©åˆç”¨åœ¨è®“使用者點擊元件外é¢ä¾†é—œé–‰ä¸‹æ‹‰é¸å–®èˆ‡å¼·åˆ¶å›žæ‡‰è¦–窗時隱è—這些元件ç‰æƒ…æ³ã€‚ **`.prevent` 修飾詞** **範例:** `<input type="checkbox" x-on:click.prevent>` 在事件監è½å™¨åŠ 上 `.prevent` æœƒåœ¨è§¸ç™¼çš„äº‹ä»¶ä¸Šå‘¼å« `preventDefault`。在上述範例ä¸ï¼Œä½¿ç”¨ `.prevent` 則代表該多é¸æ¡†åœ¨ä½¿ç”¨è€…點擊後ä¸æœƒè¢«å¯¦éš›é¸ä¸ã€‚ **`.stop` 修飾詞** **範例:** `<div x-on:click="foo = 'bar'"><button x-on:click.stop></button></div>` 在事件監è½å™¨åŠ 上 `.stop` æœƒåœ¨è§¸ç™¼çš„äº‹ä»¶ä¸Šå‘¼å« `stopPropagation`。在上述範例ä¸ï¼Œä½¿ç”¨ `.stop` 則代表「clickã€äº‹ä»¶è§¸ç™¼ä¹‹å¾Œä¸æœƒå¾žåº•éƒ¨ Bubble 到外層的 `<div>` 。æ›å¥è©±ä¾†èªªï¼Œä½¿ç”¨è€…點擊按鈕 (Button) 後, `foo` 的值ä¸æœƒè¢«è¨ç‚º `'bar'`。 **`.self` 修飾詞** **範例:** `<div x-on:click.self="foo = 'bar'"><button></button></div>` 在事件監è½å™¨åŠ 上 `.self` 則åªæœƒåœ¨ `$event.target` æ˜¯è©²å…ƒç´ çš„æ™‚å€™æ‰è§¸ç™¼ç›£è½å™¨ã€‚在上述範例ä¸ï¼Œå‰‡è¡¨ç¤ºå¾žæŒ‰éˆ• Bubble 到外層 `<div>` 上來的「clickã€äº‹ä»¶ **ä¸æœƒ** 執行監è½å™¨ã€‚ **`.window` 修飾詞** **範例:** `<div x-on:resize.window="isOpen = window.outerWidth > 768 ? false : open"></div>` 在事件監è½å™¨åŠ 上 `.window` 會將監è½å™¨å®‰è£åˆ°å…¨åŸŸçš„ window 物件ä¸ï¼Œè€Œä¸æ˜¯å®£å‘Šè©²ç›£è½å™¨çš„ DOM 物件上。é©åˆç”¨åœ¨ç•¶æœ‰å…¶ä»–æ±è¥¿ä¿®æ”¹äº† window 而需è¦ä¿®æ”¹å…ƒä»¶ç‹€æ…‹çš„時候,如縮放事件。在本例ä¸ï¼Œç•¶è¦–窗調整為大於 768 åƒç´ 寬時,程å¼æœƒé—œé–‰å¼·åˆ¶å›žæ‡‰è¦–窗或下拉é¸å–®ï¼Œå¦å‰‡æœƒç¹¼çºŒç¶æŒåŽŸæœ¬çš„狀態。 >備註:也å¯ä»¥ä½¿ç”¨ `.document` 修飾詞來將監è½å™¨é™„åŠ åˆ° `document` 而ä¸æ˜¯ `window` 上 **`.once` 修飾詞** **範例:** `<button x-on:mouseenter.once="fetchSomething()"></button>` 在事件監è½å™¨åŠ 上 `.onece` 則å¯ä»¥ç¢ºä¿åªæœƒå‘¼å«ä¸€æ¬¡äº‹ä»¶ç›£è½å™¨ã€‚é©åˆç”¨ä¾†åšä¸€äº›åªéœ€è¦åšä¸€æ¬¡å°±å¥½çš„事,如å–å¾— HTML 部分ç‰ã€‚ **`.passive` 修飾詞** **範例:** `<button x-on:mousedown.passive="interactive = true"></button>` 在事件監è½å™¨åŠ 上 `.passive` 修飾詞則å¯è®“監è½å™¨æˆç‚ºè¢«å‹•ï¼Œä¹Ÿå°±è¡¨ç¤ºåœ¨æ‰€æœ‰è™•ç†çš„事件上 `preventDefault()` 都將ä¸æœƒæœ‰ä»»ä½•ä½œç”¨ã€‚å¯ä»¥ç”¨åœ¨å¦‚æå‡è§¸æŽ§è£ç½®ä¸Šçš„滾動效能ç‰ç›®çš„。 **`.debounce` 修飾詞** **範例:** `<input x-on:input.debounce="fetchSomething()">` `.debounce` 修飾詞å¯ä»¥è©¦äº‹ä»¶ç›£è½å™¨ã€Œæ¶ˆé™¤å½ˆè·³ (Debouce)ã€ã€‚也就是說,該處ç†å¸¸å¼æœƒç‰åˆ°ä¸Šä¸€å€‹äº‹ä»¶è§¸ç™¼å¾Œçš„一段時間後æ‰åŸ·è¡Œã€‚當處ç†å¸¸å¼æº–備好å¯åŸ·è¡Œå¾Œï¼Œå‰‡æœƒåŸ·è¡Œä¸Šä¸€å€‹è™•ç†å¸¸å¼å‘¼å«ã€‚ é è¨çš„消除彈跳「ç‰å¾…ã€æ™‚間為 250 毫秒。 è‹¥è¦è‡ªå®šç‰å¾…事件,則å¯ä½¿ç”¨å¦‚下方法指定: ``` <input x-on:input.debounce.750="fetchSomething()"> <input x-on:input.debounce.750ms="fetchSomething()"> ``` **`.camel` 修飾詞** **範例:** `<input x-on:event-name.camel="doSomething()">` 使用 `.camel` 修飾詞來監è½ä»¥é§å³°å‘½å法命å的事件。在上述例åä¸ï¼Œå…ƒç´ 觸發 `eventName` 事件後會執行該é‹ç®—å¼ã€‚ --- ### `x-model` **範例:** `<input type="text" x-model="foo">` **çµæ§‹:** `<input type="text" x-model="[è³‡æ–™é …ç›®]">` `x-model` å¯ç”¨ä¾†åœ¨å…ƒç´ åŠ ä¸Šã€Œé›™å‘è³‡æ–™ç¹«çµ (Two-way Data Binding)ã€ã€‚ä¹Ÿå°±æ˜¯èªªï¼Œè¼¸å…¥å…ƒç´ çš„å€¼æœƒä¿æŒèˆ‡å…ƒä»¶è³‡æ–™é …目的值åŒæ¥ã€‚ > 備註:`x-model` 很è°æ˜Žï¼Œæœƒåµæ¸¬æ–‡å—輸入框ã€å¤šé¸æ¡†ã€å–®é¸æ¡†ã€Textareaã€ä¸‹æ‹‰é¸å–®èˆ‡å¤šé‡é¸å–å€åŸŸç‰ã€‚`x-model` çš„é‹ä½œæ–¹å¼åœ¨å„個情æ³ä¸‹æ‡‰è©²éƒ½[與 Vue 相åŒ](https://vuejs.org/v2/guide/forms.html)。 **`.debounce` 修飾詞** **範例:** `<input x-model.debounce="search">` `debounce` 修飾詞å¯ä»¥åœ¨æ•¸å€¼æ›´æ–°ä¸ŠåŠ 上「消除彈跳 (Debounce)ã€ã€‚也就是說,從上一次事件觸發之後的一段時間之後æ‰æœƒå‘¼å«äº‹ä»¶è™•ç†å¸¸å¼ã€‚當處ç†å¸¸å¼å¯å‘¼å«å¾Œï¼Œæ‰æœƒåŸ·è¡Œä¸Šä¸€å€‹è™•ç†å¸¸å¼å‘¼å«ã€‚ é è¨çš„消除彈跳「ç‰å¾…ã€æ™‚間為 250 毫秒。 è‹¥è¦è‡ªå®šç‰å¾…時間,則å¯ç”¨ä¸‹åˆ—æ–¹å¼æŒ‡å®šï¼š ``` <input x-model.debounce.750="search"> <input x-model.debounce.750ms="search"> ``` --- ### `x-text` **範例:** `<span x-text="foo"></span>` **çµæ§‹:** `<span x-text="[é‹ç®—å¼]"` `x-text` é¡žä¼¼ `x-bind` ,但更新的ä¸æ˜¯å…ƒç´ 的屬性,而是 `innerText`。 --- ### `x-html` **範例:** `<span x-html="foo"></span>` **çµæ§‹:** `<span x-html="[é‹ç®—å¼]"` `x-text` é¡žä¼¼ `x-bind` ,但更新的ä¸æ˜¯å…ƒç´ 的屬性,而是 `innerHTML`。 > :warning: **絕å°ä¸è¦ç”¨åœ¨ä½¿ç”¨è€…輸入的內容,且請åªç”¨åœ¨å¯ä¿¡ä»»çš„內容上。** :warning: > > 從第三方來æºå‹•æ…‹å‘ˆç¾ HTML å¯èƒ½æœƒå°Žè‡´ [XSS (英文)](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting) æ¼æ´žã€‚ --- ### `x-ref` **範例:** `<div x-ref="foo"></div><button x-on:click="$refs.foo.innerText = 'bar'"></button>` **çµæ§‹:** `<div x-ref="[åƒç…§å稱]"></div><button x-on:click="$refs.[ref name].innerText = 'bar'"></button>` `x-ref` æ供從元件上å–得原始 DOM å…ƒç´ çš„ç°¡ä¾¿æ–¹æ³•ã€‚åªè¦åœ¨å…ƒç´ 上è¨å®š `x-ref` 屬性,就å¯ä»¥åœ¨æ‰€æœ‰äº‹ä»¶è™•ç†å¸¸å¼ä¸é€šéŽ `$refs` 物件來å–å¾—è©²å…ƒç´ ã€‚ 除了è¨å®š ID 並在å„個地方使用 `document.querySelector`,使用 `x-ref` å¯ä½œç‚ºæ›¿ä»£æ–¹æ³•ã€‚ > 備註:若有需è¦ä¹Ÿå¯ä»¥åœ¨ `x-ref` 上繫çµå‹•æ…‹æ•¸å€¼ï¼š`<span :x-ref="item.id"></span>`。 --- ### `x-if` **範例:** `<template x-if="true"><div>ä¸€äº›å…ƒç´ </div></template>` **çµæ§‹:** `<template x-if="[é‹ç®—å¼]"><div>ä¸€äº›å…ƒç´ </div></template>` 但é‡åˆ°ä¸€äº› `x-show` ä¸åˆç”¨çš„æƒ…æ³ (`x-show` 會在表é”å¼ç‚º false æ™‚å°‡å…ƒç´ è¨ç‚º `display: none`),則å¯ä»¥ä½¿ç”¨ `x-if` ä¾†å°‡å…ƒç´ å®Œå…¨å¾ž DOM ä¸ç§»é™¤ã€‚ 但è¦æ³¨æ„,`x-if` å¿…é ˆè¦ç”¨åœ¨ `<template></template>` æ¨™ç±¤ä¸Šï¼Œå› ç‚º Alpine ä¸ä½¿ç”¨è™›æ“¬ DOM。這種實作方å¼å¯ä¿æŒ Alpine 簡陋,並使用真的 DOM 來處ç†å‹•æ…‹ (Magic) 的部分。 > 備註:使用 `x-if` 時 `<template></template>` 標籤ä¸å¿…é ˆåªèƒ½æœ‰å–®ä¸€æ ¹å…ƒç´ 。 > 備註:如果è¦åœ¨ `svg` 標籤ä¸ä½¿ç”¨ `template`,則需è¦åœ¨ Alpine.js åˆå§‹åŒ–å‰åŸ·è¡Œä¸€æ®µ [polyfill](https://github.com/alpinejs/alpine/issues/637#issuecomment-654856538)。 --- ### `x-for` **範例:** ```html <template x-for="item in items" :key="item"> <div x-text="item"></div> </template> ``` > 備註:`:key` 繫çµç‚ºéžå¿…填。但「強烈ã€å»ºè°è¦åŠ 上。 `x-for` é©ç”¨æ–¼éœ€è¦ç‚ºé™£åˆ—ä¸æ¯å€‹é …目建立新 DOM 節點的情æ³ã€‚用法看起來應該跟 Vue ä¸çš„ `v-for` 類似,但唯一ä¸åŒçš„地方就是è¦æ”¾åœ¨ `template` 標籤上而ä¸æ˜¯ä¸€èˆ¬çš„ DOM å…ƒç´ ã€‚ 若需è¦å˜å–ç›®å‰è¿ä»£çš„索引,則å¯ä½¿ç”¨ä¸‹åˆ—語法: ```html <template x-for="(item, index) in items" :key="index"> <!-- 若有需è¦ä¹Ÿå¯ä»¥åœ¨è¿ä»£ä¸åƒç…§ã€Œindexã€ã€‚ --> <div x-text="index"></div> </template> ``` > 備註:使用 `x-for` 時 `<template></template>` 標籤ä¸å¿…é ˆåªèƒ½æœ‰å–®ä¸€æ ¹å…ƒç´ 。 > 備註:如果è¦åœ¨ `svg` 標籤ä¸ä½¿ç”¨ `template`,則需è¦åœ¨ Alpine.js åˆå§‹åŒ–å‰åŸ·è¡Œä¸€æ®µ [polyfill](https://github.com/alpinejs/alpine/issues/637#issuecomment-654856538)。 #### 巢狀嵌套 `x-for` å¯ä»¥åµŒå¥—多層 `x-for` 迴圈,但æ¯å€‹è¿´åœˆéƒ½ **å¿…é ˆ** æ”¾åœ¨ä¸€å€‹å…ƒç´ å…§ï¼Œå¦‚ï¼š ```html <template x-for="item in items"> <div> <template x-for="subItem in item.subItems"> <div x-text="subItem"></div> </template> </div> </template> ``` --- ### `x-transition` **範例:** ```html <div x-show="open" x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 transform scale-90" x-transition:enter-end="opacity-100 transform scale-100" x-transition:leave="transition ease-in duration-300" x-transition:leave-start="opacity-100 transform scale-100" x-transition:leave-end="opacity-0 transform scale-90" >...</div> ``` ```html <template x-if="open"> <div x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 transform scale-90" x-transition:enter-end="opacity-100 transform scale-100" x-transition:leave="transition ease-in duration-300" x-transition:leave-start="opacity-100 transform scale-100" x-transition:leave-end="opacity-0 transform scale-90" >...</div> </template> ``` > 上述範例使用了 [Tailwind CSS](https://tailwindcss.com) çš„ Class Alpine ä¸æ供了 6 種ä¸åŒçš„變æ›æŒ‡ç¤ºè©žï¼Œå¯ç”¨æ–¼åœ¨å…ƒç´ 變æ›çš„「hidden éš±è—ã€èˆ‡ã€Œshown 顯示ã€ç‹€æ…‹é–“çš„å„個階段套用 Class。這些指示詞å¯ç”¨åœ¨ `x-show` **與** `x-if` 上。 這些行為都與 VueJS çš„ transition 指示詞很類似,但ä¸åŒçš„地方則是使用了ä¸åŒçš„å稱: | 指示詞 | 說明 | | --- | --- | | `:enter` | 套用於整個 Enter 階段。 | | `:enter-start` | åœ¨å…ƒç´ æ’å…¥å‰æ–°å¢žï¼Œä¸¦åœ¨å…ƒç´ æ’入的 1 幀後刪除。 | | `:enter-end` | åœ¨å…ƒç´ æ’入後 (與 `enter-start` 刪除åŒæ™‚) 1 幀時新增,變æ›æˆ–å‹•ç•«çµæŸæ™‚刪除。 | | `:leave` | 套用於整個 Leave 階段。 | | `:leave-start` | 在 Leave 變æ›è§¸ç™¼å¾Œç«‹åˆ»æ–°å¢žã€ä¸¦åœ¨ 1 幀後刪除。 | | `:leave-end` | 在 Leave 變æ›è§¸ç™¼å¾Œ (與 `leave-start` 刪除åŒæ™‚) 1 幀新增,並在變æ›æˆ–å‹•ç•«çµæŸæ™‚刪除。 | --- ### `x-spread` **範例:** ```html <div x-data="dropdown()"> <button x-spread="trigger">開啟下拉é¸å–®</button> <span x-spread="dialogue">下拉é¸å–®å…§å®¹</span> </div> <script> function dropdown() { return { open: false, trigger: { ['@click']() { this.open = true }, }, dialogue: { ['x-show']() { return this.open }, ['@click.away']() { this.open = false }, } } } </script> ``` `x-spread` å¯ç”¨ä¾†å°‡å…ƒç´ çš„ Alpine 繫çµæˆªå–到å¯é‡è¤‡ä½¿ç”¨çš„å…ƒç´ ä¸ã€‚ å…ƒç´ çš„ç´¢å¼•éµç‚ºæŒ‡ç¤ºè©ž (å¯ä»¥æ˜¯ä»»ä½•æŒ‡ç¤ºè©žï¼ŒåŒ…å«ä¿®é£¾è©ž)ï¼Œè€Œå…ƒç´ å€¼å‰‡ç‚ºç”± Alpine å–值的回呼函å¼ã€‚ > 備註:x-spread 唯一è¦æ³¨æ„的就是與 `x-for` æé…使用的情æ³ã€‚當被「spreadã€çš„指示詞是 `x-for`,則回呼內回傳的應該è¦æ˜¯é‹ç®—å¼å—串。如: `['x-for']() { return 'item in items' }`. --- ### `x-cloak` **範例:** `<div x-data="{}" x-cloak></div>` `x-cloak` 屬性會在 Alpine åˆå§‹åŒ–å¾Œå¾žå…ƒç´ ä¸Šç§»é™¤ã€‚å¯ä»¥ç”¨ä¾†éš±è—還未åˆå§‹åŒ–çš„ DOM å…ƒç´ ã€‚é€šå¸¸ä½¿ç”¨ä¸‹åˆ—å…¨åŸŸæ¨£å¼ï¼š ```html <style> [x-cloak] { display: none; } </style> ``` ### é”法屬性 > 除了 `$el` 是例外,所有的é”法屬性 **在 `x-data` ä¸éƒ½ç„¡æ³•ä½¿ç”¨**ï¼Œå› ç‚ºå…ƒç´ é‚„æœªåˆå§‹åŒ–。 --- ### `$el` **範例:** ```html <div x-data> <button @click="$el.innerHTML = 'foo'">這裡的內容會å–代為「fooã€</button> </div> ``` `$el` 是å¯ç”¨ä¾†å–å¾—å…ƒä»¶æ ¹ DOM 節點的é”法屬性。 ### `$refs` **範例:** ```html <span x-ref="foo"></span> <button x-on:click="$refs.foo.innerText = 'bar'"></button> ``` `$refs` 是å¯ç”¨ä¾†å–得元件內以 `x-ref` 標記的 DOM å…ƒç´ ä¹‹é”法屬性。é©åˆç”¨åœ¨è¦æ‰‹å‹•æ“作 DOM å…ƒç´ çš„æƒ…æ³ã€‚ --- ### `$event` **範例:** ```html <input x-on:input="alert($event.target.value)"> ``` `$event` 是å¯åœ¨äº‹ä»¶ç›£è½å™¨å…§å–å¾—ç€è¦½å™¨åŽŸç”Ÿã€ŒEventã€ç‰©ä»¶çš„é”法屬性。 > 備註:$event 屬性åªå¯åœ¨ DOM é‹ç®—å¼ä¸ä½¿ç”¨ã€‚ 若有需è¦åœ¨ JavaScript 函å¼ä¸å˜å– $event,則å¯ä»¥ç›´æŽ¥å°‡ $event 傳入: `<button x-on:click="myFunction($event)"></button>` --- ### `$dispatch` **範例:** ```html <div @custom-event="console.log($event.detail.foo)"> <button @click="$dispatch('custom-event', { foo: 'bar' })"> <!-- 點擊後會 console.log "bar" --> </div> ``` **æœ‰é—œäº‹ä»¶å‚³æ’ (Event Propagation)** 請注æ„,由於 [Event Bubbling (英語)](https://en.wikipedia.org/wiki/Event_bubbling),當有需è¦æˆªå–從相åŒå±¤ç´šç¯€é»žè§¸ç™¼çš„事件時,則需è¦åŠ 上 [`.window`](#x-on) 修飾詞: **範例:** ```html <div x-data> <span @custom-event="console.log($event.detail.foo)"></span> <button @click="$dispatch('custom-event', { foo: 'bar' })"> <div> ``` > ä¸Šè¿°ç¯„ä¾‹ç„¡æ•ˆï¼Œå› ç‚º `custom-event` 觸發的時候,會傳æ’到共åŒæ¯ç´šç¯€é»žï¼Œå³ `div`。 **分派至元件** 也å¯ä»¥é€šéŽå‰›æ‰é‚£å€‹æŠ€å·§ä¾†åœ¨å…ƒä»¶é–“互相æºé€šï¼š **範例:** ```html <div x-data @custom-event.window="console.log($event.detail)"></div> <button x-data @click="$dispatch('custom-event', 'Hello World!')"> <!-- 點擊後會 console.log "Hello World!". --> ``` `$dispatch` 是建立 `CustomEvent` 並在內部使用 `.dispatchEvent()` 分派的æ·å¾‘方法。還有其他許多通éŽè‡ªå®šäº‹ä»¶ä¾†åœ¨å…ƒä»¶é–“傳éžè³‡æ–™çš„例å。請 [åƒè€ƒæ¤è™• (英文)](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events) 以çžè§£æ›´å¤šæœ‰é—œä¸åŒç€è¦½å™¨ä¸çš„ `CustomEvent` 資訊。 å¯ä»¥æ³¨æ„到放在第二個åƒæ•¸çš„資料 `$dispatch('some-event', { some: 'data' })`,在新事件上å¯é€šéŽã€Œdetailã€å±¬æ€§ä¾†å–得:`$event.detail.some`ã€‚å°‡è‡ªå®šäº‹ä»¶è³‡æ–™é™„åŠ åˆ° `.detail` 屬性是在ç€è¦½å™¨ä¸ `CustomEvent` 的標準實è¸ã€‚更多資訊請 [åƒè€ƒæ¤è™• (英文)](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail)。 也å¯ä»¥ä½¿ç”¨ `$dispatch()` 來觸發 `x-model` 繫çµçš„資料更新。如: ```html <div x-data="{ foo: 'bar' }"> <span x-model="foo"> <button @click="$dispatch('input', 'baz')"> <!-- 點擊按鈕後,`x-model` 會抓到 Bubbing 的「inputã€äº‹ä»¶ï¼Œä¸¦å°‡ foo 更新為「baz〠--> </span> </div> ``` > 備註:$dispatch 屬性åªå¯åœ¨ DOM é‹ç®—å¼ä¸ä½¿ç”¨ã€‚ 若有需è¦åœ¨ JavaScript 函å¼ä¸å˜å– $dispatch,則å¯ä»¥ç›´æŽ¥å°‡ $dispatch 傳入: `<button x-on:click="myFunction($dispatch)"></button>` --- ### `$nextTick` **範例:** ```html <div x-data="{ fruit: 'apple' }"> <button x-on:click=" fruit = 'pear'; $nextTick(() => { console.log($event.target.innerText) }); " x-text="fruit" ></button> </div> ``` é€šéŽ `$nextTick` é”法屬性則å¯ä»¥åœ¨ Alpine åšå‡º DOM æ›´æ–° **之後** æ‰åŸ·è¡ŒæŒ‡å®šçš„é‹ç®—å¼ã€‚é©ç”¨æ–¼éœ€è¦åœ¨è³‡æ–™å應到 DOM 上後æ‰è¦èˆ‡ DOM 互動的情æ³ã€‚ --- ### `$watch` **範例:** ```html <div x-data="{ open: false }" x-init="$watch('open', value => console.log(value))"> <button @click="open = ! open">é–‹å•Ÿï¼é—œé–‰</button> </div> ``` å¯é€šéŽ `$watch` é”æ³•æ–¹æ³•ä¾†ã€Œç›£è½ (Watch)ã€å…ƒä»¶å±¬æ€§ã€‚在上述例åä¸ï¼Œç•¶æŒ‰éˆ•é»žæ“Šå¾Œ `open` 會該表,接著會指定給定的回呼並以新的值來執行 `console.log`。 ## 安全性 Security è‹¥ä½ ç™¼ç¾å®‰å…¨æ€§æ¼æ´žï¼Œè«‹å‚³é€é›»å郵件至 [calebporzio@gmail.com]()。 Alpine 仰賴與使用 `Function` 物件來自定實作以å°æŒ‡ç¤ºè©žå–值。雖然比 `eval()` 來的安全,但這個åšæ³•ä¾ç„¶åœ¨ä¸€äº›ç’°å¢ƒä¸‹è¢«ç¦æ¢ï¼Œå¦‚ Google Chrome App 使用了é™åˆ¶æ€§çš„ CSP (Content Security Policy,內容安全性原則)。 若在需è¦è™•ç†æ©Ÿæ•è³‡æ–™çš„網站上使用 Alpine,且需è¦è¨å®š [CSP (英語)](https://csp.withgoogle.com/docs/strict-csp.html)ï¼Œå‰‡å¿…é ˆåœ¨ CSP è¨å®šä¸åŠ 上 `unsafe-eval`。è¨å®šæ£ç¢ºä¸”å …å›ºçš„åŽŸå‰‡æœ‰åŠ©æ–¼ä¿è·ä½¿ç”¨è€…在處ç†å€‹äººè³‡æ–™æˆ–財務資料上的安全。 由於原則è¨å®šæœƒå¥—用至é é¢ä¸çš„所有腳本,所以也應注æ„è¦å°å¿ƒå¯©é–±ç¶²ç«™ä¸å¼•å…¥çš„其他外部函å¼åº«ï¼Œä»¥ç¢ºä¿èƒ½ä¿¡ä»»é€™äº›å‡½å¼åº«ï¼Œä¸¦é¿å…這些函å¼åº«å¼•ç™¼ XSS æ¼æ´žæˆ–使用 `eval()` 函å¼ä¾†èª¿æ•´ DOM 或在é é¢ä¸æ³¨å…¥æƒ¡æ„程å¼ç¢¼ã€‚ ## 授權æ¢æ¬¾ License Copyright © 2019-2021 Caleb Porzio and contributors Licensed under the MIT license, see [LICENSE.md](LICENSE.md) for details. é€éŽ MIT 授權æ¢æ¬¾æŽˆæ¬Šï¼Œè©³æƒ…è«‹åƒé–± [LICENSE.md](LICENSE.md)。