组件封装的几个经验

  • a、参数:最佳方式,仅一个object参数,所需要的实际参数,作为对象属性传入。

    如此,便于数据的处理和扩展。例如,后期扩展需要增加参数,或者调整参数时,如果使用的对象传入,老的调用方法也可以获得兼容;否则,容易出错。

  1. class Picker {
  2. constructor(options) {
  3. // 参数处理
  4. Object.assign(this, {
  5. style: defaultStyle,
  6. liTemplate: defaultLiTemplate,
  7. defaultTarget: [],
  8. isCascade: true
  9. },
  10. options, {
  11. _target: [],
  12. _list: [],
  13. _pElem: null,
  14. _currSequenceNum: [], // 当前插入面板的数据为第n个数据请求,用于处理异步请求时序
  15. _latestSequenceNum: 0, // 最新请求的序号,用于处理异步请求时序
  16. _requestRstBuff: new Map(), // 缓存数据请求的结果,加速数据返回,map结构
  17. _touchIndex: -1, // 标记当前数据请求通过那个面板触发,用于处理异步请求时序 如果有级联,当高级面板触发的请求未结束时,不能继续操作面板
  18. _translateY: [],
  19. _lineHeight: 0
  20. })
  21. }
  22. ......
  23. }
  24. // 调用
  25. new Picker({
  26. getList: () => {
  27. return new Promise((resolve, reject) => {
  28. resolve(xxx)
  29. })
  30. }
  31. })

以picker的封装为例子,传入的为options对象,通过Object.assign方法,可以处理默认值、传入参数、私有参数,并且可以防止相互的覆盖。传入参数优先于默认值,私有参数又优先于传入参数。当函数扩展时,参数数量、位置的变化,不会影响到函数的调用和处理。

  • b、UI和数据的处理

    每一个UI组件,都可以分离成UI部分,与数据部分。UI部分的变更,一般在数据变更后,驱动UI变更,将编译后的DOM string 进行挂载mount。

  • c、数据的处理

  • c1、获取数据

    在做组件封装时,无法知晓相关业务场景涉及的数据是异步还是同步,所以获取数据时,可将数据的实际获取交由业务端处理,组件内只需调用获取数据的封装函数便可。该函数返回的对象为promise,从而将因业务场景不同而产生的变化作为黑盒封装起来。如上面的例子,调用时业务端需要封装getList函数,返回相应的promise。

  1. // 业务逻辑中封装
  2. new Picker({
  3. getList: (target = [], index = 0) => {
  4. return new Promise((resolve, reject) => {
  5. let rst = {
  6. list: [],
  7. isDone: false,
  8. success: true
  9. }
  10. ...
  11. resolve(rst)
  12. })
  13. }
  14. }).init()
  15. // 返回的promise 对象对应数据为obj,包含逻辑处理所需的三个参数:success, list, isDone
  16. this.getList(this._target, index).then(({success, list, isDone}) => {
  17. if (success) {
  18. ...
  19. }
  20. }).catch((err) => {
  21. console.log(err)
  22. })
  • c2、异步请求数据时序控制

    异步请求数据,每个请求到达的时间不同,如发起请求的顺序为: 请求1 -> 请求2 -> 请求3,到达的顺序为:请求3 -> 请求1 -> 请求2,如果不做任何控制,最终使用的数据将会是最终到达的数据,但这个数据却不是最新的结果,将导致错误。因此,需要做异步请求的时序控制,对请求进行编号,当到达的结果时序号小于上一到达的结果时序号时,丢弃。

  1. this._getDataByNet(index).then((rst) => {
  2. // 当请求数据的序列号 大于 已插入面板的数据序列号时,数据有效;否则无效丢弃
  3. if (!mySequenceNum || mySequenceNum > this._currSequenceNum[index]) {
  4. // 存入内存中
  5. this._requestRstBuff.set(targetValue, rst)
  6. resolve(rst)
  7. }
  8. })
  • c3、数据缓存

    异步请求是非常消耗资源的,需要额外的网络时间,并且需要进入时间循环当中。因此,如果可以对相应的数据进行缓存,将一定程度上,提升性能。如sug、picker都可以用到。

  1. // 如果buff中有,则取buff中数据,否则请求数据
  2. if (this._requestRstBuff.has(targetValue)) {
  3. rst = this._requestRstBuff.get(targetValue)
  4. resolve(rst)
  5. } else {
  6. this._getDataByNet(index).then((rst) => {
  7. // 当请求数据的序列号 大于 已插入面板的数据序列号时,数据有效;否则无效丢弃
  8. if (!mySequenceNum || mySequenceNum > this._currSequenceNum[index]) {
  9. // 存入内存中
  10. this._requestRstBuff.set(targetValue, rst)
  11. resolve(rst)
  12. }
  13. })
  14. }
  • d、交互处理

    交互处理之前的一片blog有提到过,需要进行防抖、限頻的处理,特别是进行网络请求和UI频繁更新的交互操作。

  1. _registerUlEvent(ulElem, index) {
  2. let renderTouchUi = throttle(this._renderTouchUi, 50, this)
  3. let handleWholePanel = throttle(this._handleWholePanel, 500, this)
  4. ......
  5. ulElem.addEventListener('touchmove', (event) => {
  6. event.preventDefault()
  7. event.stopPropagation()
  8. if (!(this._touchIndex != -1 && (index + 1) > this._touchIndex && this.isCascade)) {
  9. this._touchIndex = index + 1
  10. touchInfo.currTouchY = event.touches[0].clientY
  11. renderTouchUi(touchInfo, ulElem, index, 'move')
  12. handleWholePanel(index + 1)
  13. }
  14. }, false)
  15. ......
  16. }
  17. // 限頻
  18. _throttle(fn, delay, ctx) {
  19. let isAvail = true
  20. let movement = null
  21. return function() {
  22. let args = arguments
  23. if (isAvail) {
  24. fn.apply(ctx, args)
  25. isAvail = false
  26. clearTimeout(movement)
  27. movement = setTimeout(() => {
  28. isAvail = true
  29. }, delay)
  30. }
  31. }
  32. }

如picker中,通过throttle对touchmove进行限頻处理,UI更新50ms一次,数据更新500ms一次。

由于UI更新将直接作用在用户视觉上,所以更新频率需要根据用户视感需要做调整。

而数据更新,基于以下几点条件,不宜太过频繁:

  • a、touchmove为过程操作,并非touchend一样,为结果操作;
  • b、网络请求需要消耗一定的资源,对服务器、web性能都会造成一定的影响;
  • c、过程操作中,用户需对数据进行筛选,以选择合适的结果,所以数据的更新仍然是有必要的;
  • d、综上所述,限制数据更新的频率,将更符合用户体验要求及性能要求。

picker

picker组件封装了两种,说是picekr组件,其实更倾向于级联组件,相应的数据,具有一定的层级关系。相应的组件说明和使用方法如下。

picker-limited

功能特点
  • a、受UI控制,实现有限级的数据展现;
  • b、请求数据缓存,加速数据返回;
  • c、增加数据请求的时序控制;
  • d、交互touchmove的有效性控制;
  • e、限頻:UI更新50ms/touchmove,数据更新500ms/touchmove; touchend时,立即开启数据请求及UI更新;
  • f、支持级联;
  • g、支持列表单列dom自定义;
  • h、使用getComputedStyle获取行高,保留了小数点更为精确。
调用方法
  1. import Picker from 'src/libs/picker-limited'
  2. new Picker({
  3. // 默认值
  4. defaultTarget: [
  5. {value: 'test1', id: 1},
  6. {value: 'test2', id: 2},
  7. {value: 'test3', id: 3},
  8. {value: 'test4', id: 4}
  9. ],
  10. // 结束回调
  11. done: (info) => {
  12. console.log('info', info)
  13. },
  14. // 数据接口函数 返回promise
  15. getList: (target = [], index = 0) => {
  16. return new Promise((resolve, reject) => {
  17. let rst = {
  18. list: [],
  19. isDone: false,
  20. success: true
  21. }
  22. if (index === 4) {
  23. rst.isDone = true
  24. resolve(rst)
  25. return
  26. }
  27. rst.list = [{
  28. value: 'test1',
  29. id: 1
  30. }, {
  31. value: 'test2',
  32. id: 2
  33. }, {
  34. value: 'test3',
  35. id: 3
  36. }, {
  37. value: 'test4',
  38. id: 4
  39. }]
  40. resolve(rst)
  41. })
  42. }
  43. }).init()
展现

流程图

picker-limitless

功能特点
  • a、可实现无限级数据的展现;
  • b、请求数据缓存,加速数据返回;
  • c、增加数据请求的时序控制;
  • d、支持列表单列dom自定义。
调用方法

与picker-limited一模一样

展现

流程图

因没有太复杂的交互,数据的异步、缓存等处理与picker-limited相近,所以功能流程可自行参考代码。

代码及说明链接

picker code

picker(级联)组件及组件封装经验的更多相关文章

  1. react初探(二)之父子组件通信、封装公共组件

    一.前言 在组件方面react和Vue一样的,核心思想玩的就是组件,下面举两个组件常用的情景. 场景一:假如我们现在有一个页面包含表格以及多个弹框,这种时候如果将这个页面的业务代码写在一个组件中,那么 ...

  2. VUE组件 单独文件封装

    https://www.cnblogs.com/SamWeb/p/6391373.html vuejs 单文件组件.vue 文件   vuejs 自定义了一种.vue文件,可以把html, css, ...

  3. uniapp自定义picker城市多级联动组件

    uniapp自定义picker城市多级联动组件 支持多端--h5.app.微信小程序.支付宝小程序... 支持自定义配置picker插件级数 支持无限级 注意事项:插件传入数据格式为children树 ...

  4. 从零搭建react+ts组件库(封装antd)

    为什么会有这样一篇文章?因为网上的教程/示例只说了怎么做,没有系统详细的介绍引入这些依赖.为什么要这样配置,甚至有些文章还是错的!迫于技术洁癖,我希望更多的开发小伙伴能够真正的理解一个项目搭建各个方面 ...

  5. Vue.js与ElementUI搭建无限级联层级表格组件

    前言 今天,回老家了.第一件事就是回家把大屏安排上,写作的感觉太爽了,终于可以专心地写文章了.我们今天要做的项目是怎么样搭建一个无限级联层级表格组件,好了,多了不多说,赶快行动起来吧!项目一览 到底是 ...

  6. React 面向组件化编程 - 封装了webpack - npm run build 产生的包的 /static 引用路径问题

    React 面向组件化编程 面向对象 ----> 面向模块 ----> 面向组件 套路: 注意: 组件名必须大写开头: 只能有一个根标签: <input />虚拟DOM 元素必 ...

  7. Vue.js学习 Item11 – 组件与组件间的通信

    什么是组件? 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能.在有 ...

  8. $Django Rest Framework-认证组件,权限组件 知识点回顾choices,on_delete

    一 小知识点回顾 #orm class UserInfo (models.Model): id = models.AutoField (primary_key=True) name = models. ...

  9. slot是标签的内容扩展,也就是说你用slot就可以在自定义组件时传递给组件内容,组件接收内容并输出

    html 父页面<div id="app"> <register> <span slot="name">{{message. ...

  10. drf框架 - 三大认证组件 | 认证组件 | 权限组件 | 频率组件

    RBAC 基于用户权限访问控制的认证 - Role-Based Access Control Django框架采用的是RBAC认证规则,RBAC认证规则通常会分为 三表规则.五表规则,Django采用 ...

随机推荐

  1. hdu 1443 Joseph【约瑟夫环】

    题目 题意:一共有2k个人,分别为k个好人和k个坏人,现在我们需要每隔m个人把坏人挑出来,但是条件是最后一个坏人挑出来前不能有好人被挑出来..问最小的m是多少 约瑟夫环问题,通常解决这类问题时我们把编 ...

  2. hdu 5060 五种情况求圆柱体与球体交

    http://acm.hdu.edu.cn/showproblem.php?pid=5060 官方题解http://bestcoder.hdu.edu.cn/给复杂了 实际上用圆柱体与球体体积差的积分 ...

  3. SRM484

    又Orz了一发rng_58.. 250pt: 题意:给定一种兔子数:当S(x*x) = S(x)*S(x)时,x为兔子数,其中S(x)表示各个数位之和. 思路:本来想了一个复杂度很高的想法..然后想看 ...

  4. spring mvc请求过程

    spring mvc处理请求过程 1.    首先客户端发送一个HTTP请求,Web服务器接收这个请求,如果匹配DispatcherServlet的请求映射路径,web容器将请求转交给Dispatch ...

  5. Elasticsearch 系列1 --- Windows10安装Elasticsearch

    在Windows环境下,ES提供了两种安装方式,一种是通过MSI,特点是简单方便:另一种是绿色安装,解压zip包.本文选择第二种方式. 1. 准备工作 (1) Windows 10 (2) JDK 1 ...

  6. 使用JAVA API 解析ORC File

    使用JAVA API 解析ORC File orc File 的解析过程中,使用FileInputFormat的getSplits(conf, 1)函数, 然后使用 RecordReaderreade ...

  7. 新品成熟EMR源码电子病历系统软件NET网络版CS可用带数据库全文档

    查看电子病历系统演示 医院医疗信息管理系统,EMR电子病历系统,功能模块如下所示: 1.住院医生站 2.住院护士站 3.病案浏览工作站 4.质量控制工作站 5.系统维护工作站  本店出售系统全套源码, ...

  8. KVM虚拟机配置

    KVM 全称是 Kernel-Based Virtual Machine.也就是说 KVM 是基于 Linux 内核实现的,KVM有一个内核模块叫 kvm.ko,只用于管理虚拟 CPU 和内存. 在 ...

  9. Ms17-010进行WEB提权之实践下某培训靶机服务器

    前言:该机器为某个其他培训机构的靶机,说实话在这里没炫耀啥,只是给各位学习Ms17010的同学指一条路,我原先也折腾这玩意儿好久,但是就是不行,最近才找到了出路,所以多写两篇文章,把各种需要注意的地方 ...

  10. 移动端font-size适配方案

    概述 这是我研究移动端页面时的思考,记录下来供以后开发时参考,相信对其他人也有用.由于我写移动端页面写的还比较少,一些问题都还没遇到,所以我的这篇博文不免有些错误的地方,还请大佬多多指正. 这篇文章是 ...