Skip to content

Commit

Permalink
feat(组件): 新增 Picker 组件
Browse files Browse the repository at this point in the history
  • Loading branch information
fjc0k committed Feb 14, 2019
1 parent 4464027 commit 77c3bd9
Show file tree
Hide file tree
Showing 9 changed files with 276 additions and 5 deletions.
3 changes: 2 additions & 1 deletion src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ class App extends Taro.Component {
// 'pages/Sticky/Sticky',
// 'pages/Transition/X',
// 'pages/Popup/Popup',
'pages/PickerView/PickerView',
// 'pages/Picker/PickerView',
'pages/Picker/Picker',
],
window: {
navigationBarTitleText: 'DEMO',
Expand Down
35 changes: 35 additions & 0 deletions src/components/Picker/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@import '../../settings.scss';

.view {
background: white;
width: 100vw;
font-size: 17px;
.header {
display: flex;
align-items: center;
padding: 10px 15px;
border-bottom: 1px solid $hairlineColor;
.cancel {
flex-shrink: 0;
font-size: 17px;
color: $grayColor;
&.hidden {
visibility: hidden;
opacity: 0;
pointer-events: none;
}
}
.title {
flex-grow: 1;
text-align: center;
margin: 0 15px;
font-size: 19px;
@include ellipsis;
}
.confirm {
flex-shrink: 0;
font-size: 17px;
color: $primaryColor;
}
}
}
119 changes: 119 additions & 0 deletions src/components/Picker/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { View } from '@tarojs/components'
import { noop } from 'vtils'
import { component } from '../component'
import MPickerView, { Data } from '../PickerView'
import MPopup from '../Popup'
import _ from './index.module.scss'

export default class MPicker<D extends Data, V extends (D extends Data<infer VV> ? VV : any) = any> extends component({
props: {
maskClosable: true as boolean,
data: [],
value: [],
itemHeight: '2.5em' as string,
visibleItemCount: 5 as number,
title: '' as string,
noCancel: false as boolean,
cancelText: '取消' as string,
confirmText: '确定' as string,
onCancel: noop as () => void,
onConfirm: noop,
},
state: {
localVisible: false as boolean,
localValue: [],
},
})<{
data: D,
value?: V[],
onConfirm?: (value: V[]) => void,
}, {
localValue: V[],
}> {
componentWillMount() {
const { value } = this.props
this.setState({
localValue: value,
})
}

componentWillReceiveProps({ value }: MPicker<D>['props']) {
this.setState({
localValue: value,
})
}

handleTriggerClick = () => {
this.setState(prevState => ({
localVisible: !prevState.localVisible,
}))
}

handleVisibleChange: MPopup['props']['onVisibleChange'] = visible => {
this.setState({
localVisible: visible,
...(visible ? {} as any : { localValue: this.props.value }),
})
}

handlePickerChange: MPickerView<D>['props']['onChange'] = value => {
this.setState({
localValue: value,
})
}

handleCancelClick = () => {
this.setState({
localValue: this.props.value,
localVisible: false,
}, () => {
this.props.onCancel()
})
}

handleConfirmClick = () => {
this.setState({
localVisible: false,
}, () => {
this.props.onConfirm(this.state.localValue)
})
}

render() {
const { maskClosable, data, itemHeight, visibleItemCount, noCancel, cancelText, confirmText, title } = this.props
const { localVisible, localValue } = this.state
return (
<View className={_.picker}>
<View className={_.trigger} onClick={this.handleTriggerClick}>
{this.props.children}
</View>
<MPopup
position='bottom'
visible={localVisible}
maskClosable={maskClosable}
onVisibleChange={this.handleVisibleChange}>
<View className={_.view}>
<View className={_.header}>
<View className={`${_.cancel} ${noCancel && _.hidden}`} onClick={this.handleCancelClick}>
{cancelText}
</View>
<View className={_.title}>
{title}
</View>
<View className={_.confirm} onClick={this.handleConfirmClick}>
{confirmText}
</View>
</View>
<MPickerView
data={data}
value={localValue}
itemHeight={itemHeight}
visibleItemCount={visibleItemCount}
onChange={this.handlePickerChange}
/>
</View>
</MPopup>
</View>
)
}
}
4 changes: 1 addition & 3 deletions src/components/PickerView/index.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
justify-content: center;
.label {
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@include ellipsis;
}
}
2 changes: 1 addition & 1 deletion src/components/PickerView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export type ColData<V = any> = NormalColData<V> | CascadedColData<V>

export type Data<V = any> = NormalData<V> | CascadedData<V>

export default class MPickerView<D extends Data, V extends (D extends Data<infer VV> ? VV : any)> extends component({
export default class MPickerView<D extends Data, V extends (D extends Data<infer VV> ? VV : any) = any> extends component({
props: {
data: [],
value: [],
Expand Down
2 changes: 2 additions & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// @index(^[A-Z]): export { default as M${variable/Block$//:pascal:} } from ${relpath}
export { default as MPicker } from './Picker'
export { default as MPickerView } from './PickerView'
export { default as MPopup } from './Popup'
export { default as MSticky } from './Sticky'
export { default as MTransition } from './Transition'
100 changes: 100 additions & 0 deletions src/pages/Picker/Picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { View } from '@tarojs/components'
import { component } from '../../components/component'
import { MPicker } from '../../components'

let i = 0
let l = 0

const getData = () => {
const flag = i++
return [
`中国${flag}`,
`日本${flag}`,
`美国${flag}`,
`俄罗斯${flag}`,
].reduce((res, country) => {
res.push({
label: country,
value: country,
})
return res
}, [] as any)
}

const getCascadedData = () => {
const flag = l++
return [
`中国${flag}`,
`日本${flag}`,
`美国${flag}`,
`俄罗斯${flag}`,
].reduce((res, country) => {
res.push({
label: country,
value: country,
})
return res
}, [] as any)
}

export default class Picker extends component({
state: {
data: [
getData(),
getData(),
],
value: ['日本0', '俄罗斯1'],
cascadedData: getCascadedData().map(colData => {
colData.children = getCascadedData()
colData.children.map(colData2 => {
colData2.children = getCascadedData()
return colData2
})
return colData
}),
cascadedValue: ['日本0', '俄罗斯1'],
},
}) {
handleChange: MPicker<any, any>['props']['onConfirm'] = value => {
this.setState({ value })
}

handleChange2: MPicker<any, any>['props']['onConfirm'] = value => {
console.log('changed')
this.setState({ cascadedValue: value })
}

render() {
const { data, value, cascadedData, cascadedValue } = this.state
return (
<View style={{
fontSize: '16px',
}}>
<View style={{ fontWeight: 'bold', padding: '10px 0', marginBottom: '10px', borderBottom: '1px solid #eee' }}>
NormalPicker
</View>
<MPicker
maskClosable={false}
title='选择一个国家'
data={data}
value={value}
onConfirm={this.handleChange}>
{JSON.stringify(value)}
</MPicker>

<View style={{ fontWeight: 'bold', padding: '10px 0', marginBottom: '10px', borderBottom: '1px solid #eee' }}>
CascadedPicker
</View>
<MPicker
title='选择你喜欢的城市'
noCancel={true}
data={cascadedData}
visibleItemCount={4}
value={cascadedValue}
onConfirm={this.handleChange2}>
{JSON.stringify(cascadedValue)}
</MPicker>
</View>
)
}
}
File renamed without changes.
16 changes: 16 additions & 0 deletions src/settings.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
$primaryColor: #1AAD19;
$grayColor: #999;
$hairlineColor: #E5E5E5;

@mixin ellipsis($line: 1) {
@if $line == 1 {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
} @else {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: $line;
}
}

0 comments on commit 77c3bd9

Please sign in to comment.