基於HBuilderX+UniApp+ThorUI的手機端前端的頁面組件化開發經驗

来源:https://www.cnblogs.com/wuhuacong/archive/2022/09/20/16708288.html
-Advertisement-
Play Games

現在的很多程式應用,基本上都是需要多端覆蓋,因此基於一個Web API的後端介面,來構建多端應用,如微信、H5、APP、WInForm、BS的Web管理端等都是常見的應用。本篇隨筆繼續分析總結一下項目開發的經驗,針對頁面組件化開發經驗方面進行一些梳理總結,內容包括組件的概念介紹,簡單頁面組件的抽取開... ...


現在的很多程式應用,基本上都是需要多端覆蓋,因此基於一個Web API的後端介面,來構建多端應用,如微信、H5、APP、WInForm、BS的Web管理端等都是常見的應用。本篇隨筆繼續分析總結一下項目開發的經驗,針對頁面組件化開發經驗方面進行一些梳理總結,內容包括組件的概念介紹,簡單頁面組件的抽取開發,以及對控制項值進行更改的頁面組件的處理等,希望能夠對大家有所啟發。

1、Vue組件的概念

組件是Vue中的一個重要概念,是一個可以重覆使用的Vue實例,它擁有獨一無二的組件名稱,它可以擴展HTML元素,以組件名稱的方式作為自定義的HTML標簽。因為組件是可復用的Vue實例,所以它們與new Vue()接收相同的選項,例如data,computed、watch、methods以及生命周期鉤子等。 

組件是可復用的 Vue 實例, 把一些公共的模塊抽取出來,然後寫成單獨的的工具組件或者頁面,在需要的頁面中就直接引入即可那麼我們可以將其抽出為一個組件進行復用。例如 頁面頭部、側邊、內容區,尾部,上傳圖片,等多個頁面要用到一樣的就可以做成組件,提高了代碼的復用率。

Vue的前端界面,對界面內容部分可以根據需要進行適當的拆分,也可以把通用的部分封裝為組件進行使用。如果整體界面內容比較多,可以進行拆分,根據內容的展示不同,拆分為各自的組件模塊,然後合併使用即可,如下所示。

在對象UML的圖例中,應該是如下所示的效果圖,組織機構包含組織成員和角色的內容。

在界面上,組織成員還需要添加成員的功能,同理角色也需要添加角色的處理,如下圖示。

角色界面模塊的內容劃分圖如下所示。 

實際頁面組件的開發,也可以按照內容的劃分方式進行組件的開發,然後將它們組合起來。

如果我們開發了很多不同業務場景的組件,那麼在實際頁面中,就可以對它們進行組合使用,提高頁面的整潔,同時也便於代碼的維護。

組件的拆分和封裝,是我們前端開發中非常重要的部分,也是我們快速構建複雜頁面功能的,又能輕鬆應對的必殺技之一。 

 例如對於一個異常信息的處理,我們整合了多個模塊的內容進行展示,採用自定義組件的方式,可以減少很多繁雜的前端代碼。

 上面頁面的大部分都是自定義組件的整合使用,如下代碼截圖所示。

 需要使用的組件,在Vue的JS代碼中導入組件即可

2、簡單頁面組件的抽取開發

例如在一些新錄入內容的頁面中,我們往往有一些類似人員和時間的信息需要展示,可以把它做成一個簡單的頁面組件模塊

如果用戶是創建新記錄的,那麼顯示當前登錄的用戶名稱和當前日期,如果是已有記錄,則顯示記錄中的用戶和時間即可,一個很簡單的例子。

<!--通用填報信息展示,用於創建新記錄或者明細的展示-->
<template>
    <view class="">
        <view class="tui-order-info">
            <tui-list-cell :hover="false" :arrow="showArrow" @click="showDetail">
                <view class="tui-order-title">
                    <view>{{title}}</view>
                    <view class="tui-order-status" :style="{color:subTitleColor}">
                        {{subTitle}}
                    </view>
                </view>
            </tui-list-cell>
            <view class="tui-order-content" v-show="visible">
                <view class="tui-order-flex">
                    <view class="tui-item-title">填報時間:</view>
                    <view class="tui-item-content">{{currentDate}}</view>
                    <view style="padding-right: 50rpx;"></view>
                    <view class="tui-item-title">填報人:</view>
                    <view class="tui-item-content">
                        {{currentUser}}
                    </view>
                </view>
            </view>
        </view>
    </view>
</template>

信息填報的標題中,單擊可以切換摺疊或者展示模式,通過事件showDetail 進行觸發的,而內容這裡通過visible屬性進行控制,同時接收來時Props屬性的detailVisible的初始化設置。

在Props的父傳子屬性中,我們定義了一些通用數據屬性,如標題、副標題、當前時間和填報人等。

<script>
    export default {
        emits: ['click', 'cancel'],
        props: {
            title: {
                type: String,
                default: "信息填報"
            },
            subTitle: {
                type: String,
                default: ""
            },
            subTitleColor: {
                type: String,
                default: ""
            },
            showArrow: { //預設是否展示箭頭
                type: Boolean,
                default: false
            },
            creator: {
                type: String,
                default: ""
            },
            createTime: {
                type: String,
                default: ""
            },
            detailVisible: { //預設是否展示詳情內容
                type: Boolean,
                default: true
            },
        },

另外,我們在data中添加一個組件屬性visbile屬性,

data() {
    return {
        visible: true
    }
},

這是因為傳入的detailVisible不能在組件中中修改其屬性值,因此接收它的值,並讓她賦值給局部的屬性,這種做法是常見的處理方式。為了同時保持兩個屬性的一致,我們通過Created事件中初始化局部變數,並通過Watch監控數據的變化。

created() {
    this.visible = this.detailVisible;
},
watch: {
    detailVisible(val) {
        this.visible = val
    }
},

當前用戶名稱和日期,我們判斷傳遞的屬性是否為空值,非空則使用傳遞的值,否則使用當前用戶身份和當前日期值,因此我們通過一個計算屬性來判斷,如下所示。

computed: {
    currentUser() {
        if (uni.$u.test.isEmpty(this.creator)) {
            return this.vuex_user?.info?.fullName;
        } else {
            return this.creator;
        }
    },
    currentDate() {
        if (uni.$u.test.isEmpty(this.createTime)) {
            return uni.$u.time.timeFormat();
        } else {
            return uni.$u.time.timeFormat(this.createTime);
        }
    }
},

這裡面的 this.vuex_user?.info?.fullName 是我們通過Vuex的方式存儲的一個當前用戶身份的信息,通過?來判斷是否非空。另外,我們對list-cell的事件進行處理,切換摺疊和展開的處理,因此只需要設置局部變數visible的屬性即可。

methods: {
    showDetail() {
        this.visible = !this.visible;
    }
}

這樣定義好的頁面內容後,我們只需要把它加入到頁面組件中就可以使用它了

<script>
    import createinfo from '@/pages/components/createinfo.vue';
    export default {
        components: {
            createinfo
        },

HTML代碼和其他簡單的HTML常規組件類似。

<createinfo></createinfo>

或者傳入數據處理

<createinfo :createTime="entity.createTime" :creator="entity.deliverName"></createinfo>

另外,如果我們需要在內部保留一塊區域給父頁面定義的模板,可以使用Slot進行處理,這樣除了添加了人員和日期信息,我們還可以嵌入一個更多內容信息作為區塊給組件進行展示了。

<template>
    <view class="">
        <view class="tui-order-info">
            <tui-list-cell :hover="false" :arrow="showArrow" @click="showDetail">
                <view class="tui-order-title">
                    <view>{{title}}</view>
                    <view class="tui-order-status" :style="{color:subTitleColor}">
                        {{subTitle}}
                    </view>
                </view>
            </tui-list-cell>
            <view class="tui-order-content" v-show="visible">
                <slot #default>
                    <!--                 
                    <view class="tui-order-flex">
                        <view class="tui-item-title">角色編碼</view>
                        <view class="tui-item-content">123456</view>    
                    </view>
                    -->
                </slot>
            </view>
        </view>
    </view>
</template>

 

3、對控制項值進行更改的頁面組件的處理

除了上面的閉合組件,我們有時候也需要一個傳遞信息和變更v-model的值的處理,或者拋出一些事件給父頁面進行通知。

例如,我們在選擇一些系統數據字典項目的時候,以及在選擇時間的時候,這些是比較常見的操作,我們可以結合我們的組件庫,做一些簡單的組件封裝,從而達到簡化頁面使用的目的。

如果沒有自定義組件的情況,我們使用字典模塊的內容,需要請求對應的字典列表,然後綁定在控制項Picker中,如下代碼所示。

<tui-list-cell arrow padding="0" @click="showPicker = true">
    <tui-input required backgroundColor="transparent" :borderBottom="false" label="送貨區域"
        placeholder="請選擇送貨區域" v-model="formData.deliveryArea" disabled></tui-input>
</tui-list-cell>

<tui-picker :show="showPicker" :pickerData="areas" @hide="showPicker = false" @change="changePicker">
</tui-picker>

在頁面的JS腳本處理中,還需要對字典類型進行取值、以及選擇後修改屬性值等操作處理

<script>
    import dict from '@/api/dictdata.js'
    
    export default {
    data() {
        return {
            showPicker: false,
            areas: [
                // {text: "中國", value: "1001"},
            ]
        }    
    },
    created() {
        dict.GetListItemByDictType("送貨區域").then(res => {
            this.areas = res;
        })
        dict.GetListItemByDictType("客戶等級").then(res => {
            this.grades = res;
        })
    },
    methods: {
        changePicker(e) {
            this.formData.deliveryArea = e.value;
        }
    }
  }
  </script>

一頓操作下來還是比較麻煩的,但是如果你使用自定義用戶組件來操作,那麼代碼量迅速降低,如下所示。

<createinfo>
    <view class="tui-bg-img"></view>
    <dict-items-picker v-model="formData.deliveryArea" dictTypeName="送貨區域" label="送貨區域"></dict-items-picker>
    <dict-items-picker v-model="formData.grade" dictTypeName="供貨檔級" label="供貨檔級"></dict-items-picker>
</createinfo>

獲得的界面效果如下所示,是不是感覺更好,代碼更整潔了。

 

 而其他部分的代碼,則只是包括了引入組件的代碼即可。

import dictItemsPicker from '@/pages/components/dict-items-picker.vue'
export default {
    components: {
        dictItemsPicker
    },

上面組件的dictTypeName 對應的是資料庫後臺的字典類型名稱,根據名稱,從組件中調用api類獲得數據即可,頁面則不需要干涉這些邏輯了。其中我們自定義組件中使用 v-model 來綁定選擇的值到頁面的data屬性中。

我們來看看整個頁面組件的全部代碼(內容不多,就一次性貼出來)

<!--通用字典下拉框展示-->
<template>
    <view class="">
        <tui-list-cell arrow padding="0" @click="showPicker = true">
            <tui-input :required="required" backgroundColor="transparent" :borderBottom="false" :label="labelName"
                :placeholder="placeholder" v-model="value" disabled></tui-input>
        </tui-list-cell>
        <tui-picker :show="showPicker" :pickerData="dictItems" @hide="showPicker = false" @change="changePicker">
        </tui-picker>
    </view>
</template>

<script>
    import dict from '@/api/dictdata.js'
    export default {
        emits: ['click', 'cancel', 'update:value', 'change'],
        props: {
            required: { //是否必選
                type: Boolean,
                default: false
            },
            dictTypeName: {
                type: String,
                default: ""
            },
            options: {
                type: Array,
                default () {
                    return []
                }
            },
            value: {
                type: String,
                default: ""
            },
            label: {
                type: String,
                default: ""
            }
        },
        components: {},
        data() {
            return {
                showPicker: false,
                dictItems: []
            }
        },
        mounted() {
            if (!uni.$u.test.isEmpty(this.dictTypeName)) {
                dict.GetListItemByDictType(this.dictTypeName).then(res => {
                    this.dictItems = res;
                })
            } else {
                this.dictItems = this.options;
            }
        },
        watch: {},
        computed: {
            placeholder() {
                return "請選擇" + this.dictTypeName;
            },
            labelName() {
                if (this.label) {
                    return this.label;
                } else if (!uni.$u.test.isEmpty(this.dictTypeName)) {
                    return this.dictTypeName
                } else {
                    return ""
                }
            }
        },
        methods: {
            changePicker(e) {
                this.$emit('change', e)
                this.$emit("input", e.value)
                this.$emit("update:value", e.value);
            }
        }
    }
</script>

這裡在內部組件的值變化的時候,通過事件 this.$emit("update:value", e.value); 進行通知更新父組件的綁定值,而 this.$emit("input", e.value)事件則是更新內部包含的input組件的值,同時提供一個change的事件進行完整的通知處理。

由於我們傳遞的是DIctTypeName,組件內部在Mounted的事件後進行獲取字典的內容,並將返回值更新到內部組件中去。,如果是靜態的字典集合,可以通過options 進行賦值即可。

if (!uni.$u.test.isEmpty(this.dictTypeName)) {
    dict.GetListItemByDictType(this.dictTypeName).then(res => {
        this.dictItems = res;
    })
} else {
    this.dictItems = this.options;
}

因此該組件可以接受系統數據字典的字典類型名稱,或者接受靜態的字典列表作為數據源供選擇需要。

整個組件內部封裝了讀取數據的細節以及展示控制項的處理,並將新值通過事件this.$emit("update:value", e.value); 的方式更新父頁面的v-modal的綁定值,因此看起來和一個簡單的Input的組件使用類似了。

以上就是一些簡單組件的封裝介紹,我們可以根據實際的需要,把我們 項目中遇到的可以封裝的內容提出取出來,然後進行封裝為組件的方式,會發現頁面維護起來更加方便整潔了。

在組件逐步增多的情況下,我們同步完善一個簡單的頁面用來測試查看組件的效果,否則組件一多,記起來某個組件的效果就比較困難,我們的一個測試頁面例子如下所示。

 

專註於代碼生成工具、.Net/.NetCore 框架架構及軟體開發,以及各種Vue.js的前端技術應用。著有Winform開發框架/混合式開發框架、微信開發框架、Bootstrap開發框架、ABP開發框架、SqlSugar開發框架等框架產品。
  轉載請註明出處:撰寫人:伍華聰  http://www.iqidi.com 
    

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 2022-09-20 Redis——select Redis資料庫中的資料庫的個數為: 16個,使用0號資料庫開始的,到第15個資料庫結束。 在ubantu中,進入Redis客戶端的命令: redis-cli 在ubantu中,如果選擇第0-15個資料庫中的一個的命令,例如第0個: select 0 ...
  • 一、直播介紹 前幾期,我們為大家分享了ChunJun的數據還原、Hive事務表及傳輸模塊的一些內容,本期我們為大家分享ChunJun類載入原理與實現。 本次直播我們將從Java 類載入器解決類衝突基本思想、Flink 類載入器隔離的方案、ChunJun如何實現類載入器隔離及問題排查等方面為大家進行介 ...
  • 1.創建容器併進行持久化處理 #拉取鏡像 docker pull mysql:8.0.20 #啟動鏡像,用於拷貝配置文件到宿主機 docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:8.0.20 #查 ...
  • 更多技術交流、求職機會,歡迎關註位元組跳動數據平臺微信公眾號,回覆【1】進入官方交流群 摘要 位元組數據中台DataLeap的Data Catalog系統通過接收MQ中的近實時消息來同步部分元數據。Apache Atlas對於實時消息的消費處理不滿足性能要求,內部使用Flink任務的處理方案在ToB場景 ...
  • 2022 年 9 月 16 日,由中國信息通信研究院(以下簡稱“信通院”)主辦的“2022 OSCAR 開源產業大會"活動於北京成功舉辦。會上宣佈,StoneDB 發起廠商杭州石原子科技有限公司正式加入信通院“科技製造開源社區(TMOSC)”,未來石原子將與信通院及各成員單位一起聚焦可信開源全景,推 ...
  • 本篇為Redis性能問題診斷系列的第四篇,也是最後一篇,主要從應用程式、系統、伺服器硬體及網路系統等層面上進行講解,重點分享了哪些配置需要重點關註和調整優化,才能最大程度的發揮Redis的處理能力; ...
  • 一.起步 1.1 配置uni-app開發環境 什麼是uni-app,就是基於vue的一個開發框架,可以將我們寫的一套代碼,同時發佈到ios、安卓、小程式等多個平臺 ==官方推薦使用Hbuilderx來寫uni-app項目== 下載之後可以將預設改為vscode 進入hbuilder插件市場下載scs ...
  • 前端技術的發展不斷融入了很多後端的思想,逐步形成前端的 ”四個現代化“:工程化、模塊化、規範化、流程化。這個主題介紹 *模塊化* ,主要內容包括模塊化前傳(早期模塊化的實現)、模塊化的四個規範(Common JS、AMD、CMD、ESM)。本文就聊聊早期的模塊化。 ...
一周排行
    -Advertisement-
    Play Games
  • 1、預覽地址:http://139.155.137.144:9012 2、qq群:801913255 一、前言 隨著網路的發展,企業對於信息系統數據的保密工作愈發重視,不同身份、角色對於數據的訪問許可權都應該大相徑庭。 列如 1、不同登錄人員對一個數據列表的可見度是不一樣的,如數據列、數據行、數據按鈕 ...
  • 前言 上一篇文章寫瞭如何使用RabbitMQ做個簡單的發送郵件項目,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的消息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧! 在瞭解簡單工廠模式之前,我們要知道C#是一款面向對象的高級程式語言。它有3大特性,封裝、繼承、多態。 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 介紹 Nodify是一個WPF基於節點的編輯器控制項,其中包含一系列節點、連接和連接器組件,旨在簡化構建基於節點的工具的過程 ...
  • 創建一個webapi項目做測試使用。 創建新控制器,搭建一個基礎框架,包括獲取當天日期、wiki的請求地址等 創建一個Http請求幫助類以及方法,用於獲取指定URL的信息 使用http請求訪問指定url,先運行一下,看看返回的內容。內容如圖右邊所示,實際上是一個Json數據。我們主要解析 大事記 部 ...
  • 最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太瞭解,尤其是對2016年6月發佈的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之後,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 添加節點(nodes) 通過上一篇我們已經創建好了編輯器實例現在我們為編輯器添加一個節點 添加model和viewmode ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
  • 類型檢查和轉換:當你需要檢查對象是否為特定類型,並且希望在同一時間內將其轉換為那個類型時,模式匹配提供了一種更簡潔的方式來完成這一任務,避免了使用傳統的as和is操作符後還需要進行額外的null檢查。 複雜條件邏輯:在處理複雜的條件邏輯時,特別是涉及到多個條件和類型的情況下,使用模式匹配可以使代碼更 ...
  • 在日常開發中,我們經常需要和文件打交道,特別是桌面開發,有時候就會需要載入大批量的文件,而且可能還會存在部分文件缺失的情況,那麼如何才能快速的判斷文件是否存在呢?如果處理不當的,且文件數量比較多的時候,可能會造成卡頓等情況,進而影響程式的使用體驗。今天就以一個簡單的小例子,簡述兩種不同的判斷文件是否... ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...