现在的很多程序应用,基本上都是需要多端覆盖,因此基于一个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的组件使用类似了。

以上就是一些简单组件的封装介绍,我们可以根据实际的需要,把我们 项目中遇到的可以封装的内容提出取出来,然后进行封装为组件的方式,会发现页面维护起来更加方便整洁了。

在组件逐步增多的情况下,我们同步完善一个简单的页面用来测试查看组件的效果,否则组件一多,记起来某个组件的效果就比较困难,我们的一个测试页面例子如下所示。

基于HBuilderX+UniApp+ThorUI的手机端前端的页面组件化开发经验的更多相关文章

  1. 基于HBuilderX+UniApp+ThorUI的手机端前端开发处理

    现在的很多程序应用,基本上都是需要多端覆盖,因此基于一个Web API的后端接口,来构建多端应用,如微信.H5.APP.WInForm.BS的Web管理端等都是常见的应用.本篇随笔概括性的介绍基于HB ...

  2. [js开源组件开发]-手机端照片预览组件

    手机端照片预览组件 可怜的我用着华为3C手机,用别人现成的组件都好卡,为了适应我这种屌丝,于是自己简化写了一版的照片预览效果,暂时无缩放功能,以后可能有空再加吧,你也可以自己加下,这是个github上 ...

  3. 前端web应用组件化(一) 徐飞

    https://github.com/xufei/blog/issues/6 Web应用的组件化(一) 基本思路 1. 为什么要做组件化? 无论前端也好,后端也好,都是整个软件体系的一部分.软件产品也 ...

  4. 基于HBuilderX+UniApp+ColorUi+UniCloud 优宝库 开发实战(一)

    1.   优宝库介绍 优宝库是基于阿里妈妈.淘宝联盟 淘宝商品Api,前端使用HBuilderX + UniApp + ColorUi,后端采用UniClound 精选淘宝商品进行推荐的App程序.下 ...

  5. 专注手机端前端界面开发的ui组件和js组合

    frozenui一款腾讯开发的简化版Bootstrap,只用于手机端 http://frozenui.github.io/ https://github.com/frozenui/frozenui z ...

  6. 判断手机端用户打开页面时是android还是ios,并将判断结果通过ajax返回给url接口,传递回去

    首先判断页面是android还是ios,然后利用ajax将结果通过接口url返回回去,记录到log日志中,以统计android和ios用户访问该页面的数量(数据统计) <script type= ...

  7. 今天需要做手机端访问的页面,所以把meta的整理一下。

    <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale= ...

  8. 手机端web(iPad)页面自适应js

    有关编写手机页面(ipad页面)自适应的方法有很多,比如:bootstrap,rem等等.下面分享给大家一个js控制viewPort视区自适应缩放的方法(我给它命名为phone.js): 将phone ...

  9. 使用 node.js三行代码实现手机端访问html页面文件

    首先确保你安装了node (全局安装) npm install -g browser-sync // --files 路径是相对于运行该命令的项目(目录) browser-sync start --s ...

随机推荐

  1. 一题多解,ASP.NET Core应用启动初始化的N种方案[上篇]

    ASP.NET Core应用本质上就是一个由中间件构成的管道,承载系统将应用承载于一个托管进程中运行起来,其核心任务就是将这个管道构建起来.在ASP.NET Core的发展历史上先后出现了三种应用承载 ...

  2. CF989C A Mist of Florescence 题解

    因为 \(1 \leq a,b,c,d \leq 100\) 所以每一个颜色都有属于自己的联通块. 考虑 \(a = b=c=d=1\) 的情况. AAAAAAAAAAAAAAAAAAAAAAAAAA ...

  3. 腾讯云原生数据库TDSQL-C入选信通院《云原生产品目录》

    近日,中国信通院.云计算开源产业联盟正式对外发布<云原生产品目录>,腾讯云原生数据库TDSQL-C凭借其超强性能.极致效率的弹性伸缩和完善的产品化解决方案体系,成功入围目录. 全球数字经济 ...

  4. JSP页面+请求转发+EL表达式

    1) JSP全称Java Server Pages,顾名思义就是运行在java服务器中的页面,也就是在我们JavaWeb中的动态页面,其本质就是一个Servlet.2) 其本身是一个动态网页技术标准, ...

  5. C++几种特殊形式的函数

    本篇文章主要介绍C++语言中5中特殊形式的函数,分别是带默认形参值的函数.重载函数.内联函数.带形参和返回值的主函数以及递归函数. 一.带默认形参值的函数 如果函数的形参在多数情况下都可以取某个固定的 ...

  6. 管正雄:基于预训练模型、智能运维的QA生成算法落地

    分享嘉宾:管正雄 阿里云 高级算法工程师 出品平台:DataFunTalk 导读:面对海量的用户问题,有限的支持人员该如何高效服务好用户?智能QA生成模型给业务带来的提效以及如何高效地构建算法服务,为 ...

  7. [NOIP2015 提高组] 运输计划题解

    题目链接:P2680 [NOIP2015 提高组] 运输计划 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 看了好长时间题解才终于懂的,有关lca和二分答案的题解解释的不详细,一时 ...

  8. 网格动物UVA1602

    题目大意 输入n,w,h(1<=n<=10,1<=w,h<=n).求能放在w*h网格里的不同的n连块的个数(平移,旋转,翻转算一种) 首先,方法上有两个,一是打表,dfs构造连 ...

  9. 使min-height子元素height百分比生效的2种方式

    方式1,使用flex <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  10. 【Azure 应用服务】PHP应用部署在App Service for Linux环境中,上传文件大于1MB时,遇见了413 Request Entity Too Large 错误的解决方法

    问题描述 在PHP项目部署在App Service后,上传文件如果大于1MB就会遇见 413 Request Entity Too Large 的问题. 问题解决 目前这个问题,首先需要分析应用所在的 ...