現在的很多程式應用,基本上都是需要多端覆蓋,因此基於一個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