代码规范
案例
多选组件的实现
传参
CommonSelector.propTypes = {
// 标题
headerTitle: PropTypes.string,
// 是否展示全选
showSelectAll: PropTypes.bool,
// 是否需要展开收起
showExpandAndCollapse: PropTypes.bool,
sliceIndex: PropTypes.number,
// 选项列表
dataList: PropTypes.array,
// 已选列表
selectedList: PropTypes.array,
// 选项更改方法
onSelectChange: PropTypes.func
}
样式
<View className="filter-item-wrap">
{showSelectAll && (
<Text
className={`filter-item ${selectedList.length === dataList.length ? 'chosen' : ''}`}
onClick={toggleSelectAll}>
全部
</Text>
)}
{!showExpandAndCollapse && (
<Block>
{dataList.map(item => {
return (
<Text
className={`filter-item ${selectedList.includes(item.value) ? 'chosen' : ''}`}
key={item.value}
onClick={(e) => {handleSelectChange(e)}}
data-value={item.value}
>
{item.label}
</Text>
)
})}
</Block>
)}
</View>
逻辑处理
// 点击全部
function toggleSelectAll() {
let list = []
if (selectedList.length === dataList.length) {
list = []
} else {
list = dataList.map(item => item.value)
}
onSelectChange(list)
}
// 点击子项
function handleSelectChange(e) {
const {value} = e.currentTarget.dataset
if (selectedList.includes(value)) {
selectedList = selectedList.filter(item => item !== value)
} else {
selectedList.push(value)
}
onSelectChange(selectedList)
}
外部使用
// 变量
purchaseIntentionList: [ // 潜力客户选项
{ value: 'A1', label: 'A1' },
{ value: 'A2', label: 'A2' },
{ value: 'A3', label: 'A3' },
{ value: 'B1', label: 'B1' },
{ value: 'B2', label: 'B2' },
{ value: 'C', label: 'C' },
{ value: '', label: '未分类' }
],
chooseList: [] // 选择的潜力标签
// change function
handlePotentialLabelSelect(selectedList) {
this.setState({
chooseList: selectedList
})
this.restartRequest()
}
// 组件传值
{/* 潜力客户筛选 */}
<CommonSelector
headerTitle="潜力客户"
showExpandAndCollapse={true}
sliceIndex="3"
dataList={this.state.purchaseIntentionList}
selectedList={this.state.chooseList}
onSelectChange={this.handlePotentialLabelSelect.bind(this)}>
</CommonSelector>
思考:“全部”这个选项是否应该作为选项由父组件传入,还是直接放入子组件中,作为特殊处理?
purchaseIntentionList: [
{ label: '全部', value: null },
...
]
样式切换方式
常见场景:选中状态与非选中状态
1、使用模板字符串
<Text
className={`filter-item ${selectedList.length === dataList.length ? 'chosen' : ''}`}
onClick={toggleSelectAll}>
全部
</Text>
2、使用classnames
<Button
className={classNames(
'save-button-item',
currentSelect ? '' : 'opacity-save-button'
)}
onClick={this.confirmTransferDealerOfEnquiry.bind(this)}
>
确定
</Button>
思考:是否可以使用模板字符串,或者有什么其他更好地方法?
插件的使用的取舍:自己封装or直接用相关插件
案例:时间日期处理
日期方法
插件:moment.js
公共方法的拆分的维度
// 根据不同的版本设置不同的颜色
addSaasVersionColor() {
const { garageList } = this.state
if (garageList.length > 0) {
garageList.forEach(item => {
const color = saasVersionColorMap[item.packageType]
if (color) {
item.textColor = color.textColor
item.bgColor = color.bgColor
}
})
}
this.setState({
garageList
})
}
节点
<View
className="version-show"
style={{color: garage.textColor, background: garage.bgColor}}
>
{versionTypeMap[`${garage.buyFlag}-${garage.packageType}`]}
</View>
组件封装的标准?复用性的判定
state 的粒度问题
class components extends Components {
constructor(props) {
super(props)
this.state = {
// 省市区相关
areaState: {
districtCodes: [],
pageAreaData: [],
firstIndex: 0,
secondIndex: 0,
showArea: false
}
}
}
}
class components extends Components {
constructor(props) {
super(props)
this.state = {
// 省市区相关
districtCodes: [],
pageAreaData: [],
firstIndex: 0,
secondIndex: 0,
showArea: false
}
}
}
// 接收后端接口数据
class components extends Components {
constructor(props) {
super(props)
this.state = {
// 省市区相关
garageTotalCount: 0, // 数量
purchaseTotalAmount: 0, // 成交金额合计
purchaseCommissionTotalAmount: 0, // 抽佣合计
purchaseCommissionGrossTotalAmount: 0 // 抽佣毛利合计
}
}
}
async getGarageRanking() {
const {
pageNum,
pageSize
} = this.state
const requestData = this.formatRequestData()
const rankRes = await IncomeApi.getGaragePage(requestData, {pageNum, pageSize})
if (rankRes.success && rankRes.data) {
this.setState({
garageTotalCount: rankRes.data.totalCount || 0,
purchaseTotalAmount: rankRes.data.purchaseTotalAmount || 0,
purchaseCommissionTotalAmount: rankRes.data.purchaseCommissionTotalAmount || 0,
purchaseCommissionGrossTotalAmount: rankRes.data.purchaseCommissionGrossTotalAmount || 0
})
}
}
思考:是直接用一个data对象保存所有的数据,还是单独保存每一项目
页面数据默认展示值的处理
<View className="purchase-info">
<View className="info-item">{ (dealer.purchaseCount || 0) + '单'}</View>
<View className="line"></View>
<View className="info-item">¥{dealer.purchaseTotalAmount || 0}</View>
<View className="line"></View>
<View className="info-item">¥{(dealer.purchaseCommissionTotalAmount || 0 )}</View>
</View>
长函数
// 处理配件展示数据
handleQuotationDetail(quotationDetail) {
if(quotationDetail.oldApp==='1'){
//oldApp=1证明是老版本app,需要移除掉serviceQuotationProductGroupList
delete quotationDetail["serviceQuotationProductGroupList"]
}
if (
quotationDetail.serviceQuotationProductGroupList &&
quotationDetail.serviceQuotationProductGroupList.length > 0
) {
let partListFormat = [];
for (
let index = 0;
index < quotationDetail.serviceQuotationProductGroupList.length;
index++
) {
const element = quotationDetail.serviceQuotationProductGroupList[index];
if (element.productList.length == 1) {
let item = element.productList[0];
partListFormat.push({
...item,
productList: element.productList
});
} else {
let recommendPart =null
if(element.showTips){
recommendPart=element.productList.find(ele => ele.selectType) || null;
}else{
recommendPart=element.productList.find(ele => ele.recommendType) || null;
}
if(element.showTips){
recommendPart.showTips=element.showTips
}
partListFormat.push({
...recommendPart,
productList: element.productList
});
}
}
quotationDetail.serviceQuotationProductList = partListFormat;
//是否拥有不同品质配件
quotationDetail.haveDifferentQualitiesPart = quotationDetail.serviceQuotationProductList.some(
ele => ele.productList.length > 1
);
}
//设置了满减优惠 满足门槛将discountsUseAmount复制为discountsAmount
quotationDetail.discountsAmount = this.calculateDiscount(quotationDetail);
return quotationDetail;
}