Maoyl's blog Maoyl's blog
首页
  • 前端基础

    • HTML
    • CSS
    • CSS动画
    • JavaScript文章
    • stylus
  • 性能优化

    • 《性能优化》笔记
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《JavaScript设计模式》笔记
    • 《TypeScript 从零实现 axios》
    • TypeScript笔记
    • JS设计模式总结笔记
  • 前端框架

    • Vue相关
    • React相关
  • 前端监控

    • 前端监控简介
  • 学习笔记

    • 《Vue》笔记
    • 《React》笔记
    • 小程序学习笔记
  • 后端基础

    • Nodejs
  • 学习笔记

    • 数据结构
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • 网页性能
  • 学习笔记

    • 《Git》学习笔记
    • 《Vim》学习笔记
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

maoyln

日日行,不怕千万里
首页
  • 前端基础

    • HTML
    • CSS
    • CSS动画
    • JavaScript文章
    • stylus
  • 性能优化

    • 《性能优化》笔记
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《JavaScript设计模式》笔记
    • 《TypeScript 从零实现 axios》
    • TypeScript笔记
    • JS设计模式总结笔记
  • 前端框架

    • Vue相关
    • React相关
  • 前端监控

    • 前端监控简介
  • 学习笔记

    • 《Vue》笔记
    • 《React》笔记
    • 小程序学习笔记
  • 后端基础

    • Nodejs
  • 学习笔记

    • 数据结构
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • 网页性能
  • 学习笔记

    • 《Git》学习笔记
    • 《Vim》学习笔记
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 核心概念

  • 高级指引

  • Hook

  • 案例演示

    • 案例演示
    • react自动放缩组件
    • react 使用高德地图
  • 《React》笔记
  • 案例演示
maoyln
2021-06-08

react自动放缩组件

# react自动放缩组件

背景:公司有一个大屏展示的项目(1920*1080),该项目被多个产品以iframe的形式内嵌,有时候会出现布局混乱。 所以需要做一个外部的壳子,根据外部穿进来的宽度,等比放缩该大屏项目,所以做了该功能。

# 代码

{% raw %}

// index.tsx

import React, { useEffect } from 'react';
import './index.scss';
import { useImmer } from 'use-immer';
import { Props, ScaleBoxState } from './interface';

const ScaleBox = function (props: Props) {
  const { width = 1920, height = 1080, children, monitorScaleChange, outsideWidth = 0, outsideHeight=0 } = props;
  const [state, updateState] = useImmer<ScaleBoxState>({
    scale: 1,
    wrapWidth: null,
    wrapHeight: null,
  });

  useEffect(() => {
    init();
    return () => {
      window.onresize = null
    }
  }, []);

  useEffect(() => {
    setScale();
  }, [window.innerWidth + window.innerHeight]);

  const getScale = () => {
    const currentWrapWidth =  window.innerWidth - outsideWidth;
    const currentWrapHeight = window.innerHeight - outsideHeight;
    let ww = currentWrapWidth / width;
    let wh = currentWrapHeight / height;
    updateState((draft) => {
      draft.wrapWidth = currentWrapWidth;
      draft.wrapHeight = currentWrapHeight;
    })
    return Math.min(ww, wh);
  }

  const setScale = () => {
    const scale = getScale();
    monitorScaleChange(scale);
    updateState((draft) => {
      draft.scale = scale;
    });
  }


  const debounce: Function = (fn: Function, delay: number = 500): Function => {
    let timer: any
    return function () {
      let args = arguments;
      if (timer) {
        clearTimeout(timer);
      }
      timer = setTimeout(function () {
        timer = null;
        fn(args);
      }, delay);
    }
  }

  const init = () => {
    if (state.wrapWidth === null && state.wrapHeight === null) {
      window.onresize = debounce(setScale);
    }
  }

  return (
    <div className="scale-box-wrap">
      <div className="scale-box" style={{width: `${width}px`, height: `${height}px`, transform: `scale(${state.scale}) translate(-50%, -50%)`}} >
        {
          children
        }
      </div>
    </div>
  );
};

export default ScaleBox;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

{% endraw %}

// interface.ts

export interface Props {
  width?: number;
  height?: number;
  wrapWidth?: number;
  wrapHeight?: number;
  children?: any;
  monitorScaleChange?: Function;
  outsideWidth?: number;
  outsideHeight?: number;
}

export interface ScaleBoxState {
  scale: number;
  wrapWidth: number;
  wrapHeight: number;
  // tabDom: HTMLElement[];
  // barWidth: number;
  // barLeft: number;
  // isClose: boolean;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// index.less

.scale-box-wrap {
  background-color: #000000;
  width: 100%;
  height: 100%;
}
.scale-box {
  display: flex;
  flex-direction: column;
  transform-origin: 0 0;
  position: absolute;
  left: 50%;
  top: 50%;
  transition: 0.3s;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
编辑 (opens new window)
上次更新: 2025/04/18, 01:42:12
案例演示
react 使用高德地图

← 案例演示 react 使用高德地图→

最近更新
01
GSAP动画库——如何高效写动画
04-17
02
自适应方案PxToRem
09-10
03
性能优化-requestAnimationFrame
08-10
更多文章>
Theme by Vdoing | Copyright © 2019-2025 备案号:京ICP备19058102号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式