react加ts,可视化组件预览页面

1.简介
预览窗口根据父组件width,height压缩自身宽高,按比例放入div,根据宽高大小自适应撑满宽或者高
效果图


WeChata41099fb1f8cc9bcbd6cbcd1f3d5f2f2.jpg

2、组件代码

import React from 'react';
import { Layout, Select } from 'antd';
import { CloseOutlined } from '@ant-design/icons';
import styles from './index.less';
const { Content } = Layout;
interface ScreenProps {
  width: number;
  height: number;
}

const Screen: React.FC<ScreenProps> = ({ width, height }) => (
  <div
    style={{
      width: '100%',
      height: '100%',
      background: '#fff',
      border: '1px solid #ccc',
      boxSizing: 'border-box',
      maxWidth: `${width}px`,
      maxHeight: `${height}px`,
    }}
  >
    <img
      crossOrigin="anonymous"
      style={{ width: '100%', height: '100%' }}
      src="https://img.zcool.cn/community/011f355df5e6dca801219ccefe034c.jpg@2o.jpg"
    />
  </div>
);

const Apps: React.FC = () => {
  const optionsdata = [
    {
      value: '16:9',
      label: '16:9',
    },
    {
      value: '32:9',
      label: '32:9',
    },
    {
      value: '4:3',
      label: '4:3',
    },
    {
      value: '自定义',
      label: '自定义',
    },
  ];
  const [width, setWidth] = React.useState(1920);
  const [height, setHeight] = React.useState(1080);
  const [widthview, setWidthview] = React.useState(1920);
  const [heightview, setHeightview] = React.useState(1080);
  const [viewDisable, setviewDisable] = React.useState(true);

  const onChange = (e: React.FormEvent<HTMLInputElement>, name: string): void => {
    const value = Number(e.currentTarget.value);
    if (name === 'width') {
      setWidth(value);
    }
    if (name === 'height') {
      setHeight(value);
    }
  };

  const handleChange = (value: string) => {
    console.log(`selected ${value}`);
    switch (value) {
      case '16:9':
        setWidth(1920);
        setHeight(1080);
        setviewDisable(true);
        break;
      case '32:9':
        setWidth(3840);
        setHeight(1080);
        setviewDisable(true);
        break;
      case '4:3':
        setWidth(4000);
        setHeight(3000);
        setviewDisable(true);
        break;
      case '自定义':
        setviewDisable(false);
        break;
      default:
        break;
    }
  };
  const handleResize = React.useCallback((width: number, height: number) => {
    setWidthview(width);
    setHeightview(height);
  }, []);
  const divRef = React.useRef<HTMLDivElement>(null);
  React.useEffect(() => {
    const handleWindowResize = () => {
      if (divRef.current) {
        // const divWidth = divRef.current.offsetWidth;
        // console.log(divWidth);

        const { offsetWidth, offsetHeight } = divRef.current;

        const aspectRatio = offsetWidth / offsetHeight;

        if (aspectRatio > width / height) {
          handleResize(offsetHeight * (width / height), offsetHeight);
        } else {
          handleResize(offsetWidth, offsetWidth * (height / width));
        }
        if (width / height == 1) {
          if (offsetHeight > offsetWidth) {
            handleResize(offsetWidth, offsetWidth);
          } else {
            handleResize(offsetHeight, offsetHeight);
          }
        }
      }
      // const { innerWidth, innerHeight } = window;
    };

    handleWindowResize();
    window.addEventListener('resize', handleWindowResize);

    return () => {
      window.removeEventListener('resize', handleWindowResize);
    };
  }, [width, height, handleResize]);

  return (
    <>
      <Layout
        style={{
          minWidth: '1200px',
          height: '100%',
          width: '100%',
          position: 'absolute',
          background: '#0E1017 ',
          overflow: 'hidden',
        }}
      >
        <Content
          style={{
            height: '36px',
            width: '100%',
            background: '#1C1F2E',
            position: 'fixed',
            top: '0',
          }}
        >
          <span className={styles.viewsize}>
            尺寸:
            <Select
              defaultValue="16:9"
              style={{ width: 90 }}
              bordered={false}
              options={optionsdata}
              onChange={handleChange}
            />
            <span>
              <input
                type="number"
                disabled={viewDisable}
                className={styles.sizeinput}
                value={width}
                onChange={(e) => {
                  onChange(e, 'width');
                }}
              ></input>
              <CloseOutlined style={{ fontSize: '14px', color: '#535560', margin: '0 8px' }} />
              <input
                type="number"
                disabled={viewDisable}
                className={styles.sizeinput}
                value={height}
                onChange={(e) => {
                  onChange(e, 'height');
                }}
              ></input>
            </span>
          </span>
        </Content>
        <Content style={{ marginTop: '0px', overflow: 'hidden', height: 'calc(100% - 200px)' }}>
          <p style={{ marginLeft: '16px', position: 'absolute', top: '60px' }}>总体运行情况</p>
          <div id="mainLayout" className={styles.App}>
            <div
              style={{
                height: 'calc(100vh - 200px)',
                width: 'calc(100vw - 20px)',
                background: '#ededed',
                padding: '20px',
                boxSizing: 'border-box',
              }}
              ref={divRef}
            >
              <div
                style={{
                  position: 'relative',
                  width: '100%',
                  height: '100%',
                }}
              >
                <div
                  style={{
                    position: 'absolute',
                    top: 0,
                    bottom: 0,
                    left: 0,
                    right: 0,
                    display: 'flex',
                    justifyContent:
                      width / height > window.innerWidth / window.innerHeight ? 'center' : 'center',
                    alignItems:
                      width / height < window.innerWidth / window.innerHeight ? 'center' : 'center',
                  }}
                >
                  <Screen width={widthview} height={heightview}></Screen>
                </div>
              </div>
            </div>
          </div>
        </Content>
      </Layout>
    </>
  );
};

export default Apps;

indes.less

.header {
  position: fixed;
  top: 0;
  width: 100%;
}

.xian {
  width: 1px;
  height: 12px;
  margin-left: 16px;
  border-right: 1px solid rgb(255, 255, 255);
}

.btn {
  width: 42px;
  margin-left: 15px;
  background-color: #3b4460;
  border: none;
}

.title {
  position: absolute;
  bottom: 50%;
  left: 50%;
  margin-bottom: -32px;
  margin-left: -50px;
}

.viewsize {
  position: absolute;
  bottom: 50%;
  left: 50%;
  margin-bottom: -16px;
  margin-left: -141px;
}

.sizeinput {
  width: 60px;
  height: 26px;
  text-align: center;
  background: #1c1f2e;
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 2px;
}

.capture {
  width: 100%;
  height: calc(100% - 22px);
}

.pageView {
  width: 100%;
  height: 100%;
  padding: 50px;
}

.container {
  position: relative;
  width: 100%;
  height: 100%;
}

.content {
  position: absolute;
  top: 50%;
  left: 50%;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  transform: translate(-50%, -50%);
}

.App {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

@media (max-width: 768px) {
  .App {
    height: 100%;
  }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 227,250评论 6 530
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 97,923评论 3 413
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 175,041评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,475评论 1 308
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,253评论 6 405
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 54,801评论 1 321
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,882评论 3 440
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,023评论 0 285
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,530评论 1 331
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,494评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,639评论 1 366
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,177评论 5 355
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,890评论 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,289评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,552评论 1 281
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,242评论 3 389
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,626评论 2 370

推荐阅读更多精彩内容