1. 程式人生 > 其它 >重構-線性進度條

重構-線性進度條

技術標籤:手寫重構UI框架javascriptreact

動畫:
	傳遞顏色陣列後,顏色過渡
	寬度改變有0.6s過渡

引數:
  percentage: PropTypes.number,		進度數值,0-100
  onSuccess: PropTypes.func,		當載入到100%時,觸發回撥,第一個引數是狀態
  colors: PropTypes.array,			顏色陣列,會根據傳遞的顏色,在不同進度現實不同顏色,預設為藍色		
  suffix: PropTypes.bool,			後置圖示,在整個軌道後出現,未實現邏輯,僅是展現,需自定義設定
  show: PropTypes.bool,			    是否在進度條尾部現實數字
  width: PropTypes.string,			進度條長度
  height: PropTypes.string,			進度條高度
  borderRadius: PropTypes.string,   進度條圓角
  fontSize: PropTypes.string,		數字和圖示字型大小
  outerColor: PropTypes.string,	    軌道顏色
  innerColor: PropTypes.string,     進度顏色
  percentColor: PropTypes.string,	數字顏色

效果圖:
在這裡插入圖片描述
在這裡插入圖片描述
程式碼示例:
使用:

import React,{useState,useRef,useEffect,useCallback} from 'react'
import Progress from './progress/progress'

function App(){
  let [value,setValue] =useState(0);
  const valf = useRef(null);
  valf.current = value;


  const _onClick = function ()
  {
      setInterval(() => {
    
            setValue
(v=>v+1); },1000) } const _onSuccess = function (state) { console.log(state); } return( <div> <Progress colors={['#aaa', 'brown', 'blue', 'green']} percentage={value} onSuccess={_onSuccess} show ></Progress> <br /> <
br/> <button onClick={_onClick}>開始</button> </div> ) } export default App

progress.jsx:

import React,{useState,useEffect,useCallback,useRef,useMemo} from 'react'
import PropTypes from 'prop-types'
import './progress.css'

function App(props){

  const progressf = useRef(null);
  const innerf = useRef(null);

  // 初始樣式設定
  useEffect(() => {
    _styleHandler('width', props.width);
    _styleHandler('height', props.height);
    _styleHandler('borderRadius', props.borderRadius);
    _styleHandler('fontSize', props.fontSize);
    _styleHandler('outerColor', props.outerColor);
    _styleHandler('innerColor', props.innerColor);
    _styleHandler('percentColor', props.percentColor);
  },[])

  // 進度改變過程設定
  useEffect(() => {
    innerf.current.style.width = _percentHandler + '%';

    props.percentage === 100 && props.onSuccess(true);
    props.suffix && _situationHandler();
    
    if(props.colors.length)
    {
      let index = Math.floor(100 / props.colors.length);
      _percentColorHandler(_percentHandler, index);
    }

  },[props.percentage])

  //統一處理初始化樣式
  const _styleHandler = useCallback((key, value) => {
    props[key] && progressf.current.style.setProperty('--' + key, value)
    
  },[])

  //計算屬性返回當前數值
  const _percentHandler =useMemo(function ()
  {
    return Math.floor(Math.max(0,Math.min(100,props.percentage)))
  },[props.percentage])

  //如果傳入陣列的顏色變化
  const _percentColorHandler =useCallback(function(num,index)
  {
    
    let _index = Math.floor(num / index);
    (_index == props.colors.length) &&( _index = props.colors.length - 1);
    
    innerf.current.style.backgroundColor=props.colors[_index]
  },[])


  //當有後置圖示時,根據進度清空,對圖示的處理函式
  const _situationHandler = useCallback(() => {
    // console.log(_percentHandler);

  },[_percentHandler])

  return(

    <div className='jf-progress-container' ref={progressf}>
      <div className='jf-progress-outer'>
        <div className='jf-progress-inner' ref={innerf}>{props.show && <div className='jf-progress-num'>{_percentHandler}%</div>}</div>
      </div>
      {props.suffix && <span className='jf-progress-suffix'></span>}
    </div>
  )
}

App.propTypes = {
  percentage: PropTypes.number,
  onSuccess: PropTypes.func,
  colors: PropTypes.array,
  suffix: PropTypes.bool,
  show: PropTypes.bool,
  width: PropTypes.string,
  height: PropTypes.string,
  borderRadius: PropTypes.string,
  fontSize: PropTypes.string,
  outerColor: PropTypes.string,
  innerColor: PropTypes.string,
  percentColor: PropTypes.string,
}

App.defaultProps = {
  percentage: 0,
  onSuccess: () => { },
  colors:[]
}

export default React.memo(App);

progress.css:

.jf-progress-container {
  display: inline-block;
  box-sizing: border-box;
  width: var(--width);
  height: var(--height);
  position: relative;
  vertical-align: middle;

  --width: 400px;
  --height: 20px;
  --borderRadius: 20px;
  --outerColor: #ebeef5;
  --innerColor: #409eff;
  --innerWidth: px;
  --percentColor: white;
  --fontSize: 12px;
}

.jf-progress-outer {
  width: 100%;
  height: 100%;
  position: relative;
  background-color: var(--outerColor);
  border-radius: var(--borderRadius);
  overflow: hidden;
  vertical-align: middle;
  /* display: flex; */
}

.jf-progress-inner {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  background-color: var(--innerColor);
  border-radius: var(--borderRadius);
  text-align: right;

  line-height: var(--height);
  font-size: 0;
  transition: width 0.6s ease, background-color 1s;
}

.jf-progress-num {
  display: inline-block;
  vertical-align: middle;
  font-size: var(--fontSize);
  color: var(--percentColor);
}
.jf-progress-suffix {
  position: absolute;
  top: 0;
  right: 0;
  font-size: var(--fontSize);
  line-height: var(--height);
  transform: translateX(120%);
}