├── .babelrc ├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── src ├── app.js ├── components │ └── pageMain │ │ ├── components │ │ └── ResizeDiv │ │ │ ├── index.css │ │ │ └── index.jsx │ │ └── index.js └── images │ ├── bg.jpg │ ├── favicon_16.ico │ └── favicon_32.ico ├── template └── index.html ├── webpack.common.js ├── webpack.dev.js └── webpack.prod.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env", "react","stage-0","stage-3"], 3 | "plugins": [ 4 | "syntax-dynamic-import" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "airbnb", 4 | "env": { 5 | "browser": true, 6 | "node": true, 7 | "es6": true, 8 | "jest": true 9 | }, 10 | "rules": { 11 | "react/prop-types": [0], 12 | "react/no-unused-prop-types":[0], 13 | "react/jsx-filename-extension": [1, { "extensions": [".js",".jsx"] }], 14 | "react/jsx-first-prop-new-line":[0], 15 | "react/no-array-index-key":[0], 16 | "arrow-body-style": [0], 17 | "arrow-parens": [0], 18 | "no-console":"warn", 19 | "jsx-a11y/anchor-is-valid": [0], 20 | "jsx-a11y/click-events-have-key-events": [0], 21 | "jsx-a11y/interactive-supports-focus": [0], 22 | "jsx-a11y/no-static-element-interactions":[0], 23 | "jsx-a11y/no-noninteractive-element-interactions":[0], 24 | "import/prefer-default-export": [0], 25 | "comma-dangle":[0], 26 | "no-underscore-dangle": [0], 27 | "object-curly-newline":[0], 28 | "indent":[0] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 排除引用模块 2 | node_modules/ 3 | 4 | # 排除vscode配置 5 | .vscode/ 6 | 7 | # 排除单元测试覆盖率结果文件夹 8 | coverage/ 9 | package-lock.json 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 HanZilu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 在React中实现可调整宽高的div # 2 | 3 | 已废弃,更换仓库地址为: 4 | 5 | https://gitee.com/vvjiang/resizeDiv4React 6 | 7 | 原文: 8 | 9 | * 实现高度和宽度可调整 10 | * 按住鼠标拖动水平bar和垂直bar开始调整,鼠标放开或者移出区域停止调整 11 | * 窗口resize时自适应,并且不影响宽高的调整 12 | * 设定宽高上下限,不能使宽高太小或者太大 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-demo", 3 | "version": "1.0.0", 4 | "description": "webpack的使用demo", 5 | "main": "index.js", 6 | "author": "韩子卢", 7 | "license": "MIT", 8 | "private": true, 9 | "devDependencies": { 10 | "babel-core": "6.26.3", 11 | "babel-eslint": "7.2.1", 12 | "babel-loader": "^7", 13 | "babel-plugin-import": "1.6.3", 14 | "babel-plugin-syntax-dynamic-import": "6.18.0", 15 | "babel-polyfill": "6.26.0", 16 | "babel-preset-env": "1.6.1", 17 | "babel-preset-react": "6.24.1", 18 | "babel-preset-stage-0": "6.24.1", 19 | "babel-preset-stage-3": "6.24.1", 20 | "cross-env": "5.1.3", 21 | "css-loader": "0.28.9", 22 | "eslint": "^4.17.0", 23 | "eslint-config-airbnb": "16.1.0", 24 | "eslint-plugin-import": "2.8.0", 25 | "eslint-plugin-jsx-a11y": "6.0.3", 26 | "eslint-plugin-promise": "3.6.0", 27 | "eslint-plugin-react": "7.6.1", 28 | "eslint-plugin-standard": "3.0.1", 29 | "file-loader": "2.0.0", 30 | "html-loader": "0.5.5", 31 | "html-webpack-plugin": "3.2.0", 32 | "identity-obj-proxy": "3.0.0", 33 | "image-webpack-loader": "4.0.0", 34 | "less": "2.7.3", 35 | "less-loader": "4.0.5", 36 | "mini-css-extract-plugin": "0.4.2", 37 | "style-loader": "0.19.1", 38 | "webpack-cli": "3.1.0", 39 | "webpack-dev-server": "^3.7.2", 40 | "webpack-merge": "4.1.4" 41 | }, 42 | "scripts": { 43 | "dev": "webpack-dev-server --config webpack.dev.js", 44 | "prod": "cross-env NODE_ENV=production webpack -p --config webpack.prod.js", 45 | "build": "cross-env webpack -p --config webpack.prod.js", 46 | "test": "jest --coverage", 47 | "mock": "json-server --watch mock/db.json" 48 | }, 49 | "dependencies": { 50 | "clean-webpack-plugin": "0.1.18", 51 | "prop-types": "15.6.0", 52 | "react": "^16.8.6", 53 | "react-dom": "^16.8.6", 54 | "react-loadable": "5.4.0", 55 | "react-redux": "5.0.6", 56 | "react-router-dom": "4.2.2", 57 | "redux": "3.7.2", 58 | "redux-actions": "2.2.1", 59 | "redux-logger": "3.0.6", 60 | "redux-promise": "0.6.0", 61 | "redux-thunk": "2.3.0", 62 | "underscore": "^1.9.1", 63 | "webpack": "4.19.0" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | // import { BrowserRouter as Router, Route } from 'react-router-dom'; 4 | import { HashRouter as Router, Route } from 'react-router-dom'; 5 | import Loadable from 'react-loadable'; 6 | 7 | function Loading() { 8 | return
Loading...
; 9 | } 10 | 11 | const PageMain = Loadable({ 12 | loader: () => import('./components/pageMain'), 13 | loading: Loading, 14 | }); 15 | 16 | 17 | const App = () => ( 18 | 19 |
20 | 21 |
22 |
23 | ); 24 | 25 | ReactDOM.render(, document.getElementById('app')); 26 | -------------------------------------------------------------------------------- /src/components/pageMain/components/ResizeDiv/index.css: -------------------------------------------------------------------------------- 1 | 2 | .container{ 3 | margin: 30px; 4 | overflow: hidden; 5 | position: absolute; 6 | top: 0; 7 | left: 0; 8 | bottom: 0; 9 | right: 0; 10 | } 11 | 12 | .content{ 13 | position: absolute; 14 | top: 0; 15 | left: 0; 16 | bottom: 0; 17 | right: 0; 18 | min-height: 300px; 19 | } 20 | 21 | .left{ 22 | width: 500px; 23 | height: 100%; 24 | float: left; 25 | position: relative; 26 | } 27 | 28 | .left-top{ 29 | position: absolute; 30 | top: 0; 31 | bottom: 104px; 32 | width: 100%; 33 | background-color: lightblue; 34 | box-sizing: border-box; 35 | } 36 | 37 | .h-resize{ 38 | height: 4px; 39 | width: 100%; 40 | background: #fff; 41 | position: absolute; 42 | bottom: 100px; 43 | z-index: 1; 44 | cursor: row-resize; 45 | user-select: none; 46 | } 47 | 48 | .left-bottom{ 49 | position: absolute; 50 | bottom: 0; 51 | width: 100%; 52 | height: 100px; 53 | background-color: lightgreen; 54 | box-sizing: border-box; 55 | } 56 | 57 | .v-resize{ 58 | height: 100%; 59 | width: 4px; 60 | position: absolute; 61 | background: #fff; 62 | left: 500px; 63 | z-index: 2; 64 | cursor: col-resize; 65 | user-select: none; 66 | } 67 | 68 | .right{ 69 | margin-left: 504px; 70 | background-color: lightsalmon; 71 | height: 100%; 72 | box-sizing: border-box; 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/components/pageMain/components/ResizeDiv/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import _ from 'underscore' 3 | import styles from './index.css' 4 | 5 | // 可调整宽高的Div 6 | export default class ResizeDiv extends Component { 7 | state = { 8 | isHResize: false, 9 | isVResize: false, 10 | hNum: 100, 11 | vNum: 500, 12 | hNumLimit: 30, 13 | vNumLimit: 30 14 | } 15 | 16 | resizeOffsetInfo = { 17 | clientTop: 0, 18 | clientLeft: 0 19 | } 20 | 21 | leftHeight = 0 22 | 23 | containerWidth = 0 24 | 25 | componentDidMount() { 26 | this.initResizeInfo() 27 | const throttled = _.throttle(() => { 28 | this.initResizeInfo() 29 | }, 200) 30 | 31 | window.onresize = throttled 32 | } 33 | componentWillUnmount() { 34 | window.onresize = null 35 | } 36 | 37 | /** 38 | * 初始化resize信息 39 | */ 40 | initResizeInfo = () => { 41 | const hEle = document.getElementById('h_resize_container') 42 | this.resizeOffsetInfo = this.getEleOffset(hEle) 43 | this.leftHeight = hEle.offsetHeight 44 | this.containerWidth = document.getElementById('v_resize_container').offsetWidth 45 | 46 | if (hEle.offsetHeight - this.state.hNum < this.state.hNumLimit) { 47 | this.setState({ 48 | hNum: hEle.offsetHeight - this.state.hNumLimit 49 | }) 50 | } 51 | if (this.containerWidth - this.state.vNum < this.state.vNumLimit) { 52 | this.setState({ 53 | vNum: this.containerWidth - this.state.vNumLimit 54 | }) 55 | } 56 | } 57 | 58 | /** 59 | * 获取元素的偏移信息 60 | */ 61 | getEleOffset(ele) { 62 | var clientTop = ele.offsetTop 63 | var clientLeft = ele.offsetLeft 64 | let current = ele.offsetParent 65 | while (current !== null) { 66 | clientTop += current.offsetTop 67 | clientLeft += current.offsetLeft 68 | current = current.offsetParent 69 | } 70 | return { 71 | clientTop, 72 | clientLeft, 73 | height: ele.offsetHeight, 74 | width: ele.offsetWidth 75 | } 76 | } 77 | 78 | /** 79 | * 开始拖动水平调整块 80 | */ 81 | hResizeDown = () => { 82 | this.setState({ 83 | isHResize: true 84 | }) 85 | } 86 | 87 | /** 88 | * 拖动水平调整块 89 | */ 90 | hResizeOver = (e) => { 91 | const { isHResize, hNum, hNumLimit } = this.state 92 | if (isHResize && hNum >= hNumLimit && (this.resizeOffsetInfo.height - hNum >= hNumLimit)) { 93 | let newValue = this.resizeOffsetInfo.clientTop + this.resizeOffsetInfo.height - e.clientY 94 | if (newValue < hNumLimit) { 95 | newValue = hNumLimit 96 | } 97 | if (newValue > this.resizeOffsetInfo.height - hNumLimit) { 98 | newValue = this.resizeOffsetInfo.height - hNumLimit 99 | } 100 | this.setState({ 101 | hNum: newValue 102 | }) 103 | } 104 | } 105 | 106 | /** 107 | * 开始拖动垂直调整块 108 | */ 109 | vResizeDown = () => { 110 | this.setState({ 111 | isVResize: true 112 | }) 113 | } 114 | 115 | /** 116 | * 拖动垂直调整块 117 | */ 118 | vResizeOver = (e) => { 119 | const { isVResize, vNum, vNumLimit } = this.state 120 | if (isVResize && vNum >= vNumLimit && (this.containerWidth - vNum >= vNumLimit)) { 121 | let newValue = e.clientX - this.resizeOffsetInfo.clientLeft 122 | if (newValue < vNumLimit) { 123 | newValue = vNumLimit 124 | } 125 | if (newValue > this.containerWidth - vNumLimit) { 126 | newValue = this.containerWidth - vNumLimit 127 | } 128 | this.setState({ 129 | vNum: newValue 130 | }) 131 | } 132 | } 133 | 134 | /** 135 | * 只要鼠标松开或者离开区域,那么就停止resize 136 | */ 137 | stopResize = () => { 138 | this.setState({ 139 | isHResize: false, 140 | isVResize: false 141 | }) 142 | } 143 | 144 | render() { 145 | const hCursor = this.state.isHResize ? 'row-resize' : 'default' 146 | const hColor = this.state.isHResize ? '#ddd' : '#fff' 147 | const vCursor = this.state.isVResize ? 'col-resize' : 'default' 148 | const vColor = this.state.isVResize ? '#ddd' : '#fff' 149 | 150 | return ( 151 |
152 |
153 |
155 |
aasd
156 |
157 |
asd
158 |
159 |
160 |
161 | asdas 162 |
163 |
164 |
165 | ) 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/components/pageMain/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ResizeDiv from './components/ResizeDiv/index.jsx'; 3 | 4 | /** 5 | * 首页 6 | */ 7 | class PageMain extends React.Component { 8 | render() { 9 | return ( 10 |
11 | 12 |
13 | ); 14 | } 15 | } 16 | 17 | export default PageMain 18 | -------------------------------------------------------------------------------- /src/images/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvjiang/resizeDiv4React/3d7e922bf8c9e3f89623a8eb91cf4669b66744f0/src/images/bg.jpg -------------------------------------------------------------------------------- /src/images/favicon_16.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvjiang/resizeDiv4React/3d7e922bf8c9e3f89623a8eb91cf4669b66744f0/src/images/favicon_16.ico -------------------------------------------------------------------------------- /src/images/favicon_32.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvjiang/resizeDiv4React/3d7e922bf8c9e3f89623a8eb91cf4669b66744f0/src/images/favicon_32.ico -------------------------------------------------------------------------------- /template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 微澜之间 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /webpack.common.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 3 | const path = require('path'); 4 | const webpack = require('webpack'); 5 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 6 | 7 | const pathsToClean = [ 8 | 'build', 9 | ]; 10 | 11 | const isProduction = process.env.NODE_ENV === 'production'; 12 | 13 | module.exports = { 14 | entry: { 15 | main: ['babel-polyfill', './src/app.js'], 16 | }, 17 | output: { 18 | path: path.resolve(__dirname, 'build'), 19 | filename: '[name].[chunkhash].js', 20 | // 添加 chunkFilename 21 | publicPath: '/', 22 | chunkFilename: '[name].[chunkhash:5].chunk.js', 23 | }, 24 | plugins: [ 25 | new HtmlWebpackPlugin({ 26 | template: './template/index.html', 27 | filename: 'demo.html', 28 | minify: { 29 | collapseWhitespace: true, 30 | }, 31 | hash: isProduction, 32 | }), 33 | new MiniCssExtractPlugin({ filename: '[name].[contenthash].css', allChunks: false }), 34 | new CleanWebpackPlugin(pathsToClean), 35 | ], 36 | module: { 37 | rules: [{ 38 | test: /\.jsx?$/, 39 | exclude: /(node_modules)/, 40 | use: { 41 | loader: 'babel-loader', 42 | options: { 43 | presets: ['react', 'env', 'stage-0', 'stage-3'], 44 | plugins: [ 45 | ['import', { libraryName: 'antd-mobile', style: 'css' }], // `style: true` 会加载 less 文件 46 | ], 47 | }, 48 | }, 49 | }, 50 | { 51 | test: /\.(gif|png|jpe?g|svg)$/i, 52 | use: [{ 53 | loader: 'file-loader', 54 | options: { 55 | name: '[name].[ext]', 56 | outputPath: 'images/', 57 | }, 58 | }, 59 | { 60 | loader: 'image-webpack-loader', 61 | options: { 62 | bypassOnDebug: true, 63 | }, 64 | }, 65 | ], 66 | }, 67 | { 68 | test: /\.html$/, 69 | use: [{ 70 | loader: 'html-loader', 71 | options: { 72 | minimize: true, 73 | }, 74 | }], 75 | }], 76 | }, 77 | }; 78 | -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | const webpack = require('webpack'); 4 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 5 | const { theme } = require('./package.json'); 6 | 7 | module.exports = merge(common, { 8 | mode: 'development', 9 | output: { 10 | filename: '[name].[hash].js', 11 | }, 12 | devtool: 'source-map', 13 | devServer: { 14 | port: 8787, 15 | open: true, 16 | compress: true, 17 | index: 'demo.html', 18 | }, 19 | plugins: [ 20 | new webpack.HotModuleReplacementPlugin(), 21 | ], 22 | module: { 23 | rules: [{ 24 | test: /\.css$/, 25 | exclude: /node_modules/, 26 | use: [MiniCssExtractPlugin.loader, 'css-loader?modules&sourceMap'], 27 | }, { 28 | test: /\.css$/, 29 | include: /node_modules/, 30 | use: [MiniCssExtractPlugin.loader, 'css-loader?sourceMap'], 31 | }, 32 | { 33 | test: /\.less$/, 34 | use: [ 35 | MiniCssExtractPlugin.loader, 36 | 'css-loader?modules&sourceMap', 37 | { 38 | loader: 'less-loader', 39 | options: { 40 | modifyVars: theme 41 | } 42 | }, 43 | ], 44 | }, 45 | ], 46 | }, 47 | }); 48 | -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | const webpack = require('webpack'); 5 | 6 | module.exports = merge(common, { 7 | mode: 'production', 8 | entry: { 9 | vendor: [ 10 | 'react', 11 | 'react-dom', 12 | 'redux', 13 | 'react-router-dom', 14 | 'react-redux', 15 | 'redux-actions', 16 | 'axios' 17 | ], 18 | }, 19 | plugins: [ 20 | // new webpack.optimize.CommonsChunkPlugin({ 21 | // names: ['vendor'], 22 | // minChunks: Infinity, 23 | // filename: 'common.bundle.[chunkhash].js', 24 | // }), 25 | // new webpack.optimize.CommonsChunkPlugin({ 26 | // names: ['manifest'], 27 | // filename: 'manifest.bundle.[chunkhash].js', 28 | // }), 29 | new webpack.optimize.RuntimeChunkPlugin({ 30 | name: 'manifest' 31 | }), 32 | new MiniCssExtractPlugin({ filename: '[name].[contenthash].css', allChunks: false }), 33 | ], 34 | optimization: { 35 | splitChunks: { 36 | chunks: 'initial', 37 | cacheGroups: { // 这里开始设置缓存的 chunks 38 | default: { 39 | chunks: 'initial', // 必须三选一: "initial" | "all" | "async"(默认就是异步) 40 | minSize: 0, // 最小尺寸,默认0, 41 | minChunks: 2, // 最小 chunk ,默认1 42 | maxInitialRequests: 5, // 最大初始化请求书,默认1 43 | }, 44 | vendor: { 45 | chunks: 'initial', // 必须三选一: "initial" | "all" | "async"(默认就是异步) 46 | names: ['vendor'], // 要缓存的 分隔出来的 chunk 名称 47 | priority: 10, // 缓存组优先级 48 | enforce: true, 49 | filename: 'common.bundle.[chunkhash].js', 50 | } 51 | } 52 | }, 53 | runtimeChunk: true 54 | }, 55 | module: { 56 | rules: [ 57 | { 58 | test: /\.css$/, 59 | exclude: /node_modules/, 60 | use: [MiniCssExtractPlugin.loader, 'css-loader?modules'], 61 | }, { 62 | test: /\.css$/, 63 | include: /node_modules/, 64 | use: [MiniCssExtractPlugin.loader, 'css-loader'] 65 | }, 66 | { 67 | test: /\.less$/, 68 | use: [MiniCssExtractPlugin.loader, 'css-loader?modules', 'less-loader'] 69 | }, 70 | ], 71 | } 72 | }); 73 | --------------------------------------------------------------------------------