0.6.1 • Published 7 months ago

pdquickui v0.6.1

Weekly downloads
-
License
MIT
Repository
github
Last release
7 months ago

QuickUI

(原名:PDQuickUI,自 0.6.0 版本起更名為 QuickUI)

tag size license npm download jsdeliver npm.io

QuickUI 是從 PDRenderKit 中獨立出來的前端渲染框架,專注於強化前端框架功能。 透過引入虛擬 DOM 概念重寫渲染邏輯,提升渲染效能,並實現更高效的數據監聽和自動更新。

本專案移除了 PDRenderKit 中針對 prototype 的擴展,確保兼容性與效能,適合用於複雜的應用場景。 提供 module 和非 module 版本,授權從 PDRenderKitGPL-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-inexpand,以增強用戶體驗。
:mask控制區塊載入時的動畫效果,支援 true|false|1|0,提升載入動態視覺效果。
:[attr]設定元素屬性,例如 IDclass、圖像來源等。範例::id:class:src:alt:href...
:[css]設定元素CSS,例如 marginpadding 等。範例::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>

開發者

npm.io npm.io

授權條款

本專案依據 MIT 授權使用。

獲取完整原始碼

聯絡我 獲取完整未混淆源碼 可隨意修改、商業使用,根據需求選擇授權版本:

  • 需保留 Powered by @pardnchiu/quickui 的版權聲明:$7,500
  • 完全自主,無需添加版權聲明:$10,000

©️ 2024 邱敬幃 Pardn Chiu

0.3.0

7 months ago

0.2.1

7 months ago

0.2.0

8 months ago

0.5.4

7 months ago

0.5.3

7 months ago

0.5.0

7 months ago

0.4.0

7 months ago

0.6.1

7 months ago

0.5.2

7 months ago

0.6.0

7 months ago

0.5.1

7 months ago

0.1.0

8 months ago