0.0.1 • Published 2 years ago

r-starport v0.0.1

Weekly downloads
-
License
-
Repository
-
Last release
2 years ago

react-starport

倘若你希望你的组件在不同的地方使用,在切换的时候保存组件的状态并且拥有平滑的过渡动画,不妨看看这个~

使用方法

npm i react-starport

在入口文件引入css

import 'react-starport/style.css'
 ReactDOM.createRoot(document.getElementById('root')!).render(
   <Starport>
     <App />
   </Starport>
)

demo

倘若我们有这些图片数据需要共享

npm.io

那么我们需要先用Starport组件包裹整个App(一是为了让FloatContainer悬浮在整个App下,二是让Starport包裹住Router),并且渲染FloatContainer组件,用slot指定要渲染的内容。这里我们要渲染的是一个图片组件TheImage

注意:一定要给Container唯一的port字符串

function App() {
  return (
    <div className='bg-black w-full text-white'>
      <Starport>
        <Router />
        {imgs.map((img, index) => {
          return (
            <FloatContainer
              key={index}
              slot={() => <TheImage src={img} />}
              port={index + 1 + ''}
            />
          )
        })}
        <FloatContainer slot={() => <Info />} port='13' />
      </Starport>
    </div>
  )
}

接着,我们就可以在页面中使用FloatProxy组件来渲染FloatContainer组件的slot指定的内容了(渲染的时候slot外面会多一层div),如下。我们可以给FloatProxy传入一些props,他们会被挂载到slot外的div上(一般来说可以传入一些样式,但是不推荐使用与百分比有关的单位)。

const Foo = memo(() => {
  const [mode, setMode] = useState(false)
  return (
    <>
      <div className='w-full flex flex-col items-center'>
        <div className='py-50px'>current:Foo</div>
        <FloatProxy port='13' w='96px' h='72px' />
        <nav>
		  ...
        </nav>
      </div>
      <div flex='~ wrap' justify='center'>
        {['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'].map(
          item => (
            <FloatProxy
              key={item}
              port={item}
              className={mode ? 'w-60 h-50' : 'w-60 h-30'}
              m='5'
              rounded='xl'
              overflow='hidden'
            />
          )
        )}
      </div>
    </>
  )
})

页面最终渲染如下(图片中的数字是组件内为了标记组件是否重新渲染的组件状态)

npm.io

点击toggle改变显示大小

npm.io

我们再新建一个TransferList页面,用到了其中一部分图片,如下所示(我们将前六张图片分成了ListA和ListB进行展示)

const TransferList = memo(() => {
  const [listA, setListA] = useState(['1', '2', '3'])
  const [listB, setListB] = useState(['4', '5', '6'])

  return (
    <div className='w-full flex flex-col items-center '>
      <div className='py-50px'>current:TransferList</div>
      <nav>
		...
      </nav>
      <div className='my-5'> 试试看点击图片会发生什么</div>
      <div flex='~'>
        <div className='flex flex-col items-center w-60 mr-5'>
          <span>ListA</span>
          {listA.map(item => (
            <FloatProxy
              onClick={() => {
                setListA(listA.filter(i => i !== item))
                setListB([...listB, item])
              }}
              key={item}
              port={item}
              className='m-5 rounded-xl overflow-hidden w-60 h-30'
            />
          ))}
        </div>
        <div className='flex flex-col items-center w-60'>
          <span>ListB</span>
          {listB.map(item => (
            <FloatProxy
              onClick={() => {
                setListB(listB.filter(i => i !== item))
                setListA([...listA, item])
              }}
              key={item}
              port={item}
              className='m-5 rounded-xl overflow-hidden w-60 h-30'
            />
          ))}
        </div>
      </div>
    </div>
  )
})

渲染结果如下

npm.io

切换路由的时候,会有平滑的补间动画,如下所示

npm.io

项目难点

1、封装KeepAlive缓存组件解决Portal重新渲染children的问题

2、在update前等待了一个Tick,解决切换路由时Proxy组件渲染抖动的问题

3、修改传入的metadata时,有几率出现Proxy组件渲染抖动问题,这是由于Proxy改变之后Container才变为起飞状态,所以需要在这之前改变Container的landed

4、结合portal完成组件“起飞”和“落地”功能

使用注意事项

1、最好给FloatProxy一个初始宽高,否则会因为div内部没有内容撑开而引起跳变

2、不要给Proxy组件实则hi与百分比有关的样式