@pardnchiu/quickui
Advanced tools
Comparing version 0.6.2 to 0.6.3
{ | ||
"name": "@pardnchiu/quickui", | ||
"version": "0.6.2", | ||
"version": "0.6.3", | ||
"description": "A web frontend framework that supports conditional and loop rendering, data binding, monitoring data changes, and automatic rendering. Previously known as QuickUI.", | ||
@@ -29,8 +29,8 @@ "main": "dist/QuickUI.js", | ||
"front-end-framework", | ||
"quickui", | ||
"UI-framework", | ||
"data-binding", | ||
"virtual-DOM", | ||
"loop-rendering", | ||
"conditional-rendering" | ||
"conditional-rendering", | ||
"邱敬幃", | ||
"pardnchiu" | ||
], | ||
@@ -37,0 +37,0 @@ "author": { |
906
README.md
@@ -1,7 +0,10 @@ | ||
<img src="./dist/logo.png" width=80> | ||
<img src="https://quickui.pardn.io/static/image/logo.png" width=80> | ||
# QuickUI | ||
# QuickUI: Lightweight Frontend Framework | ||
(Formerly known as PDQuickUI, renamed to QuickUI starting from version `0.6.0`) | ||
> [!NOTE] | ||
> (Formerly known as PDQuickUI, renamed to QuickUI starting from version `0.6.0`) | ||
> QuickUI is a front-end rendering framework built with pure JavaScript. By integrating virtual DOM technology, it enhances rendering performance, achieving rapid data responsiveness and automatic updates. | ||
![tag](https://img.shields.io/badge/tag-JavaScript%20Library-bb4444) | ||
@@ -14,817 +17,162 @@ ![size](https://img.shields.io/github/size/pardnchiu/QuickUI/dist%2FQuickUI.js)<br> | ||
`QuickUI` is a front-end rendering framework derived from [PDRenderKit](https://github.com/pardnchiu/PDRenderKit), focusing on enhancing front-end framework features.<br> | ||
By integrating a virtual DOM, it rewrites the rendering logic to improve rendering efficiency, enabling faster data observation and automatic updates.<br> | ||
This project removes the `prototype` extensions from `PDRenderKit` to ensure compatibility and performance, making it suitable for complex applications.<br> | ||
It provides both `module` and non-`module` versions and changes the license from `GPL-3.0` in `PDRenderKit` to `MIT`. | ||
## Features | ||
- **Clear Architecture**: Separates UI from data logic, making it easier to maintain. | ||
- **Code Simplicity**: Reduces redundant code and enhances readability. | ||
- **Automatic Rendering**: Monitors data changes and updates automatically, minimizing manual operations. | ||
- **Lightweight**: Maintains full functionality within a file size of less than `20kb`. | ||
### Efficient Virtual DOM | ||
- Precise diffing algorithm for efficient DOM updates | ||
- Smart attribute patching system that updates only changed values | ||
- Intelligent child node comparison for minimal DOM manipulation | ||
## Installation | ||
### Reactive Data Handling | ||
- Deep data monitoring system for immediate state tracking | ||
- Automatic UI updates on data changes, no manual operation needed | ||
- Smart caching system to prevent unnecessary re-renders | ||
- Support for nested data structures with reactive handling | ||
- **Install from npm** | ||
```bash | ||
npm i @pardnchiu/quickui | ||
``` | ||
- **Include from CDN** | ||
- **Directly include `QuickUI`** | ||
```html | ||
<!-- Version 0.6.0 and above --> | ||
<script src="https://cdn.jsdelivr.net/npm/@pardnchiu/quickui@[VERSION]/dist/QuickUI.js"></script> | ||
### Advanced Template Features | ||
- Built-in internationalization (i18n) support for easy localization | ||
- Dynamic template loading with asynchronous processing | ||
- Powerful expression system supporting calculations, dates, and text processing | ||
- Comprehensive directive system for flexible DOM manipulation | ||
<!-- Version 0.5.4 and below --> | ||
<script src="https://cdn.jsdelivr.net/npm/pdquickui@[VERSION]/dist/PDQuickUI.js"></script> | ||
``` | ||
- **Module Version** | ||
```javascript | ||
// Version 0.6.0 and above | ||
import { QUI } from "https://cdn.jsdelivr.net/npm/@pardnchiu/quickui@[VERSION]/dist/QuickUI.esm.js"; | ||
// Version 0.5.4 and below | ||
import { QUI } from "https://cdn.jsdelivr.net/npm/pdquickui@[VERSION]/dist/PDQuickUI.module.js"; | ||
``` | ||
### Performance Optimizations | ||
- Lazy loading for images and SVG content to improve load times | ||
- Minimal file size with zero external dependencies | ||
- Smart event delegation and resource cleanup for optimized memory usage | ||
## Usage | ||
## Documentation | ||
- Initialize `QUI` | ||
```Javascript | ||
const app = new QUI({ | ||
id: "", // Specify rendering element | ||
data: { | ||
// Custom DATA | ||
}, | ||
event: { | ||
// Custom EVENT | ||
}, | ||
when: { | ||
before_render: function () { | ||
// Stop rendering | ||
}, | ||
rendered: function () { | ||
// Rendered | ||
}, | ||
before_update: function () { | ||
// Stop updating | ||
}, | ||
updated: function () { | ||
// Updated | ||
}, | ||
before_destroy: function () { | ||
// Stop destruction | ||
}, | ||
destroyed: function () { | ||
// Destroyed | ||
} | ||
} | ||
}); | ||
``` | ||
- Website: [quickui.pardn.io](https://quickui.pardn.io) | ||
- Documentation: [quickui.pardn.io/doc.html](https://quickui.pardn.io/doc.html) | ||
## Overview | ||
Automatic Rendering: Automatically reloads when data changes are detected. | ||
## Installation | ||
<details> | ||
<summary>Attributes Overview</summary> | ||
### Install via npm | ||
```bash | ||
npm i @pardnchiu/quickui | ||
``` | ||
| Attribute | Description | | ||
| --- | --- | | ||
| `{{value}}` | Inserts text into HTML tags and automatically updates with data changes. | | ||
| `:path` | Used with the `temp` tag to load HTML fragments from external files into the current page. | | ||
| `:html` | Replaces the element's `innerHTML` with text. | | ||
| `:for` | Supports formats like `item in items`, `(item, index) in items`, `(key, value) in object`. Iterates over data collections to generate corresponding HTML elements. | | ||
| `:if`<br>`:else-if`<br>`:elif`<br>`:else` | Displays or hides elements based on specified conditions, enabling branching logic. | | ||
| `:model` | Binds data to form elements (e.g., `input`), updating data automatically when input changes. | | ||
| `:hide` | Hides elements based on specific conditions. | | ||
| `:animation` | Specifies transition effects for elements, such as `fade-in` or `expand`, to enhance user experience. | | ||
| `:mask` | Controls block loading animations, supporting `true\|false\|1\|0`, to enhance dynamic visual effects during loading. | | ||
| `:[attr]` | Sets element attributes, such as `ID`, `class`, image source, etc.<br>Examples: `:id`/`:class`/`:src`/`:alt`/`:href`... | | ||
| `:[css]` | Sets element CSS, such as margin, padding, etc. Examples: `:background-color`, `:opacity`, `:margin`, `:top`, `:position`... | | ||
| `@[event]` | Adds event listeners that trigger specified actions upon activation.<br>Examples: `@click`/`@input`/`@mousedown`... | | ||
### Include via CDN | ||
</details> | ||
#### Include the `QuickUI` library | ||
```html | ||
<!-- Version 0.6.0 and above --> | ||
<script src="https://cdn.jsdelivr.net/npm/@pardnchiu/quickui@[VERSION]/dist/QuickUI.js"></script> | ||
<details> | ||
<summary>Text Replacement</summary> | ||
<!-- Version 0.5.4 and below --> | ||
<script src="https://cdn.jsdelivr.net/npm/pdquickui@[VERSION]/dist/PDQuickUI.js"></script> | ||
``` | ||
### `{{value}}` | ||
#### Module version | ||
```javascript | ||
// Version 0.6.0 and above | ||
import { QUI } from "https://cdn.jsdelivr.net/npm/@pardnchiu/quickui@[VERSION]/dist/QuickUI.esm.js"; | ||
- index.html | ||
```HTML | ||
<h1>{{ title }}</h1> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
title: "test" | ||
} | ||
}); | ||
</script> | ||
``` | ||
- Result | ||
```HTML | ||
<body id="app"> | ||
<h1>test</h1> | ||
</body> | ||
``` | ||
// Version 0.5.4 and below | ||
import { QUI } from "https://cdn.jsdelivr.net/npm/pdquickui@[VERSION]/dist/PDQuickUI.module.js"; | ||
``` | ||
*** | ||
## How to use | ||
### `:html` | ||
- index.html | ||
```HTML | ||
<section :html="html"></section> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
html: "<b>innerHtml</b>" | ||
} | ||
}); | ||
</script> | ||
``` | ||
- Result | ||
```HTML | ||
<body id="app"> | ||
<section> | ||
<b>innerHtml</b> | ||
</section> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>Insert Block</summary> | ||
> [!NOTE] | ||
> Ensure to disable local file restrictions in your browser or use a live server when testing. | ||
### `:path` | ||
- test.html | ||
```html | ||
<h1>path heading</h1> | ||
<p>path content</p> | ||
``` | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<temp :path="./test.html"></temp> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app" | ||
}); | ||
</script> | ||
``` | ||
- Result | ||
```html | ||
<body id="app"> | ||
<!-- Directly inserted PATH content --> | ||
<h1>path heading</h1> | ||
<p>path content</p> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>Loop Rendering</summary> | ||
### `:for` | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<ul> | ||
<li :for="(item, index) in ary" :id="item" :index="index">{{ item }} {{ CALC(index + 1) }}</li> | ||
</ul> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
ary: ["test1", "test2", "test3"] | ||
} | ||
}); | ||
</script> | ||
``` | ||
- Result | ||
```html | ||
<body id="app"> | ||
<li id="test1" index="0">test1 1</li> | ||
<li id="test2" index="1">test2 2</li> | ||
<li id="test3" index="2">test3 3</li> | ||
</body> | ||
``` | ||
*** | ||
### 巢狀迴圈 | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<ul> | ||
<li :for="(key, val) in obj"> | ||
{{ key }}: {{ val.name }} | ||
<ul> | ||
<li :for="item in val.ary"> | ||
{{ item.name }} | ||
<ul> | ||
<li :for="(item1, index1) in item.ary1"> | ||
{{ CALC(index1 + 1) }}. {{ item1.name }} - ${{ item1.price }} | ||
</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
obj: { | ||
food: { | ||
name: "Food", | ||
ary: [ | ||
{ | ||
name: 'Snacks', | ||
ary1: [ | ||
{ name: 'Potato Chips', price: 10 }, | ||
{ name: 'Chocolate', price: 8 } | ||
] | ||
}, | ||
{ | ||
name: 'Beverages', | ||
ary1: [ | ||
{ name: 'Juice', price: 5 }, | ||
{ name: 'Tea', price: 3 } | ||
] | ||
} | ||
] | ||
}, | ||
home: { | ||
name: 'Home', | ||
ary: [ | ||
{ | ||
name: 'Furniture', | ||
ary1: [ | ||
{ name: 'Sofa', price: 300 }, | ||
{ name: 'Table', price: 150 } | ||
] | ||
}, | ||
{ | ||
name: 'Decorations', | ||
ary1: [ | ||
{ name: 'Picture Frame', price: 20 }, | ||
{ name: 'Vase', price: 15 } | ||
] | ||
} | ||
] | ||
} | ||
} | ||
} | ||
}); | ||
</script> | ||
``` | ||
- Result | ||
```html | ||
<body id="app"> | ||
<ul> | ||
<li>food: Food | ||
<ul> | ||
<li>Snacks | ||
<ul> | ||
<li>1. Potato Chips - $10</li> | ||
<li>2. Chocolate - $8</li> | ||
</ul> | ||
</li> | ||
<li>Beverages | ||
<ul> | ||
<li>1. Juice - $5</li> | ||
<li>2. Tea - $3</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
</li> | ||
<li>home: Home | ||
<ul> | ||
<li>Furniture | ||
<ul> | ||
<li>1. Sofa - $300</li> | ||
<li>2. Table - $150</li> | ||
</ul> | ||
</li> | ||
<li>Decorations | ||
<ul> | ||
<li>1. Picture Frame - $20</li> | ||
<li>2. Vase - $15</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>Conditional Rendering</summary> | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<h1 :if="heading == 1">{{ title }} {{ heading }}</h1> | ||
<h2 :else-if="isH2">{{ title }} {{ heading }}</h2> | ||
<h3 :else-if="heading == 3">{{ title }} {{ heading }}</h3> | ||
<h4 :else>{{ title }} {{ heading }}</h4> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
heading: [Number|null], | ||
isH2: [Boolean|null], | ||
title: "test" | ||
} | ||
}); | ||
</script> | ||
``` | ||
- Result: `heading = 1` | ||
```html | ||
<body id="app"> | ||
<h1>test 1</h1> | ||
</body> | ||
``` | ||
- Result: `heading = null && isH2 = true` | ||
```html | ||
<body id="app"> | ||
<h2>test </h2> | ||
</body> | ||
``` | ||
- Result: `heading = 3 && isH2 = null` | ||
```html | ||
<body id="app"> | ||
<h3>test 3</h3> | ||
</body> | ||
``` | ||
- Result: `heading = null && isH2 = null` | ||
```html | ||
<body id="app"> | ||
<h4>test </h4> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>Template Rendering</summary> | ||
- index.html | ||
```HTML | ||
<body id="app"></body> | ||
<script> | ||
const test = new QUI({ | ||
id: "app", | ||
data: { | ||
hint: "hint 123", | ||
title: "test 123" | ||
}, | ||
render: () => { | ||
return ` | ||
"{{ hint }}", | ||
h1 { | ||
style: "background: red;", | ||
children: [ | ||
"{{ title }}" | ||
] | ||
}` | ||
} | ||
}) | ||
</script> | ||
``` | ||
- result | ||
```HTML | ||
<body id="app"> | ||
hint 123 | ||
<h1 style="background: red;">test 123</h1> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>Binding</summary> | ||
```html | ||
<body id="app"> | ||
<input type="password" :model="password"> | ||
<button @click="show">test</button> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
password: null, | ||
### Initialize `QUI` | ||
```Javascript | ||
const app = new QUI({ | ||
id: "", // Specify rendering element | ||
data: { | ||
// Custom DATA | ||
}, | ||
event: { | ||
// Custom EVENT | ||
}, | ||
when: { | ||
before_render: function () { | ||
// Stop rendering | ||
}, | ||
event: { | ||
show: function(e){ | ||
alert("Password:", app.data.password); | ||
} | ||
rendered: function () { | ||
// Rendered | ||
}, | ||
before_update: function () { | ||
// Stop updating | ||
}, | ||
updated: function () { | ||
// Updated | ||
}, | ||
before_destroy: function () { | ||
// Stop destruction | ||
}, | ||
destroyed: function () { | ||
// Destroyed | ||
} | ||
}); | ||
</script> | ||
} | ||
}); | ||
``` | ||
</details> | ||
<details> | ||
<summary>Event</summary> | ||
## Overview | ||
```html | ||
<body id="app"> | ||
<button @click="test">test</button> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
event: { | ||
test: function(e){ | ||
alert(e.target.innerText + " clicked"); | ||
} | ||
} | ||
}); | ||
</script> | ||
``` | ||
</details> | ||
### Text & Content | ||
| Attribute | Use Case | Example | | ||
|-----------|----------|---------| | ||
| `{{value}}` | Dynamic text content | `<p>{{ userName }}</p>` displays user's name | | ||
| `:html` | Raw HTML insertion | `<div :html="richContent"></div>` renders formatted content | | ||
<details> | ||
<summary>CSS</summary> | ||
### Template Loading | ||
| Attribute | Use Case | Example | | ||
|-----------|----------|---------| | ||
| `:path` | External template loading | `<temp :path="./templates/header.html"></temp>` loads header component | | ||
> [!NOTE] | ||
> Supports simple settings using :[CSS property], directly binding data to style attributes. | ||
### List & Iteration | ||
| Attribute | Use Case | Example | | ||
|-----------|----------|---------| | ||
| `:for` | Array/Object iteration | `<li :for="item in items">{{ item.name }}</li>` renders list items | | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<button :width="width" :backdround-color="color">test</button> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
width: "100px", | ||
color: "red" | ||
} | ||
}); | ||
</script> | ||
``` | ||
- Result: | ||
```html | ||
<body id="app"> | ||
<button style="width: 100px; backdround-color: red;">test</button> | ||
</body> | ||
``` | ||
### Conditional Rendering | ||
| Attribute | Use Case | Example | | ||
|-----------|----------|---------| | ||
| `:if` | Conditional display | `<div :if="isLoggedIn">Welcome!</div>` | | ||
| `:else-if`/`:elif` | Secondary conditions | `<div :elif="isPending">Loading...</div>` | | ||
| `:else` | Fallback content | `<div :else>Please log in</div>` | | ||
</details> | ||
### Form Binding | ||
| Attribute | Use Case | Example | | ||
|-----------|----------|---------| | ||
| `:model` | Two-way data binding | `<input :model="userInput">` syncs with data | | ||
<details> | ||
<summary>Functions</summary> | ||
### Styling & Animation | ||
| Attribute | Use Case | Example | | ||
|-----------|----------|---------| | ||
| `:animation` | Transition effects | `<div :animation="fade-in">Content</div>` | | ||
| `:[css]` | Dynamic styling | `<div :background-color="bgColor">Styled content</div>` | | ||
### `LENGTH()` | ||
### Dynamic Attributes | ||
| Attribute | Use Case | Example | | ||
|-----------|----------|---------| | ||
| `:[attr]` | Dynamic attributes | `<img :src="imageUrl" :alt="imageDesc">` | | ||
- index.html | ||
```HTML | ||
<body id="app"> | ||
<p>Total: {{ LENGTH(array) }}</p> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
array: [1, 2, 3, 4] | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result | ||
```HTML | ||
<body id="app"> | ||
<p>Total: 4</p> | ||
</body> | ||
``` | ||
### Event Handling | ||
| Attribute | Use Case | Example | | ||
|-----------|----------|---------| | ||
| `@[event]` | Event listeners | `<button @click="handleClick">Click me</button>` | | ||
*** | ||
## License | ||
### `CALC()` | ||
Similar to MIT License but provides obfuscated code only: | ||
- Same as MIT: Free to use, modify and redistribute, including commercial use | ||
- Main difference: Provides obfuscated code by default, source code available for purchase | ||
- License terms: Must retain original copyright notice (same as MIT) | ||
- index.html | ||
```HTML | ||
<body id="app"> | ||
<p>calc: {{ CALC(num * 10) }}</p> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
num: 1 | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result | ||
```HTML | ||
<body id="app"> | ||
<p>calc: 10</p> | ||
</body> | ||
``` | ||
For detailed terms and conditions, please see the [Software Usage Agreement](https://github.com/pardnchiu/QuickUI/blob/main/LICENSE). | ||
*** | ||
### `UPPER()` / `LOWER()` | ||
- index.html | ||
```HTML | ||
<body id="app"> | ||
<p>{{ UPPER(test1) }} {{ LOWER(test2) }}</p> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
test1: "upper", | ||
test2: "LOWER" | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result | ||
```HTML | ||
<body id="app"> | ||
<p>UPPER lower</p> | ||
</body> | ||
``` | ||
*** | ||
### `DATE(num, format)` | ||
- index.html | ||
```HTML | ||
<body id="app"> | ||
<p>{{ DATE(now, YYYY-MM-DD hh:mm:ss) }}</p> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
now: Math.floor(Date.now() / 1000) | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result | ||
```HTML | ||
<body id="app"> | ||
<p>2024-08-17 03:40:47</p> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>Lazyload</summary> | ||
### `:lazyload` | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<img :lazyload="image"> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
image: "test.jpg" | ||
}, | ||
option: { | ||
lazyload: true // Enable image lazy loading: true|false (default: true) | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result | ||
```html | ||
<body id="app"> | ||
<img src="test.jpg"> | ||
</body> | ||
``` | ||
*** | ||
### `SVG` 替換 | ||
- test.svg | ||
```XML | ||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<line x1="18" y1="6" x2="6" y2="18" stroke="black" stroke-width="2" stroke-linecap="round"/> | ||
<line x1="6" y1="6" x2="18" y2="18" stroke="black" stroke-width="2" stroke-linecap="round"/> | ||
</svg> | ||
``` | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<temp-svg :src="svg"></temp-svg> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
svg: "test.svg", | ||
}, | ||
option: { | ||
svg: true // Enable SVG file transformation: true|false (default: true) | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result | ||
```html | ||
<body id="app"> | ||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<line x1="18" y1="6" x2="6" y2="18" stroke="black" stroke-width="2" stroke-linecap="round"> | ||
<line x1="6" y1="6" x2="18" y2="18" stroke="black" stroke-width="2" stroke-linecap="round"> | ||
</svg> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>i18n</summary> | ||
> [!NOTE] | ||
> If the format is an object, the multilingual content is directly configured. | ||
> If the format is a string, the language file is dynamically loaded via fetch. | ||
- en.json | ||
```JSON | ||
{ | ||
"greeting": "Hello", | ||
"username": "Username" | ||
} | ||
``` | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<h1>{{ i18n.greeting }}, {{ i18n.username }}: {{ username }}</h1> | ||
<button @click="change" data-lang="zh">切換至中文</button> | ||
<button @click="change" data-lang="en">Switch to English</button> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
username: "Pardn" | ||
}, | ||
i18n: { | ||
zh: { | ||
greeting: "你好", | ||
username: "用戶名" | ||
}, | ||
en: "en.json", | ||
}, | ||
i18nLang: "zh | en", // Select the displayed language | ||
event: { | ||
change: e => { | ||
const _this = e.target; | ||
const lang = _this.dataset.lang; | ||
app.lang(lang); | ||
}, | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result `i18nLang = zh` | ||
```html | ||
<body id="app"> | ||
<h1>你好, 用戶名: Pardn</h1> | ||
<button data-lang="zh">切換至中文</button> | ||
<button data-lang="en">Switch to English</button> | ||
</body> | ||
``` | ||
- result `i18nLang = en` | ||
```html | ||
<body id="app"> | ||
<h1>Hello, Username: Pardn</h1> | ||
<button data-lang="zh">切換至中文</button> | ||
<button data-lang="en">Switch to English</button> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>Lifecycle Hooks</summary> | ||
```html | ||
<body id="app"></body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
when: { | ||
before_render: function () { | ||
// Stop rendering | ||
// retuen false | ||
}, | ||
rendered: function () { | ||
// Rendered | ||
}, | ||
before_update: function () { | ||
// Stop updating | ||
// retuen false | ||
}, | ||
updated: function () { | ||
// Updated | ||
}, | ||
before_destroy: function () { | ||
// Stop destruction | ||
// retuen false | ||
}, | ||
destroyed: function () { | ||
// Destroyed | ||
} | ||
} | ||
}); | ||
</script> | ||
``` | ||
</details> | ||
<details> | ||
<summary>Data Retrieval</summary> | ||
```html | ||
<body id="app"> | ||
<input type="text" :model="test"> | ||
<button @click="get">Test</button> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
// Value bound to the input | ||
test: 123 | ||
}, | ||
event: { | ||
get: _ => { | ||
// Show an alert with the value of test on button click | ||
alert(app.data.test); | ||
}, | ||
set: _ => { | ||
let dom = document.createElement("button"); | ||
// Assign the button click event to the get function | ||
dom.onclick = app.event.get; | ||
app.body.append(dom); | ||
} | ||
} | ||
}); | ||
</script> | ||
``` | ||
</details> | ||
## Creator | ||
<img src="https://avatars.githubusercontent.com/u/25631760" align="left" width="96" height="96" style="margin-right: 0.5rem;" /> | ||
<img src="https://avatars.githubusercontent.com/u/25631760" align="left" width="96" height="96" style="margin-right: 0.5rem;"> | ||
<h4 style="padding-top: 0">邱敬幃 Pardn Chiu</h4> | ||
[![](https://pardn.io/image/mail.svg)](mailto:dev@pardn.io) [![](https://skillicons.dev/icons?i=linkedin)](https://linkedin.com/in/pardnchiu) | ||
<a href="mailto:dev@pardn.io" target="_blank"> | ||
<img src="https://pardn.io/image/email.svg" width="48" height="48"> | ||
</a> <a href="https://linkedin.com/in/pardnchiu" target="_blank"> | ||
<img src="https://pardn.io/image/linkedin.svg" width="48" height="48"> | ||
</a> | ||
## License | ||
This project is licensed under a **Proprietary License**. | ||
You may use, install, and run this software only under the terms specified in the [End-User License Agreement (EULA)](https://github.com/pardnchiu/QuickUI/blob/main/LICENSE). | ||
## Obtain Complete Source Code | ||
[Contact me](mailto:dev@pardn.io) for the complete unobfuscated source code.<br> | ||
Feel free to modify and use for commercial purposes with the following licensing options: | ||
- Must retain `Powered by @pardnchiu/quickui` copyright notice: $7,500. | ||
- Fully autonomous, no copyright notice required: $10,000. | ||
*** | ||
©️ 2024 [邱敬幃 Pardn Chiu](https://www.linkedin.com/in/pardnchiu) | ||
©️ 2024 [邱敬幃 Pardn Chiu](https://pardn.io) |
909
README.zh.md
@@ -1,7 +0,10 @@ | ||
<img src="./dist/logo.png" width=80> | ||
<img src="https://quickui.pardn.io/static/image/logo.png" width=80> | ||
# QuickUI | ||
# QuickUI: 輕量化前端框架 | ||
*(原名:PDQuickUI,自 `0.6.0` 版本起更名為 QuickUI)* | ||
> [!NOTE] | ||
> (原名:PDQuickUI,自 `0.6.0` 版本起更名為 QuickUI) | ||
> QuickUI 是一個純 JavaScript 開發的前端渲染框架。通過整合虛擬 DOM 技術提升渲染效能,實現快速的數據響應和自動更新。 | ||
![tag](https://img.shields.io/badge/tag-JavaScript%20Library-bb4444) | ||
@@ -14,816 +17,162 @@ ![size](https://img.shields.io/github/size/pardnchiu/QuickUI/dist%2FQuickUI.js)<br> | ||
`QuickUI` 是從 [PDRenderKit](https://github.com/pardnchiu/PDRenderKit) 中獨立出來的前端渲染框架,專注於強化前端框架功能。<br> | ||
透過引入虛擬 DOM 概念重寫渲染邏輯,提升渲染效能,並實現更高效的數據監聽和自動更新。<br> | ||
## 核心特色 | ||
本專案移除了 `PDRenderKit` 中針對 `prototype` 的擴展,確保兼容性與效能,適合用於複雜的應用場景。<br> | ||
提供 `module` 和非 `module` 版本,授權從 `PDRenderKit` 的 `GPL-3.0` 更改為 `MIT`。<br> | ||
### 高效虛擬 DOM | ||
- 透過精準的差異比對算法實現高效 DOM 更新 | ||
- 智慧屬性更新系統,只更新發生變化的值 | ||
- 智能子節點對比機制,最小化 DOM 操作 | ||
## 特點 | ||
### 響應式數據處理 | ||
- 深度數據監控系統,確保數據變更即時反映 | ||
- 數據變更時自動更新 UI,無需手動操作 | ||
- 智慧緩存系統避免不必要的重複渲染 | ||
- 支援巢狀數據結構的響應式處理 | ||
- **清晰的架構**:UI 和資料邏輯分離,維護方便。 | ||
- **代碼簡潔**:減少重複代碼,提升可讀性。 | ||
- **自動渲染**:監控資料變動並自動更新,減少手動操作。 | ||
- **輕量化**:使用原生 JS 和內建 API 撰寫,無任何外部依賴。 | ||
### 進階模板功能 | ||
- 內建多語系(i18n)支援,輕鬆實現國際化 | ||
- 支援動態載入模板並非同步處理 | ||
- 強大的表達式系統,支援計算、日期和文字處理 | ||
- 完整的指令系統實現靈活的 DOM 操作 | ||
## 安裝方式 | ||
### 效能優化設計 | ||
- 圖片和 SVG 內容採用懶加載技術,提升載入速度 | ||
- 極小的檔案體積且無外部依賴 | ||
- 智慧事件委派和資源清理機制,優化記憶體使用 | ||
- 從 npm 安裝 | ||
```bash | ||
npm i @pardnchiu/quickui | ||
``` | ||
## 文件 | ||
- 從 CDN 引入 | ||
- **引入 `QuickUI` 套件** | ||
```html | ||
<!-- Version 0.6.0 and above --> | ||
<script src="https://cdn.jsdelivr.net/npm/@pardnchiu/quickui@[VERSION]/dist/QuickUI.js"></script> | ||
- 網站: [nanomd.pardn.io](https://nanomd.pardn.io) | ||
- 說明文件: [nanomd.pardn.io/doc.html](https://nanomd.pardn.io/doc.html) | ||
<!-- Version 0.5.4 and below --> | ||
<script src="https://cdn.jsdelivr.net/npm/pdquickui@[VERSION]/dist/PDQuickUI.js"></script> | ||
``` | ||
- **Module 版本** | ||
```javascript | ||
// Version 0.6.0 and above | ||
import { QUI } from "https://cdn.jsdelivr.net/npm/@pardnchiu/quickui@[VERSION]/dist/QuickUI.esm.js"; | ||
// Version 0.5.4 and below | ||
import { QUI } from "https://cdn.jsdelivr.net/npm/pdquickui@[VERSION]/dist/PDQuickUI.module.js"; | ||
``` | ||
## 使用方法 | ||
## 安裝方式 | ||
- **初始化 `QUI`** | ||
```Javascript | ||
const app = new QUI({ | ||
id: "", // 指定渲染元素 | ||
data: { | ||
// 自訂 DATA | ||
}, | ||
event: { | ||
// 自訂 EVENT | ||
}, | ||
when: { | ||
before_render: function () { | ||
// 停止渲染 | ||
}, | ||
rendered: function () { | ||
// 已渲染 | ||
}, | ||
before_update: function () { | ||
// 停止更新 | ||
}, | ||
updated: function () { | ||
// 已更新 | ||
}, | ||
before_destroy: function () { | ||
// 停止銷毀 | ||
}, | ||
destroyed: function () { | ||
// 已銷毀 | ||
} | ||
} | ||
}); | ||
``` | ||
### 從 npm 安裝 | ||
```shell | ||
npm i @pardnchiu/quickui | ||
``` | ||
## 功能介紹 | ||
自動渲染:加載自動渲染在檢測到資料變更時自動重新渲染。 | ||
### 從 CDN 引入 | ||
<details> | ||
<summary>屬性概覽</summary> | ||
#### 引入 `QuickUI` 套件 | ||
```html | ||
<!-- 0.6.0 版本以上 --> | ||
<script src="https://cdn.jsdelivr.net/npm/@pardnchiu/quickui@[VERSION]/dist/QuickUI.js"></script> | ||
| 屬性 | 描述 | | ||
| --- | --- | | ||
| `{{value}}` | 將文字插入到 HTML 標籤中,並隨資料變更自動更新。 | | ||
| `:path` | 搭配 `temp` 標籤,用於將外部文件中的 HTML 片段加載到當前頁面。 | | ||
| `:html` | 使用文本替換元素的 `innerHTML`。 | | ||
| `:for` | 支援 `item in items`、`(item, index) in items`、`(key, value) in object` 格式,遍歷資料集合,生成對應的 HTML 元素。 | | ||
| `:if`<br>`:else-if`<br>`:elif`<br>`:else` | 根據條件顯示或隱藏元素,實現分支邏輯。 | | ||
| `:model` | 將資料綁定到表單元素(如 `input`),當輸入變更時自動更新資料。 | | ||
| `:hide` | 根據特定條件隱藏元素。 | | ||
| `:effect` | 用於指定元素的過渡效果,如 `fade-in` 或 `expand`,以增強用戶體驗。 | | ||
| `:mask` | 控制區塊載入時的動畫效果,支援 `true\|false\|1\|0`,提升載入動態視覺效果。 | | ||
| `:[attr]` | 設定元素屬性,例如 `ID`、`class`、圖像來源等。<br>範例:`:id`、`:class`、`:src`、`:alt`、`:href`... | | ||
| `:[css]` | 設定元素CSS,例如 `margin`、`padding` 等。<br>範例:`:background-color`、`:opacity`、`:margin`、`:top`、`:position`... | | ||
| `@[event]` | 添加事件監聽器,當事件觸發時執行指定操作。<br>範例:`@click`、`@input`、`@mousedown`... | | ||
<!-- 0.5.4 版本以下 --> | ||
<script src="https://cdn.jsdelivr.net/npm/pdquickui@[VERSION]/dist/PDQuickUI.js"></script> | ||
``` | ||
</details> | ||
#### Module 版本 | ||
```javascript | ||
// 0.6.0 版本以上 | ||
import { QUI } from "https://cdn.jsdelivr.net/npm/@pardnchiu/quickui@[VERSION]/dist/QuickUI.esm.js"; | ||
<details> | ||
<summary>文字替換</summary> | ||
// 0.5.4 版本以下 | ||
import { QUI } from "https://cdn.jsdelivr.net/npm/pdquickui@[VERSION]/dist/PDQuickUI.module.js"; | ||
``` | ||
## 使用方法 | ||
### `{{value}}` | ||
- index.html | ||
```HTML | ||
<h1>{{ title }}</h1> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
title: "test" | ||
} | ||
}); | ||
</script> | ||
``` | ||
- Result | ||
```HTML | ||
<body id="app"> | ||
<h1>test</h1> | ||
</body> | ||
``` | ||
*** | ||
### `:html` | ||
- index.html | ||
```HTML | ||
<section :html="html"></section> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
html: "<b>innerHtml</b>" | ||
} | ||
}); | ||
</script> | ||
``` | ||
- Result | ||
```HTML | ||
<body id="app"> | ||
<section> | ||
<b>innerHtml</b> | ||
</section> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>插入區塊</summary> | ||
> [!NOTE] | ||
> 確保測試時已禁用瀏覽器中的本地文件限制或使用實時服務器。 | ||
### `:path` | ||
- test.html | ||
```html | ||
<h1>path heading</h1> | ||
<p>path content</p> | ||
``` | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<temp :path="./test.html"></temp> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app" | ||
}); | ||
</script> | ||
``` | ||
- Result | ||
```html | ||
<body id="app"> | ||
<!-- 直接插入 PATH 內容 --> | ||
<h1>path heading</h1> | ||
<p>path content</p> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>迴圈渲染</summary> | ||
### `:for` | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<ul> | ||
<li :for="(item, index) in ary" :id="item" :index="index">{{ item }} {{ CALC(index + 1) }}</li> | ||
</ul> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
ary: ["test1", "test2", "test3"] | ||
} | ||
}); | ||
</script> | ||
``` | ||
- Result | ||
```html | ||
<body id="app"> | ||
<li id="test1" index="0">test1 1</li> | ||
<li id="test2" index="1">test2 2</li> | ||
<li id="test3" index="2">test3 3</li> | ||
</body> | ||
``` | ||
*** | ||
### 巢狀迴圈 | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<ul> | ||
<li :for="(key, val) in obj"> | ||
{{ key }}: {{ val.name }} | ||
<ul> | ||
<li :for="item in val.ary"> | ||
{{ item.name }} | ||
<ul> | ||
<li :for="(item1, index1) in item.ary1"> | ||
{{ CALC(index1 + 1) }}. {{ item1.name }} - ${{ item1.price }} | ||
</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
obj: { | ||
food: { | ||
name: "Food", | ||
ary: [ | ||
{ | ||
name: 'Snacks', | ||
ary1: [ | ||
{ name: 'Potato Chips', price: 10 }, | ||
{ name: 'Chocolate', price: 8 } | ||
] | ||
}, | ||
{ | ||
name: 'Beverages', | ||
ary1: [ | ||
{ name: 'Juice', price: 5 }, | ||
{ name: 'Tea', price: 3 } | ||
] | ||
} | ||
] | ||
}, | ||
home: { | ||
name: 'Home', | ||
ary: [ | ||
{ | ||
name: 'Furniture', | ||
ary1: [ | ||
{ name: 'Sofa', price: 300 }, | ||
{ name: 'Table', price: 150 } | ||
] | ||
}, | ||
{ | ||
name: 'Decorations', | ||
ary1: [ | ||
{ name: 'Picture Frame', price: 20 }, | ||
{ name: 'Vase', price: 15 } | ||
] | ||
} | ||
] | ||
} | ||
} | ||
} | ||
}); | ||
</script> | ||
``` | ||
- Result | ||
```html | ||
<body id="app"> | ||
<ul> | ||
<li>food: Food | ||
<ul> | ||
<li>Snacks | ||
<ul> | ||
<li>1. Potato Chips - $10</li> | ||
<li>2. Chocolate - $8</li> | ||
</ul> | ||
</li> | ||
<li>Beverages | ||
<ul> | ||
<li>1. Juice - $5</li> | ||
<li>2. Tea - $3</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
</li> | ||
<li>home: Home | ||
<ul> | ||
<li>Furniture | ||
<ul> | ||
<li>1. Sofa - $300</li> | ||
<li>2. Table - $150</li> | ||
</ul> | ||
</li> | ||
<li>Decorations | ||
<ul> | ||
<li>1. Picture Frame - $20</li> | ||
<li>2. Vase - $15</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>條件渲染</summary> | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<h1 :if="heading == 1">{{ title }} {{ heading }}</h1> | ||
<h2 :else-if="isH2">{{ title }} {{ heading }}</h2> | ||
<h3 :else-if="heading == 3">{{ title }} {{ heading }}</h3> | ||
<h4 :else>{{ title }} {{ heading }}</h4> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
heading: [Number|null], | ||
isH2: [Boolean|null], | ||
title: "test" | ||
} | ||
}); | ||
</script> | ||
``` | ||
- Result: `heading = 1` | ||
```html | ||
<body id="app"> | ||
<h1>test 1</h1> | ||
</body> | ||
``` | ||
- Result: `heading = null && isH2 = true` | ||
```html | ||
<body id="app"> | ||
<h2>test </h2> | ||
</body> | ||
``` | ||
- Result: `heading = 3 && isH2 = null` | ||
```html | ||
<body id="app"> | ||
<h3>test 3</h3> | ||
</body> | ||
``` | ||
- Result: `heading = null && isH2 = null` | ||
```html | ||
<body id="app"> | ||
<h4>test </h4> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>模板渲染</summary> | ||
- index.html | ||
```HTML | ||
<body id="app"></body> | ||
<script> | ||
const test = new QUI({ | ||
id: "app", | ||
data: { | ||
hint: "hint 123", | ||
title: "test 123" | ||
}, | ||
render: () => { | ||
return ` | ||
"{{ hint }}", | ||
h1 { | ||
style: "background: red;", | ||
children: [ | ||
"{{ title }}" | ||
] | ||
}` | ||
} | ||
}) | ||
</script> | ||
``` | ||
- result | ||
```HTML | ||
<body id="app"> | ||
hint 123 | ||
<h1 style="background: red;">test 123</h1> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>雙向綁定</summary> | ||
```html | ||
<body id="app"> | ||
<input type="password" :model="password"> | ||
<button @click="show">test</button> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
password: null, | ||
### 初始化 `QUI` | ||
```Javascript | ||
const app = new QUI({ | ||
id: "", // 指定渲染元素 | ||
data: { | ||
// 自訂 DATA | ||
}, | ||
event: { | ||
// 自訂 EVENT | ||
}, | ||
when: { | ||
before_render: function () { | ||
// 停止渲染 | ||
}, | ||
event: { | ||
show: function(e){ | ||
alert("Password:", app.data.password); | ||
} | ||
rendered: function () { | ||
// 已渲染 | ||
}, | ||
before_update: function () { | ||
// 停止更新 | ||
}, | ||
updated: function () { | ||
// 已更新 | ||
}, | ||
before_destroy: function () { | ||
// 停止銷毀 | ||
}, | ||
destroyed: function () { | ||
// 已銷毀 | ||
} | ||
}); | ||
</script> | ||
} | ||
}); | ||
``` | ||
</details> | ||
<details> | ||
<summary>事件偵測</summary> | ||
### 屬性概覽 | ||
```html | ||
<body id="app"> | ||
<button @click="test">test</button> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
event: { | ||
test: function(e){ | ||
alert(e.target.innerText + " clicked"); | ||
} | ||
} | ||
}); | ||
</script> | ||
``` | ||
</details> | ||
#### 文字與內容 | ||
| 屬性 | 使用場景 | 範例 | | ||
|-----------|----------|---------| | ||
| `{{ value }}` | 動態文字內容 | `<p>{{ userName }}</p>` 顯示使用者名稱 | | ||
| `:html` | 原始 HTML 插入 | `<div :html="richContent"></div>` 渲染格式化內容 | | ||
<details> | ||
<summary>CSS設置</summary> | ||
#### 模板載入 | ||
| 屬性 | 使用場景 | 範例 | | ||
|-----------|----------|---------| | ||
| `:path` | 外部模板載入 | `<temp :path="'./templates/header.html'"></temp>` 載入頁首元件 | | ||
> [!NOTE] | ||
> 支援 `:[CSS屬性]` 的簡易設定方式,直接將資料綁定到樣式屬性。 | ||
#### 列表與迭代 | ||
| 屬性 | 使用場景 | 範例 | | ||
|-----------|----------|---------| | ||
| `:for` | 陣列/物件迭代 | `<li :for="item in items">{{ item.name }}</li>` 渲染列表項目 | | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<button :width="width" :backdround-color="color">test</button> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
width: "100px", | ||
color: "red" | ||
} | ||
}); | ||
</script> | ||
``` | ||
- Result: | ||
```html | ||
<body id="app"> | ||
<button style="width: 100px; backdround-color: red;">test</button> | ||
</body> | ||
``` | ||
#### 條件渲染 | ||
| 屬性 | 使用場景 | 範例 | | ||
|-----------|----------|---------| | ||
| `:if` | 條件顯示 | `<div :if="isLoggedIn">歡迎!</div>` | | ||
| `:else-if`/`:elif` | 次要條件 | `<div :elif="isPending">載入中...</div>` | | ||
| `:else` | 預設內容 | `<div :else>請登入</div>` | | ||
</details> | ||
#### 表單綁定 | ||
| 屬性 | 使用場景 | 範例 | | ||
|-----------|----------|---------| | ||
| `:model` | 雙向資料綁定 | `<input :model="userInput">` 與資料同步 | | ||
<details> | ||
<summary>可用函式</summary> | ||
#### 樣式與動畫 | ||
| 屬性 | 使用場景 | 範例 | | ||
|-----------|----------|---------| | ||
| `:animation` | 過渡效果 | `<div :animation="fade-in">內容</div>` | | ||
| `:[css]` | 動態樣式 | `<div :background-color="bgColor">樣式內容</div>` | | ||
### `LENGTH()` | ||
#### 動態屬性 | ||
| 屬性 | 使用場景 | 範例 | | ||
|-----------|----------|---------| | ||
| `:[attr]` | 動態屬性 | `<img :src="imageUrl" :alt="imageDesc">` | | ||
- index.html | ||
```HTML | ||
<body id="app"> | ||
<p>Total: {{ LENGTH(array) }}</p> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
array: [1, 2, 3, 4] | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result | ||
```HTML | ||
<body id="app"> | ||
<p>Total: 4</p> | ||
</body> | ||
``` | ||
#### 事件處理 | ||
| 屬性 | 使用場景 | 範例 | | ||
|-----------|----------|---------| | ||
| `@[event]` | 事件監聽器 | `<button @click="handleClick">點擊我</button>` | | ||
*** | ||
## 授權條款 | ||
### `CALC()` | ||
本專案採用類 MIT 授權,但僅提供混淆後的程式碼: | ||
- 與 MIT 相同:可自由使用、修改、再散布,包含商業用途 | ||
- 主要差異:預設僅提供混淆版程式碼,原始碼需另外購買 | ||
- 授權內容:必須保留原始版權聲明 (與 MIT 相同) | ||
- index.html | ||
```HTML | ||
<body id="app"> | ||
<p>calc: {{ CALC(num * 10) }}</p> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
num: 1 | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result | ||
```HTML | ||
<body id="app"> | ||
<p>calc: 10</p> | ||
</body> | ||
``` | ||
詳細條款與條件請參閱[軟體使用協議](https://github.com/pardnchiu/QuickUI/blob/main/LICENSE)。 | ||
*** | ||
### `UPPER()` / `LOWER()` | ||
- index.html | ||
```HTML | ||
<body id="app"> | ||
<p>{{ UPPER(test1) }} {{ LOWER(test2) }}</p> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
test1: "upper", | ||
test2: "LOWER" | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result | ||
```HTML | ||
<body id="app"> | ||
<p>UPPER lower</p> | ||
</body> | ||
``` | ||
*** | ||
### `DATE(num, format)` | ||
- index.html | ||
```HTML | ||
<body id="app"> | ||
<p>{{ DATE(now, YYYY-MM-DD hh:mm:ss) }}</p> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
now: Math.floor(Date.now() / 1000) | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result | ||
```HTML | ||
<body id="app"> | ||
<p>2024-08-17 03:40:47</p> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>懶加載</summary> | ||
### `:lazyload` | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<img :lazyload="image"> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
image: "test.jpg" | ||
}, | ||
option: { | ||
lazyload: true, // 圖片延遲加載: true|false (預設: true) | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result | ||
```html | ||
<body id="app"> | ||
<img src="test.jpg"> | ||
</body> | ||
``` | ||
*** | ||
### `SVG` 替換 | ||
- test.svg | ||
```XML | ||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<line x1="18" y1="6" x2="6" y2="18" stroke="black" stroke-width="2" stroke-linecap="round"/> | ||
<line x1="6" y1="6" x2="18" y2="18" stroke="black" stroke-width="2" stroke-linecap="round"/> | ||
</svg> | ||
``` | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<temp-svg :src="svg"></temp-svg> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
svg: "test.svg", | ||
}, | ||
option: { | ||
svg: true // SVG 檔案轉換: true|false (預設: true) | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result | ||
```html | ||
<body id="app"> | ||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<line x1="18" y1="6" x2="6" y2="18" stroke="black" stroke-width="2" stroke-linecap="round"> | ||
<line x1="6" y1="6" x2="18" y2="18" stroke="black" stroke-width="2" stroke-linecap="round"> | ||
</svg> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>多國語言</summary> | ||
> [!NOTE] | ||
> 若為物件格式,直接配置多語言內容。 | ||
> 若為字串格式,會透過 `fetch` 動態載入語言檔案。 | ||
- en.json | ||
```JSON | ||
{ | ||
"greeting": "Hello", | ||
"username": "Username" | ||
} | ||
``` | ||
- index.html | ||
```html | ||
<body id="app"> | ||
<h1>{{ i18n.greeting }}, {{ i18n.username }}: {{ username }}</h1> | ||
<button @click="change" data-lang="zh">切換至中文</button> | ||
<button @click="change" data-lang="en">Switch to English</button> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
username: "帕登" | ||
}, | ||
i18n: { | ||
zh: { | ||
greeting: "你好", | ||
username: "用戶名" | ||
}, | ||
en: "en.json", | ||
}, | ||
i18nLang: "zh | en", // 選擇顯示語言 | ||
event: { | ||
change: e => { | ||
const _this = e.target; | ||
const lang = _this.dataset.lang; | ||
app.lang(lang); | ||
}, | ||
} | ||
}); | ||
</script> | ||
``` | ||
- result `i18nLang = zh` | ||
```html | ||
<body id="app"> | ||
<h1>你好, 用戶名: 帕登</h1> | ||
<button data-lang="zh">切換至中文</button> | ||
<button data-lang="en">Switch to English</button> | ||
</body> | ||
``` | ||
- result `i18nLang = en` | ||
```html | ||
<body id="app"> | ||
<h1>Hello, Username: 帕登</h1> | ||
<button data-lang="zh">切換至中文</button> | ||
<button data-lang="en">Switch to English</button> | ||
</body> | ||
``` | ||
</details> | ||
<details> | ||
<summary>生命週期</summary> | ||
```html | ||
<body id="app"></body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
when: { | ||
before_render: function () { | ||
// 停止渲染 | ||
// retuen false | ||
}, | ||
rendered: function () { | ||
// 已掛載 | ||
}, | ||
before_update: function () { | ||
// 停止更新 | ||
// retuen false | ||
}, | ||
updated: function () { | ||
// 已更新 | ||
}, | ||
before_destroy: function () { | ||
// 停止銷毀 | ||
// retuen false | ||
}, | ||
destroyed: function () { | ||
// 已銷毀 | ||
} | ||
} | ||
}); | ||
</script> | ||
``` | ||
</details> | ||
<details> | ||
<summary>資料獲取</summary> | ||
```html | ||
<body id="app"> | ||
<input type="text" :model="test"> | ||
<button @click="get">測試</button> | ||
</body> | ||
<script> | ||
const app = new QUI({ | ||
id: "app", | ||
data: { | ||
// 給 input 綁定的值 | ||
test: 123 | ||
}, | ||
event: { | ||
get: _ => { | ||
// 點擊時彈出內容為 test 值的通知 | ||
alert(app.data.test); | ||
}, | ||
set: _ => { | ||
let dom = document.createElement("button"); | ||
// 按鈕點按事件設置為 get 函式 | ||
dom.onclick = app.event.get; | ||
app.body.append(dom); | ||
} | ||
} | ||
}); | ||
</script> | ||
``` | ||
</details> | ||
## 開發者 | ||
<img src="https://avatars.githubusercontent.com/u/25631760" align="left" width="96" height="96" style="margin-right: 0.5rem;" /> | ||
<img src="https://avatars.githubusercontent.com/u/25631760" align="left" width="96" height="96" style="margin-right: 0.5rem;"> | ||
<h4 style="padding-top: 0">邱敬幃 Pardn Chiu</h4> | ||
[![](https://pardn.io/image/mail.svg)](mailto:dev@pardn.io) [![](https://skillicons.dev/icons?i=linkedin)](https://linkedin.com/in/pardnchiu) | ||
<a href="mailto:dev@pardn.io" target="_blank"> | ||
<img src="https://pardn.io/image/email.svg" width="48" height="48"> | ||
</a> <a href="https://linkedin.com/in/pardnchiu" target="_blank"> | ||
<img src="https://pardn.io/image/linkedin.svg" width="48" height="48"> | ||
</a> | ||
## 授權條款 | ||
本專案採用 **專有授權**。 | ||
更多詳細資訊,請參閱本倉庫中的 [最終使用者授權協議(EULA)](https://github.com/pardnchiu/QuickUI/blob/main/LICENSE)。 | ||
## 獲取完整原始碼 | ||
[聯絡我](mailto:dev@pardn.io) 獲取完整未混淆源碼<br> | ||
可隨意修改、商業使用,根據需求選擇授權版本: | ||
- 需保留 `Powered by @pardnchiu/quickui` 的版權聲明:$7,500 | ||
- 完全自主,無需添加版權聲明:$10,000 | ||
*** | ||
©️ 2024 [邱敬幃 Pardn Chiu](https://www.linkedin.com/in/pardnchiu) | ||
©️ 2023 [邱敬幃 Pardn Chiu](https://www.linkedin.com/in/pardnchiu) |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
6
75945
7
178