如何更优雅的封装组件 - Search

Search - 搜索框无论在B端还是C端都会存在的东西。无疑把其抽离封装成则最为合适。
能确保组件的易读性/可扩展性/最佳使用性,一直是我不断编码过程中思考的问题。
此文章以 Taro + Ts + Redux 为技术栈作为分享。

直接步入正题:
先看三张张搜索框的UI设计稿。
图一:【刚进入搜索页面中,输入框的样式】
图二:【搜索框输入内容时,有输入框清除按钮的增加】
图三:【搜索完成之后,数据展示】


image.png
image.png
image.png

思考一下你将会如何布局 -- 不知你们的代码是否和我最开始的一样/或者类似。
组件分为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没有,。功能不变,样式变化,这样显得很尴尬。是重新写一个还是怎样别的实现方式?
我第一想到的是,传入一个变量,这无疑是一种的方式。


image.png
image.png
// 在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 布局相关的东西。

你可能感兴趣的:(如何更优雅的封装组件 - Search)