From 974043cb4cb78345c9d4dc6f126a3b9d43f99efb Mon Sep 17 00:00:00 2001 From: LOGIC <376693576@qq.com> Date: Thu, 10 Sep 2020 15:57:24 +0800 Subject: [PATCH 1/5] =?UTF-8?q?globalObject=E9=85=8D=E7=BD=AE=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=9C=8D=E5=8A=A1=E7=AB=AF=E6=B8=B2=E6=9F=93?= =?UTF-8?q?=20/=20=E5=85=B6=E4=BB=96=E5=8C=85=E7=89=88=E6=9C=AC=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/src/index.js | 2 +- package.json | 28 +++++---- src/index.tsx | 136 +++++++++++++++++++++++++++++++++------- tsconfig.json | 1 + webpack.build.config.js | 1 + 5 files changed, 133 insertions(+), 35 deletions(-) diff --git a/example/src/index.js b/example/src/index.js index cdcffaa..1964ba3 100644 --- a/example/src/index.js +++ b/example/src/index.js @@ -64,7 +64,7 @@ class Test extends React.Component {
this.onInput2Change(e)} maxLength={20} /> - this.onVcode2Change(v)} value={this.state.code} width={this.state.width} /> + this.onVcode2Change(v)} onClick={() => console.log('触发onClick') } value={this.state.code} width={this.state.width} /> {this.state.input2 === this.state.vcode2 ? "输入正确" : "输入错误"}

diff --git a/package.json b/package.json index 528be63..cea9287 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-vcode", - "version": "1.0.8", + "version": "1.0.10", "description": "a react verification code component", "main": "dist/index.js", "files": [ @@ -9,7 +9,8 @@ "scripts": { "dev": "webpack-dev-server --config webpack.config.js", "build:babel": "babel src -d lib", - "build": "webpack --config webpack.build.config.js --progress --profile --colors" + "build": "webpack --config webpack.build.config.js --progress --profile --colors", + "prettier": "prettier --write \"src/index.tsx\"" }, "types": "dist/index.d.ts", "typings": "dist/index.d.ts", @@ -33,25 +34,30 @@ "react-dom": "^16.13.1" }, "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.11.4", + "@babel/cli": "^7.11.6", + "@babel/core": "^7.11.6", "@babel/plugin-proposal-decorators": "^7.10.5", - "@babel/plugin-transform-runtime": "^7.11.0", - "@babel/preset-env": "^7.11.0", + "@babel/plugin-transform-runtime": "^7.11.5", + "@babel/preset-env": "^7.11.5", "@babel/preset-react": "^7.10.4", "@babel/runtime": "^7.11.2", - "@types/react": "^16.9.48", + "@types/react": "^16.9.49", "@types/react-dom": "^16.9.8", + "@typescript-eslint/eslint-plugin": "^4.1.0", + "@typescript-eslint/parser": "^4.1.0", "autoprefixer": "^9.8.6", "awesome-typescript-loader": "^5.2.1", "babel-loader": "^8.1.0", - "css-loader": "^4.2.2", - "eslint": "^7.7.0", + "css-loader": "^4.3.0", + "eslint": "^7.8.1", "eslint-config-prettier": "^6.11.0", "eslint-loader": "^4.0.2", "eslint-plugin-prettier": "^3.1.4", - "file-loader": "^6.0.0", - "source-map-loader": "^1.0.2", + "eslint-plugin-react": "^7.20.6", + "eslint-plugin-react-hooks": "^4.1.0", + "file-loader": "^6.1.0", + "prettier": "^2.1.1", + "source-map-loader": "^1.1.0", "style-loader": "^1.2.1", "typescript": "^4.0.2", "url-loader": "^4.1.0", diff --git a/src/index.tsx b/src/index.tsx index dae1e85..4418dde 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -7,18 +7,22 @@ interface Props { value?: string; // 由父级传入指定的字符串生成code width?: number; // 多宽 px height?: number; // 多高 px - style?: object; // 自定义style + style?: { + [propName: string]: any; + }; // 自定义style className?: string; // 各种class options?: OptionsProps; // 自定义各参数 - onChange?: Function; // 每次生成新的验证码时,将验证码的值传到上级 - onClick?: Function; // 用户每次点击时触发 + onChange?: (p: string | null) => any; // 每次生成新的验证码时,将验证码的值传到上级 + onClick?: () => any; // 用户每次点击时触发 } interface State { id: string; width: number; height: number; len: number; - style: object; + style: { + [propName: string]: any; + }; options: Options; } @@ -66,7 +70,44 @@ export default class Vcode extends React.PureComponent { options: (() => { // 初始化参数 const a: Options = { - codes: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "o", "p", "q", "r", "s", "t", "x", "u", "v", "y", "z", "w", "n", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], + codes: [ + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "o", + "p", + "q", + "r", + "s", + "t", + "x", + "u", + "v", + "y", + "z", + "w", + "n", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + ], fontSizeMin: 22, // 字体尺寸最小值 fontSizeMax: 26, // 字体尺寸最大值 colors: [ @@ -109,16 +150,20 @@ export default class Vcode extends React.PureComponent { } /** 组件初始化完毕时触发 **/ - componentDidMount() { + componentDidMount(): void { this.onDraw(this.props.value); } /** 组件参数改变 **/ - componentDidUpdate(prevP: Props) { + componentDidUpdate(prevP: Props): void { if (this.props.value !== prevP.value) { this.onDraw(this.props.value); } - if (this.props.width !== prevP.width || this.props.height !== prevP.height || this.props.style !== prevP.style) { + if ( + this.props.width !== prevP.width || + this.props.height !== prevP.height || + this.props.style !== prevP.style + ) { this.setState({ width: this.props.width || 150, height: this.props.height || 40, @@ -131,7 +176,7 @@ export default class Vcode extends React.PureComponent { } /** 用户点击了验证码图片 **/ - onClick() { + onClick(): void { // 如果用户没有设置值,就直接重新生成 if (!this.props.value) { this.onDraw(this.props.value); @@ -147,8 +192,15 @@ export default class Vcode extends React.PureComponent { */ codeCss(uW: number, i: number): string { return [ - `font-size:${this.randint(this.state.options.fontSizeMin, this.state.options.fontSizeMax)}px`, - `color:${this.state.options.colors[this.randint(0, this.state.options.colors.length - 1)]}`, + `font-size:${this.randint( + this.state.options.fontSizeMin, + this.state.options.fontSizeMax + )}px`, + `color:${ + this.state.options.colors[ + this.randint(0, this.state.options.colors.length - 1) + ] + }`, "position: absolute", `left:${this.randint(uW * i, uW * i + uW - uW / 2)}px`, "top:50%", @@ -157,7 +209,11 @@ export default class Vcode extends React.PureComponent { `-ms-transform:rotate(${this.randint(-15, 15)}deg) translateY(-50%)`, `-moz-transform:rotate(${this.randint(-15, 15)}deg) translateY(-50%)`, `-webkit-transform:rotate(${this.randint(-15, 15)}deg) translateY(-50%)`, - `font-family:${this.state.options.fonts[this.randint(0, this.state.options.fonts.length - 1)]}`, + `font-family:${ + this.state.options.fonts[ + this.randint(0, this.state.options.fonts.length - 1) + ] + }`, "font-weight:bold", "z-index:2", ].join(";"); @@ -171,17 +227,34 @@ export default class Vcode extends React.PureComponent { return [ "position: absolute", `opacity:${this.randint(3, 8) / 10}`, - `width:${this.randint(this.state.options.lineWidthMin, this.state.options.lineWidthMax)}px`, - `height:${this.randint(this.state.options.lineHeightMin, this.state.options.lineHeightMax)}px`, - `background:${this.state.options.lineColors[this.randint(0, this.state.options.lineColors.length - 1)]}`, - `left:${this.randint(-this.state.options.lineWidthMin / 2, this.state.width)}px`, + `width:${this.randint( + this.state.options.lineWidthMin, + this.state.options.lineWidthMax + )}px`, + `height:${this.randint( + this.state.options.lineHeightMin, + this.state.options.lineHeightMax + )}px`, + `background:${ + this.state.options.lineColors[ + this.randint(0, this.state.options.lineColors.length - 1) + ] + }`, + `left:${this.randint( + -this.state.options.lineWidthMin / 2, + this.state.width + )}px`, `top:${this.randint(0, this.state.height)}px`, `transform:rotate(${this.randint(-30, 30)}deg)`, `-o-transform:rotate(${this.randint(-30, 30)}deg)`, `-ms-transform:rotate(${this.randint(-30, 30)}deg)`, `-moz-transform:rotate(${this.randint(-30, 30)}deg)`, `-webkit-transform:rotate(${this.randint(-30, 30)}deg)`, - `font-family:${this.state.options.fonts[this.randint(0, this.state.options.fonts.length - 1)]}`, + `font-family:${ + this.state.options.fonts[ + this.randint(0, this.state.options.fonts.length - 1) + ] + }`, `font-weight:${this.randint(400, 900)}`, ].join(";"); } @@ -190,11 +263,13 @@ export default class Vcode extends React.PureComponent { * 绘制 * @param value 需要生成的字符值,不传则随机生成 * */ - onDraw(value: string | undefined) { + onDraw(value: string | undefined): string | null { let c = ""; // 存储生成的code const div = document.getElementById(this.state.id); - const isImg: boolean = /^http[s]*:\/\/|\.jpg$|\.png$|\.jpeg$|\.gif$|\.bmp$|\.webp$|^data:image/.test(value || ""); // 是否是图片 + const isImg: boolean = /^http[s]*:\/\/|\.jpg$|\.png$|\.jpeg$|\.gif$|\.bmp$|\.webp$|^data:image/.test( + value || "" + ); // 是否是图片 if (div) { div.innerHTML = ""; } @@ -202,7 +277,11 @@ export default class Vcode extends React.PureComponent { if (isImg) { // 用户传递了一张图片 const dom = document.createElement("img"); - dom.style.cssText = ["display: block", "max-width:100%", "max-height:100%"].join(";"); + dom.style.cssText = [ + "display: block", + "max-width:100%", + "max-height:100%", + ].join(";"); dom.src = value as string; div && div.appendChild(dom); this.props.onChange && this.props.onChange(null); @@ -210,13 +289,17 @@ export default class Vcode extends React.PureComponent { } // 不是图片而是普通字符串, 如果value存在说明是用户自定义的字符串 - let length = value ? value.length : this.state.len; // 字符的长度 + const length = value ? value.length : this.state.len; // 字符的长度 const uW: number = this.state.width / length / 1.01; // 每个字符占的宽度 for (let i = 0; i < length; i++) { const dom = document.createElement("span"); dom.style.cssText = this.codeCss(uW, i); - const temp = value ? value[i] : this.state.options.codes[Math.round(Math.random() * (this.state.options.codes.length - 1))]; + const temp = value + ? value[i] + : this.state.options.codes[ + Math.round(Math.random() * (this.state.options.codes.length - 1)) + ]; dom.innerHTML = String(temp); c = `${c}${temp}`; div && div.appendChild(dom); @@ -240,6 +323,13 @@ export default class Vcode extends React.PureComponent { } render() { - return
this.onClick()} />; + return ( +
this.onClick()} + /> + ); } } diff --git a/tsconfig.json b/tsconfig.json index a7a3fa2..9e55782 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,6 +15,7 @@ "noImplicitReturns": true, "noImplicitAny": false, "noFallthroughCasesInSwitch": true, + "outDir": "dist", "lib": ["es2018", "dom"] }, diff --git a/webpack.build.config.js b/webpack.build.config.js index d6faaed..d3c05b5 100644 --- a/webpack.build.config.js +++ b/webpack.build.config.js @@ -15,6 +15,7 @@ module.exports = { filename: "[name].js", library: "vcode", libraryTarget: "umd", + globalObject: 'this' //libraryExport: 'default', }, externals: { From 6c3accf0a9e45dfcd3df3f42c505f3405b98f5ee Mon Sep 17 00:00:00 2001 From: Logic <376693576@qq.com> Date: Thu, 10 Sep 2020 16:35:03 +0800 Subject: [PATCH 2/5] Update README.md --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3ed9f85..f5fcb2d 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,15 @@ import Vcode from 'react-vcode'; ```` +## 3. 服务端渲染 +``` +import Vcode from 'react-vcode'; -## 3. 自定义参数 + +``` + 需要自己加个id, 不然服务端渲染和本地渲染,id变了会报错,因为Vcode内部使用了随机值 + +## 4. 自定义参数 可自行设置覆盖原有值 @@ -89,14 +96,14 @@ options:{ // 验证码相关自定义参数 /> ```` -## 4. 手动刷新验证码 +## 5. 手动刷新验证码 ```javascript this.vcode = obj} /> this.vcode.onClick(); // 调用内部的onClick方法可刷新验证码 ``` -## 5. 额外说明 +## 6. 额外说明 - 之前用过一个验证码插件叫 vcode.js, 不知道作者。 本react-vcode是通过vcode.js的源码进行修改加工,转成了react组件。感谢原作者。 From 7d594b71a378732238d19e3636d7871620c0b3b6 Mon Sep 17 00:00:00 2001 From: Logic <376693576@qq.com> Date: Thu, 10 Sep 2020 17:31:50 +0800 Subject: [PATCH 3/5] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f5fcb2d..632aa3d 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,9 @@ options:{ // 验证码相关自定义参数 '#008888', ],  lineHeightMin: 1, // 线的粗细最小值 -  lineHeightMax: 1, // 线的粗细最大值 -  lineWidthMin: 20, // 线的长度最小值 -  lineWidthMax: 60, // 线的长度最大值 +  lineHeightMax: 2, // 线的粗细最大值 +  lineWidthMin: 40, // 线的长度最小值 +  lineWidthMax: 100, // 线的长度最大值 } // 例子: From c68aaa8952af811036ebb843374bc8f27c83da17 Mon Sep 17 00:00:00 2001 From: LOGIC <376693576@qq.com> Date: Thu, 10 Sep 2020 17:32:37 +0800 Subject: [PATCH 4/5] =?UTF-8?q?1.0.11=20=E5=81=9A=E4=BA=86=E4=BA=9B?= =?UTF-8?q?=E8=AE=B8=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/src/index.js | 2 +- package.json | 2 +- src/index.tsx | 47 +++++++++++++++++++++----------------------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/example/src/index.js b/example/src/index.js index 1964ba3..0dce4bf 100644 --- a/example/src/index.js +++ b/example/src/index.js @@ -11,7 +11,7 @@ class Test extends React.Component { input2: "", // 第2个input的值 vcode2: "-1", // 第2个vcode的值 code: "", - width: 200, + width: 150, }; } diff --git a/package.json b/package.json index cea9287..2055f97 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-vcode", - "version": "1.0.10", + "version": "1.0.11", "description": "a react verification code component", "main": "dist/index.js", "files": [ diff --git a/src/index.tsx b/src/index.tsx index 4418dde..0ba94a4 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -137,9 +137,9 @@ export default class Vcode extends React.PureComponent { "#008888", ], lineHeightMin: 1, // 线的粗细最小值 - lineHeightMax: 1, // 线的粗细最大值 - lineWidthMin: 20, // 线的长度最小值 - lineWidthMax: 60, // 线的长度最大值 + lineHeightMax: 2, // 线的粗细最大值 + lineWidthMin: 40, // 线的长度最小值 + lineWidthMax: 100, // 线的长度最大值 }; if (this.props.options) { return Object.assign({}, a, this.props.options); @@ -188,9 +188,15 @@ export default class Vcode extends React.PureComponent { * 随机生成一个Code的CSS样式 * @param uW 每个字符所占的宽度 * @param i 当前字符的下标 + * @param maxW 最大偏移值 * @return CSS字符串 */ - codeCss(uW: number, i: number): string { + codeCss(uW: number, i: number, maxW: number): string { + const transStr = `rotate(${this.randint( + -15, + 15, + true + )}deg) translateY(${this.randint(-55, -45, true)}%)`; return [ `font-size:${this.randint( this.state.options.fontSizeMin, @@ -202,13 +208,12 @@ export default class Vcode extends React.PureComponent { ] }`, "position: absolute", - `left:${this.randint(uW * i, uW * i + uW - uW / 2)}px`, + `left:${Math.max( + Math.min(this.randint(uW * i, uW * i + uW / 2, true), maxW), + uW / 4 + )}px`, "top:50%", - `transform:rotate(${this.randint(-15, 15)}deg) translateY(-50%)`, - `-o-transform:rotate(${this.randint(-15, 15)}deg) translateY(-50%)`, - `-ms-transform:rotate(${this.randint(-15, 15)}deg) translateY(-50%)`, - `-moz-transform:rotate(${this.randint(-15, 15)}deg) translateY(-50%)`, - `-webkit-transform:rotate(${this.randint(-15, 15)}deg) translateY(-50%)`, + `transform:${transStr};-o-transform:${transStr};-ms-transform:${transStr};-moz-transform:${transStr};-webkit-transform:${transStr}`, `font-family:${ this.state.options.fonts[ this.randint(0, this.state.options.fonts.length - 1) @@ -224,6 +229,7 @@ export default class Vcode extends React.PureComponent { * @return CSS字符串 */ lineCss(): string { + const transStr = `rotate(${this.randint(-30, 30)}deg)`; return [ "position: absolute", `opacity:${this.randint(3, 8) / 10}`, @@ -245,17 +251,7 @@ export default class Vcode extends React.PureComponent { this.state.width )}px`, `top:${this.randint(0, this.state.height)}px`, - `transform:rotate(${this.randint(-30, 30)}deg)`, - `-o-transform:rotate(${this.randint(-30, 30)}deg)`, - `-ms-transform:rotate(${this.randint(-30, 30)}deg)`, - `-moz-transform:rotate(${this.randint(-30, 30)}deg)`, - `-webkit-transform:rotate(${this.randint(-30, 30)}deg)`, - `font-family:${ - this.state.options.fonts[ - this.randint(0, this.state.options.fonts.length - 1) - ] - }`, - `font-weight:${this.randint(400, 900)}`, + `transform:${transStr};-o-transform:${transStr};-ms-transform:${transStr};-moz-transform:${transStr};-webkit-transform:${transStr}`, ].join(";"); } @@ -290,11 +286,12 @@ export default class Vcode extends React.PureComponent { // 不是图片而是普通字符串, 如果value存在说明是用户自定义的字符串 const length = value ? value.length : this.state.len; // 字符的长度 + const uW: number = this.state.width / length; // 每个字符能够占据的范围宽度 + const maxW = this.state.width - uW / 4; // 最大可偏移距离 - const uW: number = this.state.width / length / 1.01; // 每个字符占的宽度 for (let i = 0; i < length; i++) { const dom = document.createElement("span"); - dom.style.cssText = this.codeCss(uW, i); + dom.style.cssText = this.codeCss(uW, i, maxW); const temp = value ? value[i] : this.state.options.codes[ @@ -316,10 +313,10 @@ export default class Vcode extends React.PureComponent { } /** 生成范围随机数 **/ - randint(n: number, m: number): number { + randint(n: number, m: number, t?: boolean): number { const c = m - n + 1; const num = Math.random() * c + n; - return Math.floor(num); + return t ? num : Math.floor(num); } render() { From c905117d288159bef532ba2a4dd31f4dcbc9d9ec Mon Sep 17 00:00:00 2001 From: LOGIC <376693576@qq.com> Date: Wed, 16 Sep 2020 17:51:11 +0800 Subject: [PATCH 5/5] update --- example/src/index.css | 3 +++ example/src/index.js | 6 ++++-- package.json | 1 + webpack.config.js | 4 ++-- 4 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 example/src/index.css diff --git a/example/src/index.css b/example/src/index.css new file mode 100644 index 0000000..6701b6b --- /dev/null +++ b/example/src/index.css @@ -0,0 +1,3 @@ +.vcode{ + width: 300px; +} \ No newline at end of file diff --git a/example/src/index.js b/example/src/index.js index 0dce4bf..bf35d51 100644 --- a/example/src/index.js +++ b/example/src/index.js @@ -3,6 +3,8 @@ import Vcode from "../../dist/index.js"; import ReactDom from "react-dom"; import ImgTest1 from "../assets/test1.png"; import ImgTest2 from "../assets/test2.png"; +import './index.css'; + class Test extends React.Component { constructor(props) { super(props); @@ -11,7 +13,7 @@ class Test extends React.Component { input2: "", // 第2个input的值 vcode2: "-1", // 第2个vcode的值 code: "", - width: 150, + width: 100, }; } @@ -64,7 +66,7 @@ class Test extends React.Component {
this.onInput2Change(e)} maxLength={20} /> - this.onVcode2Change(v)} onClick={() => console.log('触发onClick') } value={this.state.code} width={this.state.width} /> + this.onVcode2Change(v)} onClick={() => console.log('触发onClick') } value={this.state.code} width={this.state.width} className={'vcode'}/> {this.state.input2 === this.state.vcode2 ? "输入正确" : "输入错误"}

diff --git a/package.json b/package.json index 2055f97..1899155 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "eslint-plugin-react": "^7.20.6", "eslint-plugin-react-hooks": "^4.1.0", "file-loader": "^6.1.0", + "postcss-loader": "^4.0.2", "prettier": "^2.1.1", "source-map-loader": "^1.1.0", "style-loader": "^1.2.1", diff --git a/webpack.config.js b/webpack.config.js index 87e3c10..8345752 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -16,7 +16,7 @@ module.exports = { { test: /\.css?$/, use: ["style-loader", "css-loader", "postcss-loader"], - include: [path.join(__dirname, "src")], + include: [path.join(__dirname, "example")], }, { test: /\.(png|jpg|gif)$/, @@ -26,7 +26,7 @@ module.exports = { { test: /\.(eot|woff|svg|ttf|woff2|appcache|mp3|pdf|png)(\?|$)/, use: ["file-loader?name=files/[name].[ext]"], - include: [path.join(__dirname, "src")], + include: [path.join(__dirname, "example")], }, ], },