Search - 搜索框无论在B端还是C端都会存在的东西。无疑把其抽离封装成则最为合适。
能确保组件的易读性/可扩展性/最佳使用性
,一直是我不断编码过程中思考的问题。
此文章以 Taro + Ts + Redux 为技术栈作为分享。
直接步入正题:
先看三张张搜索框的UI设计稿。
图一:【刚进入搜索页面中,输入框的样式】
图二:【搜索框输入内容时,有输入框清除按钮的增加】
图三:【搜索完成之后,数据展示】
思考一下你将会如何布局 -- 不知你们的代码是否和我最开始的一样/或者类似。
组件分为search-left / search-right(btn)
search-left 分为 image / input / image(clear)
{
showdelImg && (
)
}
搜索
优化一:Input的属性排序过于混乱,我们先来调整一下。可以规定,所有都是先以 className
为先,其次是一些带 string
属性,接下来是 value
值。最后可以放事件函数。
优化二: 清楚的 X 的按钮,则用了 showdelImg
这个变量进行展示。我们试想一下,缺点在哪里。
第一:组件多传一个变量。
第二:在引用组件的页面中要根据不同状态进行改变(看如下事件 onFocus
/ onSearch
),最后传入 Search 组件进行展示与否的渲染。
第三:判断太多,对于后期维护不友好,并且如果嵌套太深,容易地狱。
// Page 页面引用的地方,此出引用的属性最好与组件的顺序一直,这样方便知道少了什么传值。
this.onSearch(e)}
onReset={this.onReset}
onFocus={this.onFocus}
onSearchList={this.onSearchList}
searchVal={searchVal}
showdelImg={showdelImg}
foucus={foucus}
/>
// input 获取焦点
onFocus = () => {
const { searchVal } = this.state;
if (searchVal) {
this.setState({ showdelImg: true });
}
}
// 获取搜索的内容
onSearch = (e) => {
const val = e.detail.value;
this.setState({
searchVal: val,
showdelImg: true,
});
};
我们第二步 Search 组件中的 Image(clear)属性优化一下写法。
思路:将 showdelImg 变量,该为组件内部去实现,通过加入内部
// 在 render中用法
const clearImgStyle = { display: 'flex' };
if (!searchVal.length) {
clearImgStyle.display = 'none';
}
// clear 处的优化写法
优化三:思考一下,我们目前的代码,布局则就是左边是搜索的input框,右边是搜索的Button按钮。但是,这时候让你改成只有一条搜索框,右边的Button没有,。功能不变,样式变化,这样显得很尴尬。是重新写一个还是怎样别的实现方式?
我第一想到的是,传入一个变量,这无疑是一种的方式。
// 在render中,引入showActionButton变量
const { showActionButton } = this.props;
const actionStyle: { opacity?: number, marginRight?: string } = {};
if(showActionButton) {
actionStyle.opacity = 1;
actionStyle.marginRight = `0`;
}
// 在搜索Button多加入一个style
搜索
如上基本上是从html角度去优化,其还可以优化的点分为,Input 的默认值 placeholder 可以分出去。原因是,最开始默认值的样式与输入值的样式可能不一样,目前先不展开说明。
优化四:写好CSS,先从组件的className着手,网上已经有很多命名规范等,这里不过多呈现。从最开始的代码看出来,基本上命名都是以 search-left-input
。可以优化为: search-left__input
一会儿在CSS代码中,大家就能体现这样的优势了。
先附上一份,最原始的CSS代码,与本文最开始的TSX代码进行结合。
.search {
display: flex;
padding: 10rpx 40rpx 20rpx 30rpx;
background-color: #fff;
position: fixed;
z-index: 1;
&-left {
width: 576rpx;
height: 80rpx;
background: #f2f2f2;
border-radius: 40rpx;
display: flex;
margin-right: 30rpx;
&-img {
width: 40rpx;
height: 40rpx;
padding: 20rpx 4rpx 20rpx 40rpx;
}
&-input {
padding: 19rpx;
width: 356rpx;
height: 42rpx;
font-size: 30rpx;
color: #111111;
}
&-clear {
width: 36rpx;
height: 36rpx;
padding: 22rpx 0 22rpx 35rpx;
}
}
&-btn {
width: 64rpx;
height: 80rpx;
line-height: 80rpx;
font-size: 32rpx;
color: #111111;
}
}
其实整体看上去是没什么毛病,样式功能也都能实现,通过变量赋予不同的类名,在做样式的调整的思维。但是,可以更好,此处分享一篇文章。
https://github.com/cssmagic/CSS-Secrets/issues/8
如果要改一个 Button 的样式,则需要修改长宽高,border,背景色,垂直水平居中等属性。只是一个简简单单的 Button 可还好,但是更多的是若一个页面的布局写得不好,在往里面挪地儿,那可能就很难了。
最后附上一份源码:
思路一:default.scss 主要是维护整个小程序主题的颜色边距等(如下有)
思路二:将一些字体大小,提取出来做变量
思路三:共用的一些 mixins 可以提取出来。多在项目中沉淀。
@import '../variables/default.scss';
@import '../mixins/index.scss';
$at-search-bar-font-size: 14PX;
$at-search-bar-input-height: 30PX;
$at-search-bar-input-padding: 25PX;
$at-search-bar-btn-padding: 10PX;
$at-search-bar-placeholder-padding: 12PX;
$at-search-bar-input-bg-color: $color-bg-grey;
$at-search-bar-input-color: $color-black-0;
$at-search-bar-placholder-color: $color-grey-2;
.at-search-bar {
display: flex;
align-items: center;
padding: $spacing-v-sm $spacing-v-md;
background-color: $color-bg;
overflow: hidden;
box-sizing: border-box;
@include hairline-bottom();
/* elements */
&__input-cnt {
position: relative;
flex: 1;
width: 100%;
height: $at-search-bar-input-height;
background-color: $at-search-bar-input-bg-color;
border-radius: $at-search-bar-input-height / 2;
overflow: hidden;
display: flex;
}
&__input {
position: absolute;
display: block;
top: 0;
left: 0;
width: 100%;
height: $at-search-bar-input-height !important;
padding: $at-search-bar-placeholder-padding $at-search-bar-input-padding + $at-search-bar-placeholder-padding;
color: $at-search-bar-input-color;
font-size: $at-search-bar-font-size !important;
text-align: left;
background-color: transparent;
transition: width 0.3s;
box-sizing: border-box;
}
&__clear {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
top: 0;
right: $at-search-bar-placeholder-padding;
height: $at-search-bar-input-height;
width: $at-search-bar-input-padding;
color: $at-search-bar-placholder-color;
font-size: $at-search-bar-font-size;
line-height: 0;
vertical-align: middle;
}
&__action {
flex: none;
display: block;
margin-left: 10PX;
padding: 0 $at-search-bar-btn-padding;
height: $at-search-bar-input-height;
color: $at-search-bar-btn-color;
font-size: $at-search-bar-font-size;
line-height: $at-search-bar-input-height;
border-radius: 4PX;
background-color: $at-search-bar-btn-bg-color;
transition: margin-right 0.3s, opacity 0.3s;
opacity: 0;
}
/* modifiers */
&--fixed {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: $zindex-search-bar;
}
}
defult.scss 中的代码
$hd: 2 !default; // 基本单位
/* 垂直间距 */
$spacing-v-xs: 5px * $hd !default;
$spacing-v-sm: 10px * $hd !default;
$spacing-v-md: 20px * $hd !default;
$spacing-v-lg: 30px * $hd !default;
$spacing-v-xl: 40px * $hd !default;
/* 背景色 */
$color-bg: #FFF !default;
$color-bg-base: #FAFBFC !default;
$color-bg-light: #ECF5FD !default;
$color-bg-lighter: tint($color-bg-light, 50%) !default;
$color-bg-grey: #F7F7F7 !default;
mixins 中的代码
@mixin hairline-bottom(
$color: $color-border-light,
$style: solid,
$width: 1PX
) {
position: relative;
&::after {
@include hairline-base($color, $style);
border-bottom-width: $width;
}
}
总结:虽然样式是整个项目中最简单的地方,但是,也绝对是耗时多,重复率最高的地方。如果后期可以思考如何将更优雅的写出样式,将代码可读性,更好的达到复用性。沉淀出一些常用的组件,一些常用的 mixins 以及 flex 布局相关的东西。