国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

「前端代碼簡潔之路」后臺系統(tǒng)之詳情頁設(shè)計(jì)

這篇具有很好參考價值的文章主要介紹了「前端代碼簡潔之路」后臺系統(tǒng)之詳情頁設(shè)計(jì)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

一、亂花迷人眼

我就是被迷的那雙眼。有時候需求來了,用熟悉的套路進(jìn)行開發(fā),確實(shí)很節(jié)省時間也能保證功能的穩(wěn)定,但是這些開發(fā)的慣性無形中阻礙了我對技術(shù)的探索。

我一直想改造詳情頁,解放重復(fù)功能開發(fā)的勞動力,但是詳情頁一眼望都是內(nèi)容平鋪,好像并沒有什么可做的代碼設(shè)計(jì)。

后來我撥開繁花,發(fā)現(xiàn)詳情頁的組件化不必想的過于復(fù)雜,后臺系統(tǒng)風(fēng)格統(tǒng)一即可。因?yàn)榇蟛糠值脑斍轫撁媸莾?nèi)容的展示,偶爾會出現(xiàn)少量的操作功能。將風(fēng)格統(tǒng)一的部分進(jìn)行組件化處理,操作功能使用回調(diào)函數(shù)放回當(dāng)前頁面,避免組件里做過多的業(yè)務(wù)邏輯???,這不就成了。

「前端代碼簡潔之路」后臺系統(tǒng)之詳情頁設(shè)計(jì)

項(xiàng)目基于React框架開發(fā)的,所以代碼寫法是JSX語法,組件開發(fā)使用的hooks函數(shù)式組件,UI框架使用的是antd。

二、欲起高樓,先建地基

開發(fā)前進(jìn)行功能設(shè)計(jì)是我逐漸養(yǎng)成的一個良好習(xí)慣,有時候急于開發(fā),可能漏掉一些設(shè)計(jì)細(xì)節(jié)或者功能。這次的詳情頁設(shè)計(jì)主要包括四個部分,UI組件、模塊劃分、數(shù)據(jù)重組、操作回調(diào)。

設(shè)計(jì)的功能如下:

「前端代碼簡潔之路」后臺系統(tǒng)之詳情頁設(shè)計(jì)

其中操作回調(diào)是為了實(shí)現(xiàn)功能性操作按鈕的功能,比如取消操作、審核操作、查看等詳情頁常見的操作按鈕。

三、設(shè)計(jì)實(shí)現(xiàn)

我捋了一下現(xiàn)有的業(yè)務(wù),除了極個別的詳情頁設(shè)計(jì)的比較有自己的風(fēng)格特點(diǎn),其他基本都是包括2-n個模塊展示數(shù)據(jù),部分模塊下會有操作按鈕,某些模塊下的某些數(shù)據(jù)項(xiàng)會有操作按鈕,較長的頁面會有快速定位導(dǎo)航等。

所以我會根據(jù)功能的復(fù)雜度遞增,逐步的實(shí)現(xiàn)這個詳情頁UI組件。

注:前面功能實(shí)現(xiàn)我主要放關(guān)鍵代碼,會把完整代碼放在文章的末尾。

3.1 基礎(chǔ)款詳情頁

純展示,根據(jù)接口返回的字段,重組數(shù)據(jù),之所以用重組 數(shù)據(jù)的方式是因?yàn)槟承?shù)據(jù)需要特殊處理,比如時間數(shù)據(jù),需要將時間戳轉(zhuǎn)成日期格式;枚舉數(shù)據(jù),需要將返回值展示為具體文字。

3.1.1 模塊劃分

假設(shè)當(dāng)前詳情頁有四個模塊:用戶信息、訂單信息、快遞信息、支付信息。四個模塊內(nèi)容展示有相似有不同,但是依舊可以把展示方式分成兩種:一排兩個的平鋪展示和Table表格展示。

模塊劃分完成之后,頁面呈現(xiàn)在腦海中也有了大致的結(jié)構(gòu)。第一個明確的設(shè)計(jì)點(diǎn)也就有了,既然模塊展示具有相似性。我就可以把UI渲染設(shè)計(jì)成數(shù)組循環(huán)的方式。對于不同的展示方式,可以根據(jù)模塊的key值去區(qū)分定義展示類型。

詳情頁

  • 根據(jù)模塊的劃分,定義dataList數(shù)組對象,后續(xù)頁面渲染是使用dataList進(jìn)行渲染的;
  • 設(shè)置contentType-展示形式分類變量,其值為row-平鋪,table-表格。會根據(jù)contentType將模塊展示成不同的形式;
  • 訂單列表因?yàn)槭荰able格式,它的表格列的配置描述維護(hù)在常量管理文件中;
/**
* @description 詳情頁
*/
import React, { useState, useEffect } from 'react';
......
import { ORDER_COLUMNS } from '@/constants/detailBase';

const DetailBase = () => {
  /** @name 頁面內(nèi)容數(shù)組對象  */
  let dataListInit = [
    {
      key: 'userInfo', // 模塊key值
      name: '用戶信息', //模塊標(biāo)題
    },
    {
      key: 'orderList',
      name: '訂單信息',
      columns: _.cloneDeep(ORDER_COLUMNS),
    },
    {
      key: 'postInfo',
      name: '快遞信息',
    },
    {
      key: 'payInfo',
      name: '支付信息',
    },
  ];
  
  // 列表數(shù)據(jù)重組
  dataListInit.map(item => {
    item.list = []; // 模塊展示內(nèi)容數(shù)組
    item.contentType = 'row'; // 展示形式類型 row-平鋪 table-表格
    // =>true: 訂單信息 展示為表格
    if (item.key === 'orderList') {
      item.contentType = 'table';
    }
  });
  let [dataList, setDataList] = useState(dataListInit);
  return <></>;
};
export default DetailBase;

詳情頁常量

對于常量管理,一般會放到常量文件中。

3.1.2 數(shù)據(jù)重組

  • 請求詳情數(shù)據(jù),獲得返回值。一般返回值都是嵌套對象的格式,所以可以將返回值的對象key值和設(shè)置的dataList中key一一對應(yīng);
  • 根據(jù)模塊設(shè)置模塊的list值,最終頁面渲染使用的是每個模塊的list對象。contentType類型為table時,可以直接將返回值賦值給該模塊的list變量;contentType類型為row時,需要進(jìn)行數(shù)據(jù)的重組。(注:之所以需要重組數(shù)據(jù)是因?yàn)橐厥馓幚頃r間戳、枚舉值等特殊返回值,比如時間戳要展示為日期格式,枚舉值根據(jù)返回值展示文字描述等);
/**
 * @description 詳情頁
 */
import React, { useState, useEffect } from 'react';
......
const DetailBase = () => {
  ......
  /**
   * 用戶信息-展示數(shù)據(jù)重組
   * @param {Object} data 需要獲取的項(xiàng)的對象
   * @return {Object} 獲得的值
   */
  const getUserData = data => {
    let list = [
      {
        name: '姓名',
        value: data.name,
      },
      {
        name: '年齡',
        value: data.age,
      },
      {
        name: '電話',
        value: data.phone,
      },
      {
        name: '收貨地址',
        value: data.address,
      },
    ];
    return list;
  };

  /**
   * 快遞信息-展示數(shù)據(jù)重組
   * @param {Object} data 需要獲取的項(xiàng)的對象
   * @return {Object} 獲得的值
   */
  const getPostData = data => {
    let list = [
      {
        name: '付款單號',
        value: data.postNum,
      },
      {
        name: '付款公司',
        value: data.postName,
      },
    ];
    return list;
  };

  /**
   * 支付信息-展示數(shù)據(jù)重組
   * @param {Object} data 需要獲取的項(xiàng)的對象
   * @return {Object} 獲得的值
   */
  const getPayData = data => {
    let list = [
      {
        name: '付款時間',
        value: data.payAt ? moment(data.payAt).format('YYYY-MM-DD HH:mm:ss') : '',
      },
      {
        name: '付款金額',
        value: data.payMoney,
      },
      {
        name: '操作時間',
        value: data.payOperateAt ? moment(data.payOperateAt).format('YYYY-MM-DD HH:mm:ss') : '',
      },
    ];
    return list;
  };

  /**
   * 獲取列表項(xiàng)的實(shí)際值
   * @param {Object} item 需要獲取的項(xiàng)的對象
   * @param {Object} res 接口請求數(shù)據(jù)
   * @return {Object} 獲得的值
   */
  const getItemList = (item, data) => {
    let obj = {
      userInfo: getUserData(data),
      postInfo: getPostData(data),
      payInfo: getPayData(data),
    };
    return obj[item.key];
  };

  /**
   * 初始化數(shù)據(jù)
   */
  const initData = () => {
    // 請求接口獲取返回值
    let res = {
      userInfo: {
        name: '張三',
        age: 30,
        phone: '12345678912',
        address: '北京市朝陽區(qū)',
      },
      payInfo: {
        payAt: 1641039600000,
        payMoney: 999,
        payOperateAt: 1641038400000,
      },
      orderList: [
        {
          name: '跑鞋·追光者',
          color: '白色',
          creatAt: 1641038400000,
          payAt: 1641039600000,
          haveFreight: 1,
        },
        {
          name: '運(yùn)動褲·逐夢',
          color: '黑色',
          creatAt: 1641038400000,
          payAt: 1641039600000,
          haveFreight: 1,
        },
        {
          name: '外套·閃光者',
          color: '藍(lán)色',
          creatAt: 1641038400000,
          payAt: 1641039600000,
          haveFreight: 1,
        },
      ],
      postInfo: {
        postName: '順豐',
        postNum: '1111',
      },
    };
    let list = _.cloneDeep(dataListInit);
    // 數(shù)據(jù)重置
    list.map(item => {
      if (item.contentType === 'table') {
        item.list = res[item.key];
      } else {
        let data = res[item.key];
        item.list = getItemList(item, data);
      }
    });
    setDataList(list);
  };

  useEffect(() => {
    initData();
  }, []);

  return <></>;
};

export default DetailBase;

3.1.3 詳情組件

因?yàn)槭歉鶕?jù)業(yè)務(wù)進(jìn)行的功能設(shè)計(jì),所以我把詳情組件放到了業(yè)務(wù)組件下面。

  • 模塊的展示,使用antd提供的Card卡片組件進(jìn)行頁面布局;Card卡片官網(wǎng)地址;
  • row平布類型的展示,使用antd提供的Row、Col柵格組件進(jìn)行頁面布局;Row、Col柵格組件官網(wǎng)地址;
  • table類型的展示,使用ante提供的Table組件進(jìn)行頁面布局;Table組件官網(wǎng)地址;
  • 組件通信,props傳參為dataList數(shù)據(jù)數(shù)組對象;
  • 注:像邊距mt/mb之類的樣式設(shè)置,我們的項(xiàng)目里面是定義的全局樣式,直接使用的。
/**
 * @description 公共業(yè)務(wù)組件-詳情
 */
import React from 'react';
import PropTypes from 'prop-types';
import { Card, Row, Col, Table } from 'antd';

const CommonDetailBase = ({ ...props }) => {
  const { dataList } = props;

  /**
   * row類頁面內(nèi)容回顯
   * @param {Object} data 展示內(nèi)容對象
   * @return {Element} 展示內(nèi)容
   */
  const dataRowContent = data => {
    const list = data.list ? data.list : [];
    return (
      <>
        {list.map((rowItem, rowIndex) => {
          return (
            <Col span={12} key={rowIndex}>
              <Card size='small'>
                <div>
                  {rowItem.name}:{rowItem.value}
                </div>
              </Card>
            </Col>
          );
        })}
      </>
    );
  };

  /**
   * Table類頁面內(nèi)容回顯
   * @param {Object} item 展示內(nèi)容對象
   * @return {Node} 展示內(nèi)容
   */
  const dataTableContent = item => {
    let list = item.list ? item.list : [];
    return <Table dataSource={list} columns={item.columns} rowKey={record => record.id} pagination={false} size='small' />;
  };

  return (
    <div>
      <div className='view-content'>
        {dataList.map(item => {
          return (
            <Card type='inner' title={item.name} id={item.key} key={item.key} className='mb20'>
              {item.contentType === 'row' ? <Row gutter={[12, 12]}>{dataRowContent(item)}</Row> : null}
              {item.contentType === 'table' ? dataTableContent(item) : null}
              {item.moduleBottomName ? (
                <Button type='primary' onClick={() => item.moduleBottomView(item)} className='mt20'>
                  {item.moduleBottomName}
                </Button>
              ) : null}
            </Card>
          );
        })}
      </div>
    </div>
  );
};

CommonDetailBase.propTypes = {
  dataList: PropTypes.array, // 頁面展示數(shù)組對象
};

CommonDetailBase.defaultProps = {
  dataList: [],
};

export default CommonDetailBase;

頁面使用

/**
 * @description 詳情頁
 */
import React, { useState, useEffect } from 'react';
......
// 引入組件
import { CommonDetailBase } from '@/bundleComponents';
......
const DetailBase = () => {
  return <CommonDetailBase dataList={dataList} />;
};

export default DetailBase;

3.2 升級款詳情頁

所謂升級款,即在原來的基礎(chǔ)上功能更豐富。比如我們的業(yè)務(wù)需求,模塊下面會跟著操作按鈕,頁面底部會有操作按鈕,頁面帶導(dǎo)航條。以及如果我們想組件功能更強(qiáng),需要支持的情況更多,可以支持某個模塊自定義展示。這個時候需要在原來的基礎(chǔ)上進(jìn)行功能擴(kuò)展.

3.2.1 詳情組件

詳情組件已開發(fā)好了,新增功能只需要在原來的基礎(chǔ)上新增代碼邏輯即可

  • 導(dǎo)航條,使用antd提供的Affix固釘組件,Affix固釘官網(wǎng)地址;
    • affixTabs:導(dǎo)航條數(shù)據(jù)對象,數(shù)組類型
    • afffixIndex:當(dāng)前選中導(dǎo)航變量,字符串類型
  • 模塊可以使用自定義展示,在模塊代碼中加入children變量的判斷,如果存在,則展示children內(nèi)容,如果不存在,則按照組件中的展示;
  • 模塊底部可以添加操作按鈕,支持按鈕組,根據(jù)moduleBottomList數(shù)組變量的值判斷,如果有值,則循環(huán)展示按鈕組,如果不存在,則不展示;
  • 數(shù)據(jù)項(xiàng)可以使用自定義展示,在數(shù)據(jù)項(xiàng)代碼中加入children變量的判斷,如果存在,則展示children內(nèi)容,如果不存在,則按照組件中的展示;
  • 數(shù)據(jù)項(xiàng)左側(cè)可以添加操作按鈕,支持按鈕組,根據(jù)colBtnList數(shù)組變量的值判斷,如果有值,則循環(huán)展示按鈕組,如果不存在,則不展示;
/**
 * @description 公共業(yè)務(wù)組件-詳情
 */
import React, { useState } from 'react';
......
const CommonDetailBase = ({ ...props }) => {
  const { dataList, affixTabs } = props;

  /** @name 當(dāng)前所在導(dǎo)航index值  */
  const [afffixIndex, setAfffixIndex] = useState(props.afffixIndex);

  /** @name 是否展示導(dǎo)航 */
  const hasAffixTabs = !!affixTabs;

  /**
   * 快速定位方法
   * @param {string} id 定位到的id值
   * @return {void} 無
   */
  const fastGo = id => {
    let element = document.getElementById(id);
    let view = document.querySelector('.view');
    view.scrollTo({
      top: element.offsetTop - 90,
    });
  };

  /**
   * 右側(cè)錨點(diǎn)導(dǎo)航-切換
   * @param {Object} item 選擇的導(dǎo)航標(biāo)簽
   * @return {void} 無
   */
  const tabChange = item => {
    setAfffixIndex(item.key);
    fastGo(item.key);
  };

  /**
   * row類頁面內(nèi)容回顯
   * @param {Object} data 展示內(nèi)容對象
   * @return {Element} 展示內(nèi)容
   */
  const dataRowContent = data => {
    const list = data.list ? data.list : [];
    return (
      <>
        {list.map((rowItem, rowIndex) => {
          return (
            <Col span={12} key={rowIndex}>
              <Card size='small'>
                {rowItem.children ? (
                  <>{rowItem.children}</>
                ) : (
                  <div>
                    {rowItem.name}:{rowItem.value}
                    {rowItem.colBtnList &&
                      rowItem.colBtnList.map((colBtnItem, colBtnIndex) => {
                        return (
                          <Button className='ml10' type='primary' onClick={() => colBtnItem.colBtnCallback(colBtnItem, rowItem)} key={colBtnIndex}>
                            {colBtnItem.name}
                          </Button>
                        );
                      })}
                  </div>
                )}
              </Card>
            </Col>
          );
        })}
      </>
    );
  };

  /**
   * Table類頁面內(nèi)容回顯
   * @param {Object} item 展示內(nèi)容對象
   * @return {Node} 展示內(nèi)容
   */
  const dataTableContent = item => {
    let list = item.list ? item.list : [];
    return <Table dataSource={list} columns={item.columns} rowKey={record => record.id} pagination={false} size='small' />;
  };

  return (
    <div className={style['detail-base']}>
      <div className='view-content' id='view'>
        {dataList.map(item => {
          return (
            <Card type='inner' title={item.name} id={item.key} key={item.key} className='mb20'>
              {item.children ? (
                <>{item.children}</>
              ) : (
                <>
                  {item.contentType === 'row' ? <Row gutter={[12, 12]}>{dataRowContent(item)}</Row> : null}
                  {item.contentType === 'table' ? dataTableContent(item) : null}
                </>
              )}
              {item.moduleBottomList &&
                item.moduleBottomList.map((moduleBtnItem, moduleBtnIndex) => {
                  return (
                    <Button className='mr10 mt20' type='primary' onClick={() => moduleBtnItem.moduleBtnCallback(moduleBtnItem, item)} key={moduleBtnIndex}>
                      {moduleBtnItem.name}
                    </Button>
                  );
                })}
            </Card>
          );
        })}
        {/* 右側(cè)錨點(diǎn)導(dǎo)航 */}
        {hasAffixTabs ? (
          <Affix offsetTop={120} className='sider-affix'>
            <ul className='affix'>
              {affixTabs.map((item, index) => (
                <li key={index}>
                  <div className={classnames('affix-item', { current: afffixIndex === item.key })} onClick={() => tabChange(item)}>
                    {item.name}
                  </div>
                </li>
              ))}
            </ul>
          </Affix>
        ) : null}
      </div>
    </div>
  );
};

CommonDetailBase.propTypes = {
  dataList: PropTypes.array, // 頁面展示數(shù)組對象
  affixTabs: PropTypes.array, // 導(dǎo)航數(shù)組對象
  afffixIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), // 導(dǎo)航默認(rèn)定位
};

CommonDetailBase.defaultProps = {
  dataList: [],
};

export default CommonDetailBase;

3.2.2 導(dǎo)航條

  • 導(dǎo)航條數(shù)據(jù)可以直接使用頁面列表數(shù)據(jù),因?yàn)槎ㄎ坏膋ey和頁面列表的key值做了一致性的處理;
  • 通過設(shè)置afffixIndex的值,可以控制當(dāng)前導(dǎo)航固定的位置;
  • 當(dāng)子組件的props傳參比較復(fù)雜的時候,可以設(shè)置一個config對象,比如detailConfig包含了所有props,子組件使用時直接用...(擴(kuò)展運(yùn)算符)進(jìn)行展開;
/**
 * @description 詳情頁
 */
import React, { useState, useEffect } from 'react';
......
import { CommonDetailBase } from '@/bundleComponents';
const DetailBase = () => {
  /** @name 頁面導(dǎo)航  */
  const affixTabs = [];
  ......
  // 列表數(shù)據(jù)重組
  dataListInit.map(item => {
    ......
    // 設(shè)置導(dǎo)航條數(shù)據(jù)
    affixTabs.push(item);
  });
  ......
  /** @name 詳情組件配置項(xiàng)  */
  const detailConfig = {
    afffixIndex: 'userInfo',
    affixTabs: affixTabs,
    dataList: dataList,
  };

  return (
    <div>
      <CommonDetailBase {...detailConfig} />
    </div>
  );
};
export default DetailBase;

3.2.3 模塊下的操作按鈕

  • moduleBottomList:模塊下的按鈕組數(shù)組變量,控制操作按鈕組是否展示,當(dāng)它有值時按鈕展示,沒值時按鈕不展示;
  • moduleBottomCallback:操作按鈕元素的操作回調(diào)函數(shù),可以做一些操作處理;
/**
 * @description 詳情頁
 */
import React, { useState, useEffect } from 'react';
......
const DetailBase = () => {
  ......
  let dataListInit = [
    ......
    {
      key: 'postInfo',
      name: '快遞信息',
    },
    ......
  ];
  ......
  const initData = () => {
    let list = _.cloneDeep(dataListInit);
      list.map(item => {
      ......
      // =>true: 快遞信息 表格項(xiàng)處理
      if (item.key === 'postInfo') {
        item.moduleBottomList = [
          {
            name: '快遞詳情',
            moduleBtnCallback: (_, data) => moduleBottomCallback(data, res),
          },
          {
            name: '快遞詳情2',
            moduleBtnCallback: (_, data) => moduleBottomCallback(data, res),
          },
        ];
      }
    })
  }
  ......
};
export default DetailBase;

3.2.4 數(shù)據(jù)項(xiàng)的操作按鈕

  • colBtnList:數(shù)據(jù)項(xiàng)的操作按鈕組,控制操作按鈕是否展示,當(dāng)它有值時按鈕展示,沒值時按鈕不展示;
  • colBtnCallback:操作按鈕元素的操作回調(diào)函數(shù),可以做一些操作處理;
/**
 * @description 詳情頁
 */
import React, { useState, useEffect } from 'react';
......
const DetailBase = () => {
  ......
  const getUserData = data => {
    let list = [
      ......
      {
        name: '收貨地址',
        value: data.address,
        colBtnList: [
          {
            name: '地址詳情',
            colBtnCallback: () => {
              window.open('https://juejin.cn/', '_blank');
            },
          },
        ],
      },
      .......
    ];
    return list;
  };
  ......
};
export default DetailBase;

3.2.5 模塊為自定義展示

將需要自定義展示的模塊對象的children值設(shè)置為需要展示的內(nèi)容即可

/**
 * @description 詳情頁
 */
import React, { useState, useEffect } from 'react';
......
const DetailBase = () => {
  ......
  /**
  * 支付模塊展示
  * @param {Object} dafa 展示的數(shù)據(jù)對象
  */
  const getPayInfo = data => {
    return (
      <Row gutter={[8, 8]}>
        {data.list.map((item, index) => {
          return (
            <Col span={24} key={index}>
              {item.name}:{item.value}
            </Col>
          );
        })}
      </Row>
    );
  };
  ......
  const initData = () => {
    ......
    let list = _.cloneDeep(dataListInit);
    list.map(item => {
    ......
      // =>true: 支付信息 自定義展示
      if (item.key === 'payInfo') {
        item.children = getPayInfo(item);
      }
    });
    setDataList(list);
  };
  ......
};
export default DetailBase;

3.2.6 數(shù)據(jù)項(xiàng)為自定義展示

將需要自定義展示的模塊下的數(shù)據(jù)項(xiàng)對象的children值設(shè)置為需要展示的內(nèi)容即可

/**
 * @description 詳情頁
 */
import React, { useState, useEffect } from 'react';
......
const DetailBase = () => {
  ......
  /**
  * 圖片類型展示
  * @param {Object} data 展示的數(shù)據(jù)對象
  */
  const getImageView = data => {
    return (
      <>
        頭像:<Button type="link">編輯</Button>
        <Row gutter={(12, 12)}>
          <Col span={4}>
            <img style={{ width: '80px', height: '80px', display: 'block' }} src={data.headImage} />
          </Col>
        </Row>
      </>
    );
  };
  ......
  const getUserData = data => {
    let list = [
      ......
      {
        name: '頭像',
        children: getImageView(data),
      },
    ];
    return list;
  };
  ......
};
export default DetailBase;

以上,一個功能相對全面的詳情頁組件就完成了。

3.3 完整代碼

3.3.1 詳情頁組件

/**
 * @description 公共業(yè)務(wù)組件-詳情
 */
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { Button, Card, Row, Col, Table, Affix } from 'antd';
import style from './style';

const CommonDetailBase = ({ ...props }) => {
  const { dataList, affixTabs } = props;

  /** @name 當(dāng)前所在導(dǎo)航index值  */
  const [afffixIndex, setAfffixIndex] = useState(props.afffixIndex);

  /** @name 是否展示導(dǎo)航 */
  const hasAffixTabs = !!affixTabs;

  /**
   * 快速定位方法
   * @param {string} id 定位到的id值
   * @return {void} 無
   */
  const fastGo = id => {
    let element = document.getElementById(id);
    let view = document.querySelector('.view');
    view.scrollTo({
      top: element.offsetTop - 90,
    });
  };

  /**
   * 右側(cè)錨點(diǎn)導(dǎo)航-切換
   * @param {Object} item 選擇的導(dǎo)航標(biāo)簽
   * @return {void} 無
   */
  const tabChange = item => {
    setAfffixIndex(item.key);
    fastGo(item.key);
  };

  /**
   * row類頁面內(nèi)容回顯
   * @param {Object} data 展示內(nèi)容對象
   * @return {Element} 展示內(nèi)容
   */
  const dataRowContent = data => {
    const list = data.list ? data.list : [];
    return (
      <>
        {list.map((rowItem, rowIndex) => {
          return (
            <Col span={12} key={rowIndex}>
              <Card size='small'>
                {rowItem.children ? (
                  <>{rowItem.children}</>
                ) : (
                  <div>
                    {rowItem.name}:{rowItem.value}
                    {rowItem.colBtnList &&
                      rowItem.colBtnList.map((colBtnItem, colBtnIndex) => {
                        return (
                          <Button className='ml10' type='primary' onClick={() => colBtnItem.colBtnCallback(colBtnItem, rowItem)} key={colBtnIndex}>
                            {colBtnItem.name}
                          </Button>
                        );
                      })}
                  </div>
                )}
              </Card>
            </Col>
          );
        })}
      </>
    );
  };

  /**
   * Table類頁面內(nèi)容回顯
   * @param {Object} item 展示內(nèi)容對象
   * @return {Node} 展示內(nèi)容
   */
  const dataTableContent = item => {
    let list = item.list ? item.list : [];
    return <Table dataSource={list} columns={item.columns} rowKey={record => record.id} pagination={false} size='small' />;
  };

  return (
    <div className={style['detail-base']}>
      <div className='view-content' id='view'>
        {dataList.map(item => {
          return (
            <Card type='inner' title={item.name} id={item.key} key={item.key} className='mb20'>
              {item.children ? (
                <>{item.children}</>
              ) : (
                <>
                  {item.contentType === 'row' ? <Row gutter={[12, 12]}>{dataRowContent(item)}</Row> : null}
                  {item.contentType === 'table' ? dataTableContent(item) : null}
                </>
              )}
              {item.moduleBottomList &&
                item.moduleBottomList.map((moduleBtnItem, moduleBtnIndex) => {
                  return (
                    <Button className='mr10 mt20' type='primary' onClick={() => moduleBtnItem.moduleBtnCallback(moduleBtnItem, item)} key={moduleBtnIndex}>
                      {moduleBtnItem.name}
                    </Button>
                  );
                })}
            </Card>
          );
        })}
        {/* 右側(cè)錨點(diǎn)導(dǎo)航 */}
        {hasAffixTabs ? (
          <Affix offsetTop={120} className='sider-affix'>
            <ul className='affix'>
              {affixTabs.map((item, index) => (
                <li key={index}>
                  <div className={classnames('affix-item', { current: afffixIndex === item.key })} onClick={() => tabChange(item)}>
                    {item.name}
                  </div>
                </li>
              ))}
            </ul>
          </Affix>
        ) : null}
      </div>
    </div>
  );
};

CommonDetailBase.propTypes = {
  dataList: PropTypes.array, // 頁面展示數(shù)組對象
  affixTabs: PropTypes.array, // 導(dǎo)航數(shù)組對象
  afffixIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), // 導(dǎo)航默認(rèn)定位
};

CommonDetailBase.defaultProps = {
  dataList: [],
};

export default CommonDetailBase;

組件樣式

:local(.detail-base) {
  position: relative;
  padding-left: 20px;
  background: #fff;

  .view-content {
    padding-top: 20px;
    padding-right: 120px;
    padding-bottom: 80px;
  }

  .sider-affix {
    position: fixed;
    top: 50px;
    right: 10px;

    .affix {
      padding-left: 0;
      margin: 16px 0;
      font-size: 12px;
      list-style: none;
      border-left: 1px solid #f0f0f0;

      li {
        padding-left: 0;
        margin-left: 0;
        line-height: 2;
        list-style: none;
      }

      .affix-item {
        display: block;
        width: 110px;
        padding-left: 16px;
        margin-left: -1px;
        overflow: hidden;
        font-size: 16px;
        color: rgba(0, 0, 0, 0.85);
        text-overflow: ellipsis;
        white-space: nowrap;
        cursor: pointer;
        border-left: 1px solid transparent;

        &.current {
          color: #1890ff;
          border-color: #1890ff;
        }
      }
    }
  }
}

3.3.3?完整UI

「前端代碼簡潔之路」后臺系統(tǒng)之詳情頁設(shè)計(jì)

四、總結(jié)

對后臺系統(tǒng)代碼簡潔之路,仍在探索中,后續(xù)想實(shí)現(xiàn)列表頁的操作表單項(xiàng)的設(shè)計(jì),這樣后臺系統(tǒng)的基礎(chǔ)的頁面能快速完成搭建。

當(dāng)然了,更好的方式是搭建低代碼平臺,但是現(xiàn)有的開發(fā)精力并不能支撐完成這種復(fù)雜的開發(fā)。所以先從基礎(chǔ)出發(fā),逐步升級自己的技能。文章來源地址http://www.zghlxwxcb.cn/news/detail-456857.html

到了這里,關(guān)于「前端代碼簡潔之路」后臺系統(tǒng)之詳情頁設(shè)計(jì)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包