pdquickui
v0.6.1
Published
A web frontend framework that supports conditional and loop rendering, data binding, monitoring data changes, and automatic rendering. Previously known as QuickUI.
Downloads
185
Maintainers
Readme
QuickUI
(原名:PDQuickUI,自 0.6.0
版本起更名為 QuickUI)
QuickUI
是從 PDRenderKit 中獨立出來的前端渲染框架,專注於強化前端框架功能。
透過引入虛擬 DOM 概念重寫渲染邏輯,提升渲染效能,並實現更高效的數據監聽和自動更新。
本專案移除了 PDRenderKit
中針對 prototype
的擴展,確保兼容性與效能,適合用於複雜的應用場景。
提供 module
和非 module
版本,授權從 PDRenderKit
的 GPL-3.0
更改為 MIT
。
特點
- 清晰的架構:UI 和資料邏輯分離,維護方便。
- 代碼簡潔:減少重複代碼,提升可讀性。
- 自動渲染:監控資料變動並自動更新,減少手動操作。
- 輕量化:使用原生 JS 和內建 API 撰寫,無任何外部依賴。
安裝方式
從 npm 安裝
npm i @pardnchiu/quickui
從 CDN 引入
- 引入
QuickUI
套件<!-- Version 0.6.0 and above --> <script src="https://cdn.jsdelivr.net/npm/@pardnchiu/quickui@[VERSION]/dist/QuickUI.js"></script> <!-- Version 0.5.4 and below --> <script src="https://cdn.jsdelivr.net/npm/pdquickui@[VERSION]/dist/PDQuickUI.js"></script>
- Module 版本
// 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
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 () { // 已銷毀 } } });
功能介紹
自動渲染:加載自動渲染在檢測到資料變更時自動重新渲染。
| 屬性 | 描述 |
| --- | --- |
| {{value}}
| 將文字插入到 HTML 標籤中,並隨資料變更自動更新。 |
| :path
| 搭配 temp
標籤,用於將外部文件中的 HTML 片段加載到當前頁面。 |
| :html
| 使用文本替換元素的 innerHTML
。 |
| :for
| 支援 item in items
、(item, index) in items
、(key, value) in object
格式,遍歷資料集合,生成對應的 HTML 元素。 |
| :if
:else-if
:elif
:else
| 根據條件顯示或隱藏元素,實現分支邏輯。 |
| :model
| 將資料綁定到表單元素(如 input
),當輸入變更時自動更新資料。 |
| :hide
| 根據特定條件隱藏元素。 |
| :effect
| 用於指定元素的過渡效果,如 fade-in
或 expand
,以增強用戶體驗。 |
| :mask
| 控制區塊載入時的動畫效果,支援 true|false|1|0
,提升載入動態視覺效果。 |
| :[attr]
| 設定元素屬性,例如 ID
、class
、圖像來源等。範例::id
、:class
、:src
、:alt
、:href
... |
| :[css]
| 設定元素CSS,例如 margin
、padding
等。範例::background-color
、:opacity
、:margin
、:top
、:position
... |
| @[event]
| 添加事件監聽器,當事件觸發時執行指定操作。範例:@click
、@input
、@mousedown
... |
{{value}}
- index.html
<h1>{{ title }}</h1> <script> const app = new QUI({ id: "app", data: { title: "test" } }); </script>
- Result
<body id="app"> <h1>test</h1> </body>
:html
- index.html
<section :html="html"></section> <script> const app = new QUI({ id: "app", data: { html: "<b>innerHtml</b>" } }); </script>
- Result
<body id="app"> <section> <b>innerHtml</b> </section> </body>
[!NOTE] 確保測試時已禁用瀏覽器中的本地文件限制或使用實時服務器。
:path
- test.html
<h1>path heading</h1> <p>path content</p>
- index.html
<body id="app"> <temp :path="./test.html"></temp> </body> <script> const app = new QUI({ id: "app" }); </script>
- Result
<body id="app"> <!-- 直接插入 PATH 內容 --> <h1>path heading</h1> <p>path content</p> </body>
:for
- index.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
<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
<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
<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>
- index.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
<body id="app"> <h1>test 1</h1> </body>
- Result:
heading = null && isH2 = true
<body id="app"> <h2>test </h2> </body>
- Result:
heading = 3 && isH2 = null
<body id="app"> <h3>test 3</h3> </body>
- Result:
heading = null && isH2 = null
<body id="app"> <h4>test </h4> </body>
- index.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
<body id="app"> hint 123 <h1 style="background: red;">test 123</h1> </body>
<body id="app">
<input type="password" :model="password">
<button @click="show">test</button>
</body>
<script>
const app = new QUI({
id: "app",
data: {
password: null,
},
event: {
show: function(e){
alert("Password:", app.data.password);
}
}
});
</script>
<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>
[!NOTE] 支援
:[CSS屬性]
的簡易設定方式,直接將資料綁定到樣式屬性。
- index.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:
<body id="app"> <button style="width: 100px; backdround-color: red;">test</button> </body>
LENGTH()
- index.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
<body id="app"> <p>Total: 4</p> </body>
CALC()
- index.html
<body id="app"> <p>calc: {{ CALC(num * 10) }}</p> </body> <script> const app = new QUI({ id: "app", data: { num: 1 } }); </script>
- result
<body id="app"> <p>calc: 10</p> </body>
UPPER()
/ LOWER()
- index.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
<body id="app"> <p>UPPER lower</p> </body>
DATE(num, format)
- index.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
<body id="app"> <p>2024-08-17 03:40:47</p> </body>
:lazyload
- index.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
<body id="app"> <img src="test.jpg"> </body>
SVG
替換
- test.svg
<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
<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
<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>
[!NOTE] 若為物件格式,直接配置多語言內容。 若為字串格式,會透過
fetch
動態載入語言檔案。
- en.json
{ "greeting": "Hello", "username": "Username" }
- index.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
<body id="app"> <h1>你好, 用戶名: 帕登</h1> <button data-lang="zh">切換至中文</button> <button data-lang="en">Switch to English</button> </body>
- result
i18nLang = en
<body id="app"> <h1>Hello, Username: 帕登</h1> <button data-lang="zh">切換至中文</button> <button data-lang="en">Switch to English</button> </body>
<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>
<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>
開發者
授權條款
本專案依據 MIT 授權使用。
獲取完整原始碼
聯絡我 獲取完整未混淆源碼 可隨意修改、商業使用,根據需求選擇授權版本:
- 需保留
Powered by @pardnchiu/quickui
的版權聲明:$7,500 - 完全自主,無需添加版權聲明:$10,000
©️ 2024 邱敬幃 Pardn Chiu