Closed yingwinwin closed 3 years ago
import React, { Component } from "react";
import "../css/picker.css";
export default class Picker extends Component {
render() {
return (
<div className="picker-wrap">
<div className="picker-title">
<div className="picker-cancel">取消</div>
<div className="picker-sure">确定</div>
</div>
<div className="picker-content-wrap">
<ul className="picker-content">
<li className="picker-list">123</li>
<li className="picker-list">123</li>
<li className="picker-list">123</li>
<li className="picker-list">123</li>
<li className="picker-list">123</li>
</ul>
<div className="picker-up-shadow"></div>
<div className="picker-line"></div>
<div className="picker-down-shadow"></div>
</div>
</div>
);
}
}
.mask() {
position: absolute;
width: 100%;
pointer-events: none;
padding: 0 0.533rem;
box-sizing: border-box;
}
* {
padding: 0;
margin: 0;
}
ul li {
list-style: none;
}
.picker-wrap {
width: 100vw;
height: 250px;
overflow: hidden;
position: absolute;
left: 0;
background: #fff;
touch-action: none;
color: #333;
border-radius: 0.32rem 0.32rem 0 0;
display: flex;
flex-direction: column;
.picker-title {
display: flex;
justify-content: space-between;
padding: 0 0.533rem;
height: 50px;
line-height: 50px;
box-sizing: border-box;
position: relative;
border-bottom: 1px solid rgb(#526279, 0.1);
}
.picker-sure {
color: #4c97ff;
}
}
.picker-content-wrap {
position: relative;
width: 100vw;
background: #fff;
display: flex;
overflow: hidden;
.picker-content {
position: relative;
flex: 1;
transition: 0.03s ease-out 0s;
-webkit-transition: -webkit-transform 0.03s ease-out 0s;
transition: transform 0.2s ease-out;
.picker-list {
height: 40px;
line-height: 40px;
position: relative;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
}
.picker-up-shadow {
.mask();
top: 0;
height: 80px;
background-image: linear-gradient(
to bottom,
#fff,
rgba(255, 255, 255, 0.5)
);
z-index: 50;
}
.picker-down-shadow {
.mask();
background-image: linear-gradient(to top, #fff, rgba(255, 255, 255, 0.5));
z-index: 50;
top: 120px;
height: 80px;
}
.picker-line {
width: 95vw;
left: 50%;
box-sizing: border-box;
transform: translate3d(-50%, 0, 0);
-webkit-transform: translate3d(-50%, 0, 0);
position: absolute;
pointer-events: none;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
height: 40px;
top: 80px;
}
}
import React, { Component } from "react";
import Picker from "./components/Picker";
export default class App extends Component {
handleDate = () => {
let hour = [];
for (let i = 0; i < 23; i++) {
hour.push({ value: i, key: i });
}
let min = [];
for (let i = 0; i < 59; i++) {
min.push({ value: i, key: i });
}
return [hour, min, min];
};
handleData = () => {
let prov = [
{ value: "北京", key: "01" },
{ value: "杭州", key: "33" },
];
let city = {
"01": [{ value: "北京市", key: "0101" }],
"33": [
{ value: "江干区", key: "3301" },
{ value: "滨江区", key: "3302" },
{ value: "西湖区", key: "3303" },
],
};
let area = {
"0101": [{ value: "丰台区", key: "010101" }],
"3301": [
{ value: "彭埠街道", key: "330101" },
{ value: "四季青街道", key: "330102" },
],
"3302": [
{ value: "长河街道", key: "330201" },
{ value: "西兴街道", key: "330202" },
],
"3303": [
{ value: "蒋村街道", key: "330301" },
{ value: "古荡街道", key: "330302" },
{ value: "灵隐街道", key: "330303" },
],
};
return [prov, city, area];
};
render() {
return <Picker data={this.handleData()} format={[2, 2]} isLink={true} />;
}
}
import React, { Component } from "react";
import { array } from "prop-types";
import "../css/picker.css";
export default class Picker extends Component {
static propTypes = {
data: array.isRequired,
};
static defaultProps = {
data: [],
};
constructor(props) {
super();
this.state = {
translateY: props.data.map((item) => 0),
};
this.liHeight = 40;
}
//普通滚动
handleStart = (event) => {
event.preventDefault();
this.startFinger = event.changedTouches[0].clientY;
this.startFinger = event.targetTouches[0].pageY;
this.temp = [...this.state.translateY];
};
handleMove = (event, idx) => {
event.preventDefault();
let nowFinger = event.changedTouches[0].clientY;
let distance = nowFinger - this.startFinger;
let tempTramslateY = [...this.state.translateY].map((item, index) => {
if (idx === index) {
item = this.temp[idx] + distance;
}
return item;
});
this.setState({
translateY: tempTramslateY,
});
};
handleEnd = (event, idx, len) => {
event.preventDefault();
let temTranslateY = [...this.state.translateY].map((item, index) => {
if (idx === index) {
item = item > 0 ? 0 : item;
item =
item < (-len + 1) * this.liHeight ? (-len + 1) * this.liHeight : item;
let sub = item % this.liHeight;
if (sub < this.liHeight / 2) {
item = item - sub;
} else {
item = item + (this.liHeight - sub);
}
}
return item;
});
this.setState({
translateY: temTranslateY,
});
};
renderPickerCol = (data) => {
return data.map((item, idx) => (
<ul
className="picker-content"
key={idx}
onTouchStart={this.handleStart}
onTouchMove={(e) => this.handleMove(e, idx)}
onTouchEnd={(e) => this.handleEnd(e, idx, item.length)}
style={{
transform: `translate3d(0, ${this.state.translateY[idx]}px, 0)`,
}}
>
{this.renderPickerList(item)}
</ul>
));
};
renderPickerList = (item) => {
return item.map((ele) => (
<li className="picker-list" key={ele.key}>
{ele.value}
</li>
));
};
render() {
return (
<div className="picker-wrap">
<div className="picker-title">
<div className="picker-cancel">取消</div>
<div className="picker-sure">确定</div>
</div>
<div className="picker-content-wrap">
{this.renderPickerCol(this.props.data)}
<div className="picker-up-shadow"></div>
<div className="picker-line"></div>
<div className="picker-down-shadow"></div>
</div>
</div>
);
}
}
import React, { Component } from "react";
import { array, bool } from "prop-types";
import "../css/picker.css";
export default class Picker extends Component {
static propTypes = {
data: array.isRequired,
format: array,
isLink: bool,
};
static defaultProps = {
data: [],
format: [2, 2],
isLink: false,
};
constructor(props) {
super();
this.state = {
translateY: props.data.map((item) => 0),
link: props.data.map((item) => 0),
};
this.liHeight = 40;
}
setLink = (idx) => {
let length = this.props.data.length;
let translateY = [...this.state.translateY];
let link = [...this.state.link];
translateY[idx] = parseInt(this.state.translateY[idx]);
link[idx] = parseInt(Math.abs(this.state.translateY[idx])) / this.liHeight;
if (this.props.isLink) {
for (let i = 1; i < length - idx; i++) {
translateY[length - i] = 0;
link[length - i] = 0;
}
}
this.setState({
translateY,
link,
});
};
//普通滚动
handleStart = (event) => {
event.preventDefault();
this.startFinger = event.changedTouches[0].clientY;
this.startFinger = event.targetTouches[0].pageY;
this.temp = [...this.state.translateY];
};
handleMove = (event, idx) => {
event.preventDefault();
let nowFinger = event.changedTouches[0].clientY;
let distance = nowFinger - this.startFinger;
let tempTramslateY = [...this.state.translateY].map((item, index) => {
if (idx === index) {
item = this.temp[idx] + distance;
}
return item;
});
this.setState({
translateY: tempTramslateY,
});
};
handleEnd = (event, idx, len) => {
event.preventDefault();
let tempTranslateY = [...this.state.translateY].map((item, index) => {
if (idx === index) {
item = item > 0 ? 0 : item;
item =
item < (-len + 1) * this.liHeight ? (-len + 1) * this.liHeight : item;
let sub = item % this.liHeight;
if (sub < this.liHeight / 2) {
item = item - sub;
} else {
item = item + (this.liHeight - sub);
}
}
return item;
});
this.setState(
{
translateY: tempTranslateY,
},
() => {
this.setLink(idx);
}
);
};
handleFormat = (format) => {
let formatArr = [];
while (format--) {
formatArr.push(<li key={format} className="picker-list"></li>);
}
return formatArr;
};
renderPickerCol = (data, format, isLink, link) => {
if (!data.length) return;
const { translateY } = this.state;
let arr = [];
arr[0] = data[0];
let selectArr = [];
selectArr[0] = data[0][link[0]];
for (let i = 1; i < data.length; i++) {
if (isLink) {
if (data[i][selectArr[i - 1].key]) {
selectArr.push(data[i][selectArr[i - 1].key][link[i]]);
arr.push(data[i][arr[i - 1][link[i - 1]].key]);
} else {
alert("数据配置错误!");
return;
}
} else if (!isLink) {
selectArr.push(data[i][link[i]]);
arr.push(data[i]);
}
}
return arr.map((item, idx) => (
<ul
className="picker-content"
key={idx}
onTouchStart={this.handleStart}
onTouchMove={(e) => this.handleMove(e, idx)}
onTouchEnd={(e) => this.handleEnd(e, idx, item.length)}
style={{ transform: `translate3d(0, ${translateY[idx]}px, 0)` }}
>
{this.handleFormat(format[0])}
{this.renderPickerList(item)}
{this.handleFormat(format[1])}
</ul>
));
};
renderPickerList = (item) => {
return item.map((ele) => (
<li className="picker-list" key={ele.key}>
{ele.value}
</li>
));
};
render() {
const { data, format, isLink } = this.props;
const { link } = this.state;
return (
<div className="picker-wrap">
<div className="picker-title">
<div className="picker-cancel">取消</div>
<div className="picker-sure">确定</div>
</div>
<div className="picker-content-wrap">
{this.renderPickerCol(data, format, isLink, link)}
<div className="picker-up-shadow"></div>
<div className="picker-line"></div>
<div className="picker-down-shadow"></div>
</div>
</div>
);
}
}
import React, { Component } from "react";
import Picker from "./components/Picker";
export default class App extends Component { state = { show: false, text: "", initValue: [] } handleDate = () => { let hour = []; for (let i = 0; i < 23; i++) { hour.push({ value: i, key: i }); }
let min = [];
for (let i = 0; i < 59; i++) {
min.push({ value: i, key: i });
}
return [hour, min, min];
};
handleData = () => { let prov = [ { value: "北京", key: "01" }, { value: "杭州", key: "33" }, ]; let city = { "01": [{ value: "北京市", key: "0101" }], "33": [ { value: "江干区", key: "3301" }, { value: "滨江区", key: "3302" }, { value: "西湖区", key: "3303" }, ], }; let area = { "0101": [{ value: "丰台区", key: "010101" }], "3301": [ { value: "彭埠街道", key: "330101" }, { value: "四季青街道", key: "330102" }, ], "3302": [ { value: "长河街道", key: "330201" }, { value: "西兴街道", key: "330202" }, ], "3303": [ { value: "蒋村街道", key: "330301" }, { value: "古荡街道", key: "330302" }, { value: "灵隐街道", key: "330303" }, ], }; return [prov, city, area]; };
handleClosed = () => { this.setState({ show: false }) }
handleSure = (v) => {
this.setState({
show: false,
text: ${v[0].value}${v[1].value}${v[2].value}
,
initValue: v
})
console.log(v)
}
openPicker = () => { this.setState({ show: true }) }
handleChange = () => { this.setState({ initValue: this.state.text }) }
render() { return (
);
} }
- 组件
```jsx
import React, { Component } from "react";
import { array, bool, func } from "prop-types";
import "../css/picker.css";
export default class Picker extends Component {
static propTypes = {
data:array.isRequired,
format: array,
isLink: bool,
initValue: array,
handleClosed: func,
handleSure: func
};
static defaultProps = {
data: [],
format: [2, 2],
isLink: false,
initValue: []
};
constructor(props) {
super();
this.state = {
translateY: props.data.map((item) => 0),
link: props.data.map((item) => 0),
};
this.liHeight = 40;
this.select = props.initValue.length > 0 && props.initValue[0].key !== '' ? props.initValue : this.defaultInitValue(props)
}
componentDidMount() {
const { data, initValue } = this.props;
if(!(initValue.length > 0 && data.length > 0)) return; // 如果父组件没有穿初始值就不设置初始值
for(let i = 0; i < data.length; i++) {
if(initValue[i].key === '' || initValue[i].value === '') return // 如果父组件没有穿初始值就不设置初始值
}
this.setInitValue(); // 如果设置了,就设置初始值
}
/* 默认初始值,没有给初始值,默认数组的第一项 */
defaultInitValue = (props) => {
const { data, initValue, isLink } = props;
if(!initValue.length > 0) {
let initValue = [];
for(let i = 0; i < data.length; i ++) {
if(isLink && i === 0) {
initValue[i] = data[i][0]; // 联动
} else {
initValue[i] = data[i][initValue[i - 1].key][0]; // 非联动
}
}
}
return initValue;
}
/* 设置初始值 */
setInitValue = () => {
const { data, initValue, isLink } = this.props;
let link = [...this.state.link];
let translateY = [...this.state.translateY];
// 在data里面把用户传过来的值找到,转换为初始值,translateY的高度和数组的下标随之改变
for(let out = 0; out < data.length; out ++) {
if( out === 0 || !isLink) {
for(let i = 0; i < data[out].length; i ++) {
if(data[out][i].key === initValue[out].key) {
link[out] = i;
translateY[out] = -i * this.liHeight;
}
}
} else {
if(data[out][initValue[out - 1].key]){
for(let i = 0; i < data[out][initValue[out - 1].key].length; i++) {
if(data[out][initValue[out - 1].key][i].key === initValue[out].key) {
link[out] = i;
translateY[out] = -i * this.liHeight;
}
}
} else {
alert('数据配置错误')
}
}
}
this.setState({
link,
translateY
});
}
/* 获取数据 */
getSelect = () => {
const { data, isLink } = this.props;
const { link } = this.state;
let selecArr = [];
selecArr[0] = data[0][link[0]];
for(let i = 1; i < data.length; i ++) {
if(isLink) {
selecArr.push(data[i][selecArr[i - 1].key][link[i]]);
} else if (!isLink){
selecArr.push(data[i][link[i]]);
}
}
return selecArr;
}
// 设置联动
setLink = (idx) => {
let length = this.props.data.length;
let translateY = [...this.state.translateY];
let link = [...this.state.link];
translateY[idx] = parseInt(this.state.translateY[idx]); // 当前滚动的距离
link[idx] = parseInt(Math.abs(this.state.translateY[idx])) / this.liHeight; // 当前滚动的数组下标
// 如果是联动的话
if (this.props.isLink) {
for (let i = 1; i < length - idx; i++) {
translateY[length - i] = 0;
link[length - i] = 0;
}
}
this.setState({
translateY,
link,
});
};
//普通滚动
handleStart = (event) => {
event.preventDefault();
this.startFinger = event.changedTouches[0].clientY;
this.temp = [...this.state.translateY];
};
// 处理移动手势
handleMove = (event, idx) => {
event.preventDefault();
let nowFinger = event.changedTouches[0].clientY;
let distance = nowFinger - this.startFinger;
let tempTramslateY = [...this.state.translateY].map((item, index) => {
if (idx === index) {
item = this.temp[idx] + distance; // 点击到的距离 + 滑动的距离 = 移动的距离
}
return item;
});
this.setState({
translateY: tempTramslateY,
});
};
/* 处理结束时滚动 */
handleEnd = (event, idx, len) => {
// 阻止冒泡
event.preventDefault();
let tempTranslateY = [...this.state.translateY].map((item, index) => {
// 如果是当前滑动的这一项
if (idx === index) {
item = item > 0 ? 0 : item; // 如果小于 0 , 就等于 0 否则就是它移动的距离
item =
item < (-len + 1) * this.liHeight ? (-len + 1) * this.liHeight : item; // 如果小于最大高度就是当前的距离,否则就是最大高度
let sub = item % this.liHeight; // 如果当前的距离 膜 高度
// 如果小于高度的一半就是当前高度 - 膜出来的距离, 否则就加上
if (sub < this.liHeight / 2) {
item = item - sub;
} else {
item = item + (this.liHeight - sub);
}
}
return item;
});
this.setState(
{
translateY: tempTranslateY,
},
() => {
this.setLink(idx);
}
);
};
// 处理数据结构
handleFormat = (format) => {
let formatArr = [];
while (format--) {
formatArr.push(<li key={format} className="picker-list"></li>);
}
return formatArr;
};
/* 渲染picker组件的列 */
renderPickerCol = (data, format, isLink, link) => {
if (!data.length) return;
const { translateY } = this.state;
let arr = [];
arr[0] = data[0];
let selectArr = [];
selectArr[0] = data[0][link[0]];
for (let i = 1; i < data.length; i++) {
// 如果是联动的话
if (isLink) {
if (data[i][selectArr[i - 1].key]) {
selectArr.push(data[i][selectArr[i - 1].key][link[i]]);
arr.push(data[i][arr[i - 1][link[i - 1]].key]);
} else {
alert("数据配置错误!");
return;
}
// 不联动的话
} else if (!isLink) {
selectArr.push(data[i][link[i]]);
arr.push(data[i]);
}
}
this.select = selectArr
return arr.map((item, idx) => (
<ul
className="picker-content"
key={idx}
onTouchStart={this.handleStart}
onTouchMove={(e) => this.handleMove(e, idx)}
onTouchEnd={(e) => this.handleEnd(e, idx, item.length)}
style={{ transform: `translate3d(0, ${translateY[idx]}px, 0)` }}
>
{this.handleFormat(format[0])}
{this.renderPickerList(item)}
{this.handleFormat(format[1])}
</ul>
));
};
// 渲染picker组件的每一项
renderPickerList = (item) => {
return item.map((ele) => (
<li className="picker-list" key={ele.key}>
{ele.value}
</li>
));
};
handleClosed = () => {
this.props.handleClosed()
}
handleSure = (e) => {
e.stopPropagation();
this.props.handleSure(this.getSelect());
}
render() {
const { data, format, isLink } = this.props;
const { link } = this.state;
return (
<div className="picker-mask">
<div className="picker-wrap">
<div className="picker-title">
<div className="picker-cancel" onClick={this.handleClosed}>取消</div>
<div className="picker-sure" onClick={this.handleSure}>确定</div>
</div>
<div className="picker-content-wrap">
{this.renderPickerCol(data, format, isLink, link)}
<div className="picker-up-shadow"></div>
<div className="picker-line"></div>
<div className="picker-down-shadow"></div>
</div>
</div>
</div>
);
}
}
.mask() {
position: absolute;
width: 100%;
pointer-events: none;
padding: 0 .533rem;
box-sizing: border-box;
}
*{
padding: 0;
margin: 0;
}
ul li{ list-style: none; }
.picker-mask{ position: fixed; width: 100vw; height: 100vh; background: rgba(0, 0, 0, 0.5); top: 0; left: 0; z-index: 1;
.picker-wrap {
width: 100vw;
height: 250px;
overflow: hidden;
position: absolute;
bottom: 0;
left: 0;
background: #fff;
touch-action: none;
color: #333;
border-radius: 0.32rem 0.32rem 0 0;
display: flex;
flex-direction: column;
.picker-title {
display: flex;
justify-content: space-between;
padding: 0 .533rem;
height: 50px;
line-height: 50px;
box-sizing: border-box;
position: relative;
border-bottom: 1px solid rgb(#526279, 0.1);
}
.picker-sure {
color: #4c97ff;
}
}
.picker-content-wrap {
position: relative;
width: 100vw;
background: #fff;
display: flex;
overflow: hidden;
.picker-content {
position: relative;
flex: 1;
transition: 0.03s ease-out 0s;
-webkit-transition: -webkit-transform 0.03s ease-out 0s;
transition: transform 0.2s ease-out;
z-index: 2;
.picker-list {
height: 40px;
line-height: 40px;
position: relative;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
z-index: 2;
}
}
.picker-up-shadow {
.mask();
top:0;
height: 80px;
background-image: linear-gradient(to bottom, #fff, rgba(255, 255, 255, 0.5));
z-index: 50;
}
.picker-down-shadow {
.mask();
background-image: linear-gradient(to top, #fff, rgba(255, 255, 255, 0.5));
z-index: 50;
top: 120px;
height: 80px;
}
.picker-line {
width: 95vw;
left: 50%;
box-sizing: border-box;
transform: translate3d(-50%, 0, 0);
-webkit-transform: translate3d(-50%, 0, 0);
position: absolute;
pointer-events: none;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
height: 40px;
top: 80px;
}
}
}
![image](https://user-images.githubusercontent.com/55273635/87178912-7c44d400-c310-11ea-8a4f-d08b764e873d.png)
import React, { Component } from "react";
import { array, bool, func } from "prop-types";
import "../css/picker.css";
export default class Picker extends Component {
static propTypes = {
data:array.isRequired,
format: array,
isLink: bool,
initValue: array,
handleClosed: func,
handleSure: func
};
static defaultProps = {
data: [],
format: [2, 2],
isLink: false,
initValue: []
};
constructor(props) {
super();
this.state = {
translateY: props.data.map((item) => 0),
link: props.data.map((item) => 0),
};
this.liHeight = 40;
this.checkProps(props);
this.select = props.initValue.length > 0 && props.initValue[0].key !== '' ? props.initValue : this.defaultInitValue(props)
}
componentDidMount() {
const { data, initValue } = this.props;
if(!(initValue.length > 0 && data.length > 0)) return; // 如果父组件没有穿初始值就不设置初始值
for(let i = 0; i < data.length; i++) {
if(initValue[i].key === '' || initValue[i].value === '') return // 如果父组件没有穿初始值就不设置初始值
}
this.setInitValue(); // 如果设置了,就设置初始值
}
/* 检查传过来的内容是否正确 */
checkProps = (props) => {
/* 如果data,没有长度就return */
if(!(props.data.length > 0)) return console.error('请传入数据!');
/* 如果data的【0】不是数组,或data不是数组 */
if(!Array.isArray(props.data[0]) || !Array.isArray(props.data)) {
console.error('数据结构错误!');
return;
} else {
if( props.isLink) {
for(let i = 1; i < props.data.length; i++) {
if(Object.prototype.toString.call(props.data[i]) !== "[object Object]") return console.error('数据结构错误!');
}
} else {
for( let i = 1; i < props.data.length; i++) {
if(!Array.isArray(props.data[i])) return console.error('数据结构错误!');
}
}
}
if (!(props.initValue.length > 0 && props.data.length > 0)) return;
if(!Array.isArray(props.initValue)) {
console.error('初始值结构错误!');
return;
} else {
for(let i = 0; i < props.initValue.length; i++) {
if(Object.prototype.toString.call(props.initValue[i]) !== "[object Object]") return console.error('初始值结构错误!');
}
}
}
/* 默认初始值,没有给初始值,默认数组的第一项 */
defaultInitValue = (props) => {
const { data, initValue, isLink } = props;
if(!initValue.length > 0) {
let initValue = [];
for(let i = 0; i < data.length; i ++) {
if(isLink && i === 0) {
initValue[i] = data[i][0]; // 联动
} else {
initValue[i] = data[i][initValue[i - 1].key][0]; // 非联动
}
}
}
return initValue;
}
/* 设置初始值 */
setInitValue = () => {
const { data, initValue, isLink } = this.props;
let link = [...this.state.link];
let translateY = [...this.state.translateY];
// 在data里面把用户传过来的值找到,转换为初始值,translateY的高度和数组的下标随之改变
for(let out = 0; out < data.length; out ++) {
if( out === 0 || !isLink) {
for(let i = 0; i < data[out].length; i ++) {
if(data[out][i].key === initValue[out].key) {
link[out] = i;
translateY[out] = -i * this.liHeight;
}
}
} else {
if(data[out][initValue[out - 1].key]){
for(let i = 0; i < data[out][initValue[out - 1].key].length; i++) {
if(data[out][initValue[out - 1].key][i].key === initValue[out].key) {
link[out] = i;
translateY[out] = -i * this.liHeight;
}
}
} else {
alert('数据配置错误')
}
}
}
this.setState({
link,
translateY
});
}
/* 获取数据 */
getSelect = () => {
const { data, isLink } = this.props;
const { link } = this.state;
let selecArr = [];
selecArr[0] = data[0][link[0]];
for(let i = 1; i < data.length; i ++) {
if(isLink) {
selecArr.push(data[i][selecArr[i - 1].key][link[i]]);
} else if (!isLink){
selecArr.push(data[i][link[i]]);
}
}
return selecArr;
}
// 设置联动
setLink = (idx) => {
let length = this.props.data.length;
let translateY = [...this.state.translateY];
let link = [...this.state.link];
translateY[idx] = parseInt(this.state.translateY[idx]); // 当前滚动的距离
link[idx] = parseInt(Math.abs(this.state.translateY[idx])) / this.liHeight; // 当前滚动的数组下标
// 如果是联动的话
if (this.props.isLink) {
for (let i = 1; i < length - idx; i++) {
translateY[length - i] = 0;
link[length - i] = 0;
}
}
this.setState({
translateY,
link,
});
};
//普通滚动
handleStart = (event) => {
event.preventDefault();
this.startFinger = event.changedTouches[0].clientY;
this.temp = [...this.state.translateY];
};
// 处理移动手势
handleMove = (event, idx) => {
event.preventDefault();
let nowFinger = event.changedTouches[0].clientY;
let distance = nowFinger - this.startFinger;
let tempTramslateY = [...this.state.translateY].map((item, index) => {
if (idx === index) {
item = this.temp[idx] + distance; // 点击到的距离 + 滑动的距离 = 移动的距离
}
return item;
});
this.setState({
translateY: tempTramslateY,
});
};
/* 处理结束时滚动 */
handleEnd = (event, idx, len) => {
// 阻止冒泡
event.preventDefault();
let tempTranslateY = [...this.state.translateY].map((item, index) => {
// 如果是当前滑动的这一项
if (idx === index) {
item = item > 0 ? 0 : item; // 如果小于 0 , 就等于 0 否则就是它移动的距离
item =
item < (-len + 1) * this.liHeight ? (-len + 1) * this.liHeight : item; // 如果小于最大高度就是当前的距离,否则就是最大高度
let sub = item % this.liHeight; // 如果当前的距离 膜 高度
// 如果小于高度的一半就是当前高度 - 膜出来的距离, 否则就加上
if (sub < this.liHeight / 2) {
item = item - sub;
} else {
item = item + (this.liHeight - sub);
}
}
return item;
});
this.setState(
{
translateY: tempTranslateY,
},
() => {
this.setLink(idx);
}
);
};
// 处理数据结构
handleFormat = (format) => {
let formatArr = [];
while (format--) {
formatArr.push(<li key={format} className="picker-list"></li>);
}
return formatArr;
};
/* 渲染picker组件的列 */
renderPickerCol = (data, format, isLink, link) => {
if (!data.length) return;
const { translateY } = this.state;
let arr = [];
arr[0] = data[0];
let selectArr = [];
selectArr[0] = data[0][link[0]];
for (let i = 1; i < data.length; i++) {
// 如果是联动的话
if (isLink) {
if (data[i][selectArr[i - 1].key]) {
selectArr.push(data[i][selectArr[i - 1].key][link[i]]);
arr.push(data[i][arr[i - 1][link[i - 1]].key]);
} else {
alert("数据配置错误!");
return;
}
// 不联动的话
} else if (!isLink) {
selectArr.push(data[i][link[i]]);
arr.push(data[i]);
}
}
this.select = selectArr
return arr.map((item, idx) => (
<ul
className="picker-content"
key={idx}
onTouchStart={this.handleStart}
onTouchMove={(e) => this.handleMove(e, idx)}
onTouchEnd={(e) => this.handleEnd(e, idx, item.length)}
style={{ transform: `translate3d(0, ${translateY[idx]}px, 0)` }}
>
{this.handleFormat(format[0])}
{this.renderPickerList(item)}
{this.handleFormat(format[1])}
</ul>
));
};
// 渲染picker组件的每一项
renderPickerList = (item) => {
return item.map((ele) => (
<li className="picker-list" key={ele.key}>
{ele.value}
</li>
));
};
handleClosed = () => {
this.props.handleClosed()
}
handleSure = (e) => {
e.stopPropagation();
this.props.handleSure(this.getSelect());
}
render() {
const { data, format, isLink } = this.props;
const { link } = this.state;
return (
<div className="picker-mask">
<div className="picker-wrap">
<div className="picker-title">
<div className="picker-cancel" onClick={this.handleClosed}>取消</div>
<div className="picker-sure" onClick={this.handleSure}>确定</div>
</div>
<div className="picker-content-wrap">
{this.renderPickerCol(data, format, isLink, link)}
<div className="picker-up-shadow"></div>
<div className="picker-line"></div>
<div className="picker-down-shadow"></div>
</div>
</div>
</div>
);
}
}
打算从头整理一下最近项目中写的picker组件的内容,比较多要从头开始写。