介绍三个React组件

React Component

简单介绍三个React组件吧。

  • Image
  • Table
  • Form

React-Image

源码 Demo

一个用于加载/预览图片的组件

Image

  • 自动管理图片的loadingerror状态, 并显示不同提示.
  • 通过IntersectionObserver来实现图片懒加载
  • 默认使用Preview来进行图片预览
  • 可以通过group来管理图片预览列表, 同一个group的图片会出现在预览列表中
import { Image } from '@zzwing/react-image'

;<Image src='any.jpg' width='200px' height='200px' onClick={this.onClick} />

Preview

图片浏览器, 可以放大/移动/切换等. 已集成到Image中, 可以通过preview={false}关闭预览功能. 也可以直接通过api调用

import { PreviewApi } from '@zzwing/react-image'
const list = ['1.jpg', '2.jpg', '3.jpg']
// use index
PreviewApi.preview(2, list)
// or use src
PreviewApi.preview('2.jpg', list)

  

React-Table

源码 Demo

可固定表头及两侧的表格.

antd的表格

antd的表格也能满足该功能, 但也有几个不足点(我个人觉得)

  • 要求每一列都要写入width用来固定列宽: 通过拆分theadtbody来固定表头, 通过colgroup来完成列宽的固定
  • 表格高度不能自适应(有可能我使用方式不对?)
  • 还有一点就是antd的表格功能太强大, 有很多功能我是用不上, 无形中增加了代码.

解决方法

指定表格的scrollTarget, 既滚动的目标, 默认是document.scrollingElement.

  • 当表头滚动到顶部时, 使用transform固定,由于属于同一个table, 这样能解决tbodythead不对齐的问题.
  • 固定两侧是通过table冗余实现(antd也是如此), 但只会冗余需要固定的部分。通过absolute + padding 实现两侧固定.
  • 最后通过不同表格的同一行中的最大高度, 来设定其他表格该行的高度, 来达到高度同步
  • 由于表格高度超过容器高度, 横向滚动条会被'隐藏', 因此提供了一个scroller来模拟横向滚动条, 也就是说任何时候都可以拉动滚动条. (当然也可以通过shift + 滚轮完成滚动)

不足点

  • 由于thead使用了transform, 因此也带来了几个问题
    • thead设了transform之后, border会失效, 因此使用了box-shadow来模拟border. 当然,
  • 监听mousewheel来设置transform的时候, 因为滚动和视图更新有延迟, 在firfoxsafari会有抖动, 在chrome下表现良好.
    • chromefirfox分别加入window.addEventListener('scroll', console.log), 鼠标滚动一次, 会发现ff下会触发多次回调, 而chrome只会触发一次
  • safari下, thead在被固定后的box-shadow会失效.

使用方式

antd类似

import { Table } from '@zzwing/react-table'
const data = [{key1: '123', keyn: '123'}]
const columns = [{
    title: 'column1',
    fixed: 'left',
    dataIndex: 'key1'
}, { /* ... */} , {
    title: 'column2',
    fixed: 'right',
    dataIndex: 'keyn'
}]

<Table dataSource={data} columns={columns} rowKey='key1'/>

React-Form-Wrapper

源码 Demo

封装了onChangevalue的高阶组件, 与antdform组件类似 不过只包含最基础的数据绑定, 也可通过options来自定义数据的读写.

import FormWrapperHoc from '@zzwing/react-form-wrapper'

class Test extends React.PureComponent {
  render() {
    const { itemWrapper, getState } = this.props.formWrapper
    const Input = itemWrapper('valueKey', {/* options */})(<input />)
    const value = getState().valueKey
    return (
      <>
        {Input}
        you can get value for {value}
      </>
    )
  }
}

链式key的读写实现

const Input = itemWrapper('a.b.c.d')(<input />)

按照一般实现, 会通过遍历每一层来set/get数据.

const _state = {}
const pathArr = path.split('.')
let tmp = _state
pathArr.forEach((each, index) => {
    if(index === pathArr.length - 1) {
        // do something
    }
    if(each in tmp) {
        tmp = tmp[each]
    } else {
        tmp[each] = {}
        tmp = tmp[each]
    }
})

最近改了一种实现方法, 通过一个chain对象直接存储path对应的数据 Edit chain object

// a.b.c.d
const chain = {
  a: { b: chain['a.b'] },
  'a.b': { c: chain['a.b.c'] },
  'a.b.c': { d: chain['a.b.c.d'] },
  'a.b.c.d': undefined
}
  • 对于get操作, 则可以直接从chain[path]中获取数据
  • 对于set操作, 则可以直接修改chain['a.b.c'].d = 'str', 最后修改chain['a.b.c.d'] = 'str
  • 因为修改的是同一个引用, 所以set操作会同步chain.achain.a.b

最后

antd是一个功能很全的UI库 但又正因为它功能很全,而大部分我是不需要,无形中可能添加了不少的代码量 所以我更喜欢是参考antd的实现,去开发满足个人需求的组件 自己开发的组件,自己会更清楚,使用起来更加顺手,扩展起来也会很方便 不过对于DatePicker这类组件,我想我还是直接用antd的吧


希望这几个组件能帮到你.