在获取数据时显示CSS加载指示器 [英] Showing a CSS loading indicator while fetching data

查看:77
本文介绍了在获取数据时显示CSS加载指示器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个不确定的线性CSS加载指示器,如材料设计中的指示器.每次我从Redux的reducer获取数据时,都会显示此指示符.问题在于,尽管指示器显示出来,但它没有被动画化.看起来整个页面都冻结了,直到用数据填充化简器为止.

I have a indeterminate linear css loading indicator like the ones in material design. Every time I fetch data from a Redux's reducer, I show this indicator. The problem is that while the indicator shows up, it is not being animated. It looks like the whole pages freezes up until the reducer is populated with the data.

假设我的加载指示器始终处于可见状态并具有动画效果.一旦我将数据提取/请求到化简器中,加载指示符便会停止动画处理.

Let's suppose I have my loading indicator visible and animated at all times. As soon as I fetch/request data into a reducer, the loading indicator stops animating.

您认为是什么原因引起的?它是可修复的,还是我需要实现gif指示器而不是css指示器?

What do you think is causing this? Is it fixable or Do I need to implement a gif indicator and not a css one?

编辑1

EDIT 1

这是我的Loader组件:

import React, { Component, PropTypes } from 'react';
import radium from 'radium';

// indeterminate Linear (type: indeterminateLinear)
const indeterminateLinearLong = radium.keyframes({
  '0%': {
    left: '-35%',
    right: '100%'
  },
  '60%': {
    left: '100%',
    right: '-90%'
  },
  '100%': {
    left: '100%',
    right: '-90%'
  }
});
const indeterminateLinearShort = radium.keyframes({
  '0%': {
    left: '-200%',
    right: '100%'
  },
  '60%': {
    left: '107%',
    right: '-8%'
  },
  '100%': {
    left: '107%',
    right: '-8%'
  }
});
const indeterminateLinear = {
  base: {
    backgroundColor: '#26a69a',
  },
  progress: {
    position: 'relative',
    height: '4px',
    display: 'block',
    width: '100%',
    backgroundColor: '#acece6',
    // borderRadius: '2px',
    backgroundClip: 'padding-box',
    // margin: '0.5rem 0 1rem 0',
    overflow: 'hidden',
    zIndex: '999'
  },
  before: {
    position: 'absolute',
    backgroundColor: 'yellow',
    top: '0',
    left: '0',
    bottom: '0',
    willChange: 'left, right',
    animation: 'indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite',
    animationName: indeterminateLinearLong
  },
  after: {
    position: 'absolute',
    backgroundColor: 'yellow',
    top: '0',
    left: '0',
    bottom: '0',
    willChange: 'left, right',
    animation: 'indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite',
    animationName: indeterminateLinearShort,
    animationDelay: '1.15s'
  }
};

// Indeterminate Cirular (type: indeterminateCircular (default))
const indeterminateCircularRotate = radium.keyframes({
  '100%': {
    transform: 'rotate(360deg)'
  },
});
const indeterminateCircularColor = radium.keyframes({
  '100%, 0%': {
    stroke: 'red'
  },
  '40%': {
    stroke: 'blue'
  },
  '60%': {
    stroke: 'green'
  },
  '80%, 90%': {
    stroke: 'yellow'
  }
});
const indeterminateCircularDash = radium.keyframes({
  '0%': {
    strokeDasharray: '1,200',
    strokeDashoffset: '0'
  },
  '50%': {
    strokeDasharray: '89,200',
    strokeDashoffset: '-35'
  },
  '100%': {
    strokeDasharray: '89,200',
    strokeDashoffset: '-124'
  },
});
const indeterminateCircular = {
  loader: {
    position: 'absolute',
    width: '100px',
    height: '100px',
    left: '50%',
    top: '20%'
  },
  circular: {
    animation: 'x 2s linear infinite',
    animationName: indeterminateCircularRotate,
    height: '24px',
    position: 'relative',
    width: '24px'
  },
  path: {
    strokeDasharray: '1,200',
    strokeDashoffset: '0',
    animation: 'dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite',
    animationName: indeterminateCircularDash,
    strokeLinecap: 'round',
    stroke: 'red',
    strokeWidth: '2'
  }
}

class Loader extends Component {
  render() {
    const {
      type
    } = this.props;
    let loader = null;

    if ( type === 'indeterminateLinear' ) {
      loader = (
        <div style={ indeterminateLinear.progress }>
          <div style={ indeterminateLinear.before }></div>
          <div style={ indeterminateLinear.base }></div>
          <div style={ indeterminateLinear.after }></div>
        </div>
      );
    } else {
      loader = (
        <div>
          <div style={ indeterminateCircular.loader }>
            <svg style={ indeterminateCircular.circular } viewBox="25 25 50 50">
              <circle style={
                indeterminateCircular.path
              } cx="50" cy="50" r="20" fill="none" strokeMiterlimit="10"/>
            </svg>
          </div>
        </div>
      );
    }

    return (
      <div>{ loader }</div>
    );
  }
}

Loader.propTypes = {
  type: PropTypes.string,
};

export default radium(Loader);

当我包含Loader组件时,它可以正常工作并进行动画处理;但是,当我请求获取某些数据时,动画将停止.我还可以注意到,在React重新渲染并显示所获取的数据之前,其他所有内容也都陷入了僵局.

When I include the Loader component, it works and animates without a problem; however, when I request some data to be fetched, the animation stops. I can also notice that everything else frozes up too until React rerenders and shows the fetched data.

此Loader组件包含在与reducer连接的顶级组件中,当获取数据时,该组件将被显示.

This Loader component is being included in an top level component that is connected to the reducers, when data is being fetched, the component is being shown.

{ this.props.globalState.someReducer.isFetching ?
  <Theme render="Loader" type="indeterminateLinear" /> : null
}

编辑2

EDIT 2

我想添加另一个用例.这次与redux无关,因此我们可以将其从图片中删除.它必须与自身反应.

I want to add another use case. This time has nothing to do with redux, so we can remove it from the picture. It has to be with react itself.

我有一个页面列出了一些物品,大约. 40个项目,我有一个按日期对列表进行排序的按钮.

I have a page listing some items, approx. 40 items, and I have a button that sorts this list by date.

这就是我的渲染函数中的内容:

This is what I have in my render function:

const sortDesc = ( a, b ) => (
    transactions[b].updatedAt ||
    transactions[b].createdAt) -
    (transactions[a].updatedAt ||
    transactions[a].createdAt
)
const sortAsc = ( a, b ) => (
    transactions[a].updatedAt ||
    transactions[a].createdAt) -
    (transactions[b].updatedAt ||
    transactions[b]. createdAt
)

let sortDate = sortDesc;
if (!this.state.sortDesc) {
  sortDate = sortAsc
}

<button onClick={ this.handleSortBy }>sort by date</button>

        {
          Object.keys(transactions)
            .sort(
              sortDate
          ).map(( key, index )=> {

            return (
              <div key={ index }>
                <Payout {...this.props} />
              </div>
            );
          })
        }

我的Loader组件位于父组件中.结构可能是这样的:

I have my Loader component inside a parent component. The structure could be something like this:

-布局<-这里有装载程序

-- Layout <-- here we have the Loader

----交易<-这是排序功能

---- Transactions <-- here is the sort function

------支出<-子元素

------ Payout <-- child component

现在,每当我按下排序按钮时,所有内容都会冻结,直到完成排序为止.当我说一切"时,它表示所有组件,包括父组件(在本例中为LayoutLoader).

Now, everytime I hit the sort button, everything freezes up until the sorting is finished. When I say "everything" it means all components, including parent components (in this case Layout and Loader).

Loader是用Radium构建的.

The Loader is built with Radium.

我必须在这里丢失一些东西,我不敢相信当重新绘制子组件时所有组件都会冻结.

I must be missing something here, I cannot believe all the components will freeze up when a child componen is re-rendering.

推荐答案

我终于解决了.经过一番研究,我发现关于Web Worker的知识很多,只是发现它不是正确的解决方案.无论如何,它与javascript的工作方式有关. Javascript是单线程的,因此是阻塞的.因此,当我们执行一些需要花费一些时间的任务(在我的情况下是一秒钟左右)时,我们在屏幕上看到的所有内容都会冻结,甚至css动画也是如此!它确实取决于您使用的浏览器.就我而言,我使用的是Chrome.我测试了它的Firefox,动画没有停止.

I finally solved it. After some research, I learned a lot about web workers just to find out it was not the right solution. Anyways, it has to do on how javascript works. Javascript is single threaded and thus blocking. So when we have some task that takes some time (in my case was a second or so) everything we seen on screen will freeze, even css animations! It does depend on what browser you are using. In my case, i was using Chrome. I tested it firefox and the animations did not stop.

我们去解决问题.我注意到Chrome在转换方面存在一些问题,尤其是一些基本的CSS元素,例如top,right,bottom,left,margin ...,因此我不得不进行转换.并非所有转换都可以.例如,翻译百分比不起作用,因此我不得不使用像素.为此,我需要计算父元素的宽度并进行一些计算,以便能够将我的子元素在X轴上从屏幕的左侧向右侧平移.

Let's go to the solution. I noticed that Chrome has some issues with transitions, specially with some basic css elements such as top, right, bottom, left, margins... so i had to go with transforms. Not all transforms will work either. For example, translate percentages won't work, so I had to use pixels. For this, i needed to calculate the width of the parent element and do some calculations to be able to translate my child element on the X axis from the left to the right of the screen.

我将用实际代码更新此帖子.

I will update this post with the actual code.

这篇关于在获取数据时显示CSS加载指示器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆