0.6.1 • Published 9 months ago

pdquickui v0.6.1

Weekly downloads
-
License
MIT
Repository
github
Last release
9 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

10 months ago

0.2.1

10 months ago

0.2.0

10 months ago

0.5.4

10 months ago

0.5.3

10 months ago

0.5.0

10 months ago

0.4.0

10 months ago

0.6.1

9 months ago

0.5.2

10 months ago

0.6.0

9 months ago

0.5.1

10 months ago

0.1.0

10 months ago