资讯专栏INFORMATION COLUMN

使用Vue的HOC技术开发一个无限加载列表

stefan / 1100人阅读

摘要:高阶组件的概念,是里面经常提到的,类似于高阶函数。高阶函数高阶组件高阶组件用是代码复用的优秀工具,主要在处理逻辑方面和普适性上,有着奇效。

前言

在web开发上,我们都对数据采用分页加载的机制,一种变形就是在页面采用循环加载的机制,拉到页面最下方有个加载更多的按钮。问题在于,当不同的数据要展示时,就要写很多这种列表,但是其中的逻辑都是相似的。

维护一组数据

加载更多数据

将数据用对应的组件显示出来

处理加载状态等

那有没有这么一个组件,来完成这一切相同的逻辑呢?

需求

需要有这么一个InfiniteList组件,它负责管理相关数据的加载和维护,然后以列表的形式显示出来,而列表项必须是由调用方决定的组件

HOC

高阶组件的概念,是React里面经常提到的,类似于高阶函数。
高阶函数:(fn) => otherFn
高阶组件:component => otherComponent
高阶组件用是代码复用的优秀工具,主要在处理逻辑方面和普适性上,有着奇效。

所以我决定用HOC来实现这个需求

参考文章:http://hcysun.me/2018/01/05/%...
良心博客
本文涉及的知识

vue

vue的render函数

实现 0

我使用的是vue和iview UI库

1

先弄出UI框架先,我用一个vue文件来构建整个组件的基本框架。源代码地址

html部分

用一个slot来分发要循环渲染的项目

js部分

一些UI有关的数据(不是很重要)

 props: {
      loadTip: {
        type: String,
        default: "加载更多"
      }
      ...
    },
    computed: {
      loadButtonText() {},
      tipIcon() {}
    }

这部分比较重要的只有一个事件发射,将点按钮的行为转换为 请求加载数据

handleClickLoad() {
        // 发射 请求加载数据的 事件
        this.$emit("on-load");
      }

css部分略

2

接下来就是最重要的部分,编写HOC
首先要明白,Vue中的组件,到底是什么。像我们写一个Vue文件,export出的是一个对象,所以我们现在写HOC,其实也是要最后返回一个对象。
所以我写了下面的函数来生成HOC

/**
 * 使用高阶组件的办法实现了一个无限加载列表
 * 可以根据数据循环渲染出特定的组件,并且管理加载状态
 * @param component 具体项的组件 {props: {data}}
*/
function InfiniteList(listItem) {
    return {
        props:...
        data(){}
        ...
    }
}

而我们如果渲染呢,当然是用Vue的render函数

render(h) {
    return h(component, data, children);
}

我们使用组合的方式,最外层需要用到我们第1步写到的模板,于是导入它,并注册它

import InfiniteListTemplate from "./InfiniteListTemplate";
function InfiniteList(listItem) {
    return {
        ...
        components: {
          InfiniteListTemplate  //  列表框架的模板,这个模板里面只有ui表现
        },
        ...
    }
}

render函数对于熟悉React的程序员来说应该是不难的,官网也有很详细的介绍。

render(h) {
      const self = this;
      // 根据 data 的 dataList循环渲染子组件
      const listItems = ...

      return h(InfiniteListTemplate, {
        props: {
          ...self.$props, // 传递所有参数
          hasMore: self.hasMore,  // 另外的hasMore和loading是这个HOC的state
          loading: self.loading
        },
        attrs: self.$attrs,
        on: {
          // 监听加载按钮事件
          "on-load": () => self.handleLoadData()
        }
      }, listItems);
    },

这里在最外层渲染我们的模板(且称为模板组件),并将当前HOC的props,attrs传递给模板组件。
这里提到了HOC的data,非常简单,就是两个状态和一个数据数组

data() {
      return {
        hasMore: true,
        loading: false,
        dataList: []
      }
    }

然后呢,循环渲染在哪?别急,render中的listItems就是我们循环渲染出来的组件,这里使用了map,相信使用React的人非常熟悉这种风格

const listItems = this.dataList.map(item => h(component, {
            props: {
              data: item
            }
          })
        );

最终返回的就是

return h(InfiniteListTemplate, {options}, listItems);

在哪里维护数据呢?当然是要传入一个加载数据的函数来进行管理,我们在HOC的props里面定义

props: {
      tipColor,
      loadTip,
      loadingTip,
      // 上面的数据都是为了传给模板(组件)
      offset: {
        type: Number,
        default: 5
      },
      // 数据加载的函数,需要的是一个 (index, offset) => Promise<[]>
      loadDataFunc: {
        type: Function,
        default() {
          return (index, offset) => Promise.resolve(new Array(offset).map((o, i) => index + i));
        }
      }
    },

然后我们还记得模板函数发射了个on-load事件么?我们需要在HOC里监听它并且处理逻辑

render(h) {
    return h(InfiniteListTemplate, {
        ...
        on: {
            "on-load": () => self.handleLoadData()
        }
    }, listItems);
},
methods: {
      /**
       * 监听模板点出了加载按钮时的操作
       * 调用数据加载函数加载数据
       * @return {Promise}
       */
      async handleLoadData() {
        try {
          this.loading = true;
          let res = await this.loadDataFunc(this.dataList.length, this.offset);
          if (res && res.length) {
            this.dataList = this.dataList.concat(res);
            this.$Message.success(`成功获取到${res.length}条新数据`);
          } else {
            this.$Message.info(`已经获取了全部数据了`);
            this.hasMore = false;
          }
        } catch (e) {
          this.$Message.error("加载失败" + e.message);
        } finally {
          this.loading = false;
        }
      }
    },

完整InfiniteList.js代码

3

接下来使用一遍




MyComponent.vue是个非常简单的组件



效果图如下

总结

在前端开发过程中,HOC是代码利用的利器,但是对抽象的要求高。
我觉得自己爱上了React...Vue实现这个HOC烦死了

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100857.html

相关文章

  • 02.react进阶指南

    摘要:指定读取当前的。它为其后代元素触发额外的检查和警告。严格模式检查仅在开发模式下运行它们不会影响生产构建。作用识别不安全的生命周期关于使用过时字符串的警告关于使用废弃的方法的警告检测意外的副作用检测过时的为高阶组件。 react 进阶 懒加载 React.lazy函数能让你像渲染常规组件一样处理动态引入(的组件)。Suspense加载指示器为组件做优雅降级。fallback属性接受任何在...

    zzbo 评论0 收藏0
  • 基于 Vue.js 移动端组件库mint-ui实现无限滚动加载更多

    摘要:网上找到很多的组件来实现上拉加载更多,由于上拉触发相应的加载更多事件,所以当进入页面的时候应该不会自动载入数据,则这里可以加一个获取第一页数据的函数。 通过多次爬坑,发现了这些监听滚动来加载更多的组件的共同点, 因为这些加载更多的方法是绑定在需要加载更多的内容的元素上的, 所以是进入页面则直接触发一次,当监听到滚动事件之后,继续加载更多, 所以对于无限滚动加载不需要写首次载入列表的函数...

    huayeluoliuhen 评论0 收藏0
  • React 328道最全面试题(持续更新)

    摘要:希望大家在这浮夸的前端圈里,保持冷静,坚持每天花分钟来学习与思考。 今天的React题没有太多的故事…… 半个月前出了248个Vue的知识点,受到很多朋友的关注,都强烈要求再出多些React相前的面试题,受到大家的邀请,我又找了20多个React的使用者,他们给出了328道React的面试题,由我整理好发给大家,同时发布在了前端面试每日3+1的React专题,希望对大家有所帮助,同时大...

    kumfo 评论0 收藏0
  • 可靠React组件设计7个准则之SRP

    摘要:编写组件时要考虑的基本准则是单一职责原则。这些更改通常要求组件在隔离状态下易于修改这也是的目标。解决多重责任问题需要将分割为两个组件和。组件之间的通信是通过实现。更改的唯一原因是修改表单字段。 翻译:刘小夕原文链接:https://dmitripavlutin.com/7-... 原文的篇幅非常长,不过内容太过于吸引我,还是忍不住要翻译出来。此篇文章对编写可重用和可维护的React组...

    Charles 评论0 收藏0
  • 使用Vue2+webpack+Es6快速开发一个移动端项目,封装属于自己jsonpAPI和手势响应

    摘要:导语最近看到不少使用制作的音乐播放器,挺好玩的,本来工作中也经常使用,一起交流学习,好的话点个哦本项目特点如下原生封装自己的跨域请求函数,支持调用,支持错误处理制作一些复用性强的组件,如轮播图组件,支持手势滑动,无限循环,图片按需加载 showImg(http://upload-images.jianshu.io/upload_images/4149586-1849aa83e2decf...

    lemanli 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<