Skip to content

Commit

Permalink
feature: 添加 password 组件
Browse files Browse the repository at this point in the history
  • Loading branch information
战友 committed Jun 17, 2017
1 parent 021e413 commit 6b5eed6
Show file tree
Hide file tree
Showing 13 changed files with 5,577 additions and 68 deletions.
39 changes: 37 additions & 2 deletions config/webpack.config.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ module.exports = {
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
// https://github.com/facebookincubator/create-react-app/issues/290
extensions: ['.ts', '.tsx', '.js', '.json', '.jsx'],
extensions: ['.ts', '.tsx', '.js', '.json', '.jsx', 'styl'],
alias: {

// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
Expand Down Expand Up @@ -141,6 +141,7 @@ module.exports = {
/\.(js|jsx)(\?.*)?$/,
/\.(ts|tsx)(\?.*)?$/,
/\.css$/,
/\.styl$/,
/\.json$/,
/\.bmp$/,
/\.gif$/,
Expand Down Expand Up @@ -204,6 +205,40 @@ module.exports = {
},
],
},
{
test: /\.styl$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss', // https://webpack.js.org/guides/migrating/#complex-options
sourceMap: true,
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
{
loader: require.resolve('stylus-loader')
}
],
},
// ** STOP ** Are you adding a new loader?
// Remember to add the new extension(s) to the "url" loader exclusion list.
],
Expand Down
39 changes: 37 additions & 2 deletions config/webpack.config.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ module.exports = {
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
// https://github.com/facebookincubator/create-react-app/issues/290
extensions: ['.ts', '.tsx', '.js', '.json', '.jsx'],
extensions: ['.ts', '.tsx', '.js', '.json', '.jsx', '.styl'],
alias: {

// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
Expand Down Expand Up @@ -132,6 +132,7 @@ module.exports = {
/\.(js|jsx)$/,
/\.(ts|tsx)$/,
/\.css$/,
/\.styl$/,
/\.json$/,
/\.bmp$/,
/\.gif$/,
Expand Down Expand Up @@ -211,6 +212,40 @@ module.exports = {
),
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
{
test: /\.styl$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss', // https://webpack.js.org/guides/migrating/#complex-options
sourceMap: true,
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
{
loader: require.resolve('stylus-loader')
}
],
},
// ** STOP ** Are you adding a new loader?
// Remember to add the new extension(s) to the "file" loader exclusion list.
],
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"react-error-overlay": "^1.0.6",
"source-map-loader": "^0.2.1",
"style-loader": "0.17.0",
"stylus": "^0.54.5",
"stylus-loader": "^3.0.1",
"sw-precache-webpack-plugin": "0.9.1",
"ts-loader": "^2.0.3",
"tslint": "^5.2.0",
Expand Down
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>React Password</title>
</head>
<body>
<noscript>
Expand Down
24 changes: 0 additions & 24 deletions src/App.css

This file was deleted.

19 changes: 6 additions & 13 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
import * as React from 'react';
import './App.css';
import * as React from 'react'

const logo = require('./logo.svg');
import { Password } from './components/password'

class App extends React.Component<{}, null> {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
To get started, edit <code>src/App.tsx</code> and save to reload.
</p>
<div className='App'>
<Password passwordLength={6} />
</div>
);
)
}
}

export default App;
export default App
1 change: 1 addition & 0 deletions src/components/password/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './password.component'
24 changes: 24 additions & 0 deletions src/components/password/password.component.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.password-component

.item
width: 48px
height: 48px
border: 1px solid #666666
border-radius: 4px
text-align center
margin: 10px
font-size: 30px
color: transparent
text-shadow: 0 0 0 black

&::selection {
background: transparent
}

&::-moz-selection {
background: transparent
}

&::-webkit-selection {
background: transparent
}
139 changes: 139 additions & 0 deletions src/components/password/password.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import * as React from 'react'
import './password.component.styl'

interface PasswordProps {
passwordLength: number
onConfirm?: (password: string) => void
}

interface PasswordState {
valueArr: string[]
}

export class Password extends React.Component<PasswordProps, PasswordState> {
private refArr: React.Ref<HTMLInputElement> | never[] = []
private index: number = 0

constructor(props: any) {
super(props)
this.state = {
valueArr: []
}
}

componentDidMount() {
this.refArr[this.index].focus()
}

handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { passwordLength } = this.props
const { valueArr } = this.state
const isNumber = /^[0-9]*$/
const value = e.target.value
if (isNumber.test(value) && parseInt(value, 10) >= 0) {
valueArr[this.index] = value
if (value.length === 1 && this.index < passwordLength - 1) {
this.refArr[++this.index].focus()
}
} else {
valueArr[this.index] = ''
}
this.setState({
...this.state,
valueArr
})

const password = this.checkPassword(valueArr)
if (password) {
const { onConfirm } = this.props
if (onConfirm) {
onConfirm(password)
}
}
}

checkPassword(valueArr: string[]) {
const { passwordLength } = this.props
let password = ''
if (valueArr.length < passwordLength) {
return false
}
valueArr.map((item) => {
if (item !== '') {
password += item
}
})
if (password.length < length) {
return false
}
return password
}

handlePress = (target: any) => {
const { passwordLength } = this.props
switch (target.keyCode) {
case 8:
// 返回
const value = target.target.value
if (value === '' && this.index > 0) {
this.refArr[--this.index].focus()
}
break
case 37:
// 左移
if (this.index > 0) {
this.refArr[--this.index].focus()
} else {
this.refArr[passwordLength - 1].focus()
this.index = passwordLength - 1
}
break
case 39:
// 右移
if (this.index < passwordLength - 1) {
this.refArr[++this.index].focus()
} else {
this.refArr[0].focus()
this.index = 0
}
break
default:
break
}
}

handelFocus = (i: number) => {
this.index = i
this.refArr[i].select()
}

setRef(index: number, ref: any) {
this.refArr[index] = ref
}

render() {
const { passwordLength } = this.props
const { valueArr } = this.state
const inputs: JSX.Element[] = []
for (let i = 0; i < passwordLength; i++) {
inputs.push(
<input
key={i}
ref={this.setRef.bind(this, i)}
className='item'
type='text'
maxLength={1}
onChange={this.handleChange}
onKeyUp={this.handlePress}
onFocus={this.handelFocus.bind(this, i)}
value={valueArr[i]}
/>
)
}
return(
<div className='password-component'>
{inputs}
</div>
)
}
}
14 changes: 7 additions & 7 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import './index.css';
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import App from './App'
import registerServiceWorker from './registerServiceWorker'
import './index.css'

ReactDOM.render(
<App />,
document.getElementById('root') as HTMLElement
);
registerServiceWorker();
)
registerServiceWorker()
Loading

0 comments on commit 6b5eed6

Please sign in to comment.