【React工作记录八十】 一步步教你用taro封装一个公司库的下拉组件

简介: 【React工作记录八十】 一步步教你用taro封装一个公司库的下拉组件

前言


我是歌谣 我有个兄弟 巅峰的时候排名c站总榜19 叫前端小歌谣 曾经我花了三年的时间创作了他 现在我要用五年的时间超越他 今天又是接近兄弟的一天人生难免坎坷 大不了从头再来 歌谣的意志是永恒的 放弃很容易 但是坚持一定很酷


前言


歌谣 歌谣 如何封装一个公司库的一个组件


需求介绍


首先要实现的是

1第一步 需要在一个input框中输入字符 当字符发生变化的时候进行接口的调用

2超过两个字符开始渲染页面

3将页面的值返回出去


核心代码部分


import Taro, { Component } from "@tarojs/taro";
import { View, Text, Input, Form, ScrollView } from "@tarojs/components";
import { AtList, AtListItem, AtAccordion } from "taro-ui";
import { searchCompanyLibrary } from "@/services/user";
import "./index.scss";
/********
 * @param placeholder String 默认请输入
 * @param title String 输入框名字【required】
 * @param clear Boolean 是否显示清楚按钮
 * @param searchCompanyLibrary Function 获取列表数据 [required] 接口请求
 *  @param searchCompanyLibraryList 回调传值 第一个参数为外层需要的文本值 
第二个参数为控制外面元素是不是存在的值
 *  @param companyName 用于编辑回显使用 外层传入
 *  @param  ScrollView 滚动取值
 * ****************** */
class FuzzyQuery extends Component {
  state = {
    applicantName: this.props.companyName || "",
    popLeft: 0,
    popWidth: 0,
    open: false,
    dataSource: [1, 2, 3],
    popTop: 0,
    selectItem: {},
    isSelectCompany: false,
    pageIndex: 1,
    pageSize: 10
  };
  componentDidMount() {
    this.props.onRef && this.props.onRef(this);
    setTimeout(() => {
      this.handleGetDom();
    }, 100);
    // this.handleGetDom();
  }
  handleGetDom = () => {
    let _this = this;
    Taro.createSelectorQuery()
      .select(".fuzzy-query .weui-input")
      .boundingClientRect(function(rect) {
        // rect.id; // 节点的ID
        // rect.dataset; // 节点的dataset
        // rect.left; // 节点的左边界坐标
        // rect.right; // 节点的右边界坐标
        // rect.top; // 节点的上边界坐标
        // rect.bottom; // 节点的下边界坐标
        // rect.width; // 节点的宽度
        // rect.height; // 节点的高度
        _this.setState({
          popLeft: rect.left,
          popWidth: rect.width,
          popTop: rect.height
        });
      })
      .exec();
  };
  //选中某一项时触发
  handleClick = (e, item) => {
    console.log(e, "e");
    e.stopPropagation();
    e.preventDefault();
    this.setState(
      {
        open: false,
        applicantName: item.name,
        selectItem: item
      },
      () => {
        const { open } = this.state;
        this.props.searchCompanyLibraryList &&
          this.props.searchCompanyLibraryList(item.name, open);
      }
    );
  };
  //当输入框发生变化时
  handleChange = async keyWord => {
    var company = keyWord.detail.value;
    //先编码
    var value = encodeURI(keyWord.detail.value);
    console.log(value, "value");
    //如果少于2个字符,是不调用接口的,此时不显示公司公司列表弹窗,且将数据清空
    if (company.length < 2) {
      this.setState(
        {
          applicantName: company,
          open: false,
          dataSource: [],
          pageIndex: 1
        },
        () => {
          const { open } = this.state;
          this.props.searchCompanyLibraryList &&
            this.props.searchCompanyLibraryList(company, open);
        }
      );
      Taro.showToast({
        title: "请输入不少于两个字符",
        icon: "none",
        mask: true
      });
    } else {
      const { pageIndex, pageSize, dataSource, open } = this.state;
      let params = { keyWord: decodeURI(value), pageSize, pageIndex };
      const data = await searchCompanyLibrary(params);
      this.setState(
        {
          open: true,
          applicantName: company,
          dataSource: data.data.data,
          pageIndex: 1
        },
        () => {
          const { open } = this.state;
          this.props.searchCompanyLibraryList &&
            this.props.searchCompanyLibraryList(company, open);
        }
      );
    }
  };
  //触底函数
  onScrollToUpper = async () => {
    console.log("我在触底");
    const { pageIndex, pageSize, dataSource, applicantName } = this.state;
    let applicantNameList = encodeURI(applicantName);
    let params = {
      keyWord: decodeURI(applicantNameList),
      pageSize,
      pageIndex: pageIndex + 1
    };
    const data = await searchCompanyLibrary(params);
    console.log(dataSource, "dataSource");
    console.log(data.data.data, "data");
    this.setState({
      // open: true,
      // applicantName: applicantName,
      dataSource: [...dataSource, ...data.data.data],
      pageIndex: pageIndex + 1
    });
  };
  render() {
    const {
      applicantName,
      popLeft,
      popWidth,
      open,
      popTop,
      dataSource
    } = this.state;
    console.log(dataSource, "dataSource");
    const scrollStyle = {
      zIndex: 100,
      height: "250px"
    };
    const { placeholder = "请输入", title = "", clear = false } = this.props;
    return (
      <View
        className="position-relative fuzzy-query"
        id="fuzzy-query"
        onRef={node => (this.fuzzyWrap = node)}
      >
        <Form>
          <View className=" input-wrap">
            <View className="flex-between input-item">
              <Text className="input_title">{title}</Text>
              <View
                className={
                  clear && applicantName
                    ? "search-input-show-clear"
                    : "search-input-wrap"
                }
              >
                <Input
                  placeholderStyle="color:#f8f8f8"
                  className="search-input"
                  value={applicantName}
                  onChange={this.handleChange}
                  placeholder={placeholder}
                ></Input>
              </View>
              {clear && applicantName && (
                <div
                  className="at-input__icon "
                  onClick={() =>
                    this.setState({
                      applicantName: "",
                      dataSource: [],
                      open: false
                    })
                  }
                >
                  <span className="taro-text at-icon 
at-icon-close-circle at-input__icon-close"></span>
                </div>
              )}
            </View>
          </View>
        </Form>
        <View
          style={{ top: `${popTop * 2}px` }}
          className={
            open
              ? "show-fuzzy-pop position-absolute fuzzy-query-pop"
              : "position-absolute fuzzy-query-pop"
          }
        >
          <ScrollView
            scrollY
            style={scrollStyle}
            scrollWithAnimation
            onScrollToLower={this.onScrollToUpper} 
// 使用箭头函数的时候 可以这样写 `onScrollToUpper={this.onScrollToUpper}`
          >
            <View
              style={{
                paddingLeft: `${popLeft - 12}px`,
                width: `${popWidth}px`
              }}
            >
              <AtList>
                {dataSource.length > 0 &&
                  dataSource.map(item => {
                    return (
                      <AtListItem
                        title={item.name}
                        onClick={e => this.handleClick(e, item, "selectItem")}
                      />
                    );
                  })}
              </AtList>
            </View>
          </ScrollView>
        </View>
      </View>
    );
  }
}
export default FuzzyQuery;


样式部分


.fuzzy-query{
  .at-list::after{border-top:0;}
  .fuzzy-query-pop{
    // border: 1px solid #e8e8e8;
    box-sizing: border-box;
    z-index:100;
    width: 100%;
    background: #fff;
    // opacity: 0;
    max-height:0;
    overflow: hidden;
    transition:max-height 0.5s ;
    .at-list__item{
      padding:20px;
      font-size: 28px;
    }
    .at-list__item::after{left:0;}
  }
  .show-fuzzy-pop{
    max-height:800px;
    z-index: 100;
    // overflow-y: scroll;
  }
  .input-wrap{
margin-left: 32px;
color:#333;
font-size: 28px;
.input-item{
  position: relative;
  padding:24px 0 ;
  &::after{
  content: '';
  position: absolute;
  -webkit-transform-origin: center;
  -ms-transform-origin: center;
  transform-origin: center;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  pointer-events: none;
  top: -50%;
  left: -50%;
  right: -50%;
  bottom: -50%;
  border: 0 solid #d6e4ef;
  -webkit-transform: scale(0.5);
  -ms-transform: scale(0.5);
  transform: scale(0.5);
  border-bottom-width: 1PX;
}}
    .input_title{
      width:172px;
      margin-right: 16px;
    }
    .search-input-wrap{width:calc(100% - 172px);position: relative;
    .fuzzy-clear{position: absolute;right:0;width:32px;height:32px}}
    .search-input-show-clear{width:480.12px;position: relative;
    .fuzzy-clear{position: absolute;right:0;width:32px;height:32px}}
input::-webkit-input-placeholder {
  color: rgb(204,204,204);
}
input::-moz-placeholder {
  /* Mozilla Firefox 19+ */
  color: rgb(204,204,204);
}
input:-moz-placeholder {
  /* Mozilla Firefox 4 to 18 */
  color: rgb(204,204,204);
}
input:-ms-input-placeholder {
  /* Internet Explorer 10-11 */
  color: rgb(204,204,204);
}
  }
}


实现思路介绍(接口调用在子组件执行还是父组件)


const { pageIndex, pageSize, dataSource, open } = this.state;
      let params = { keyWord: decodeURI(value), pageSize, pageIndex };
      const data = await searchCompanyLibrary(params);

总结1


子组件中进行接口的调用并进行页面的渲染


实现思路介绍(get请求传入中文页面获取不到参数)


let applicantNameList = encodeURI(applicantName);
    let params = {
      keyWord: decodeURI(applicantNameList),
      pageSize,
      pageIndex: pageIndex + 1
    };


总结2


先用encodeURI编码再用decodeURI解码


实现思路介绍(如何改变下拉的分页)


//触底函数
  onScrollToUpper = async () => {
    console.log("我在触底");
    const { pageIndex, pageSize, dataSource, applicantName } = this.state;
    let applicantNameList = encodeURI(applicantName);
    let params = {
      keyWord: decodeURI(applicantNameList),
      pageSize,
      pageIndex: pageIndex + 1
    };
    const data = await searchCompanyLibrary(params);
    console.log(dataSource, "dataSource");
    console.log(data.data.data, "data");
    this.setState({
      // open: true,
      // applicantName: applicantName,
      dataSource: [...dataSource, ...data.data.data],
      pageIndex: pageIndex + 1
    });
  };


总结3


ScrollView包裹 设置出现滚动条的高度 触底执行 并对数据用扩展运算符拼接


实现思路介绍(如何控制下拉选择的值渲染到input上)


{dataSource.length > 0 &&
                  dataSource.map(item => {
                    return (
                      <AtListItem
                        title={item.name}
                        onClick={e => this.handleClick(e, item,
 "selectItem")}
                      />
                    );
                  })}


总结4


事件多绑定一个参数进行赋值 点击触发 完成赋值


实现思路介绍(如何把子组件获取的值给到父组件)


this.props.searchCompanyLibraryList &&
            this.props.searchCompanyLibraryList(company, open);

总结5


简单的子组件向着父组件传值


实现思路介绍(如何控制事件的冒泡)  


this.props.searchCompanyLibraryList &&
            this.props.searchCompanyLibraryList(company, open);

总结6


open去控制外层dom元素的显隐


实现效果

图片.png

相关文章
|
5天前
|
前端开发 JavaScript 测试技术
React 分页组件 Pagination
本文介绍了如何在 React 中从零构建分页组件,涵盖基础概念、常见问题及解决方案。通过示例代码详细讲解了分页按钮的创建、分页按钮过多、初始加载慢、状态管理混乱等常见问题的解决方法,以及如何避免边界条件、性能优化和用户反馈等方面的易错点。旨在帮助开发者更好地理解和掌握 React 分页组件的开发技巧,提升应用的性能和用户体验。
24 0
|
1月前
|
前端开发 开发者
React 函数组件与类组件对比
【10月更文挑战第4天】本文详细比较了React中的函数组件与类组件。函数组件是一种简单的组件形式,以纯函数的形式返回JSX,易于理解与维护,适用于简单的UI逻辑。类组件则是基于ES6类实现的,需要重写`render`方法并能利用更多生命周期方法进行状态管理。文章通过示例代码展示了两者在状态管理与生命周期管理上的差异,并讨论了常见的问题如状态更新异步性与生命周期管理的复杂性,最后给出了相应的解决方法。通过学习,开发者可以根据具体需求选择合适的组件类型。
55 8
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
162 2
|
2月前
|
前端开发 JavaScript 网络架构
react对antd中Select组件二次封装
本文介绍了如何在React中对Ant Design(antd)的Select组件进行二次封装,包括创建MSelect组件、定义默认属性、渲染Select组件,并展示了如何使用Less进行样式定义和如何在项目中使用封装后的Select组件。
89 2
react对antd中Select组件二次封装
|
9天前
|
移动开发 前端开发 API
React 拖拽组件 Drag & Drop
本文介绍了在 React 中实现拖拽功能的方法,包括使用原生 HTML5 Drag and Drop API 和第三方库 `react-dnd`。通过代码示例详细讲解了基本的拖拽实现、常见问题及易错点,帮助开发者更好地理解和应用拖拽功能。
31 9
|
4天前
|
前端开发 UED 开发者
React 分页组件 Pagination
本文介绍了如何在 React 中实现分页组件,从基础概念到常见问题及解决方案。分页组件用于将大量数据分成多个页面,提升用户体验。文章详细讲解了分页组件的基本结构、快速入门步骤、以及如何处理页面跳转不平滑、页码过多导致布局混乱、边界条件处理和数据加载延迟等问题。通过本文,读者可以全面了解并掌握 React 分页组件的开发技巧。
8 2
|
8天前
|
设计模式 前端开发 编译器
与普通组件相比,React 泛型组件有哪些优势?
与普通组件相比,React 泛型组件有哪些优势?
22 6
|
16天前
|
前端开发 JavaScript 安全
学习如何为 React 组件编写测试:
学习如何为 React 组件编写测试:
33 2
|
23天前
|
前端开发 JavaScript 测试技术
React 高阶组件 (HOC) 应用
【10月更文挑战第16天】高阶组件(HOC)是 React 中一种复用组件逻辑的方式,通过接受一个组件并返回新组件来实现。本文介绍了 HOC 的基础概念、核心功能和常见问题,包括静态方法丢失、ref 丢失、多个 HOC 组合和 props 冲突的解决方案,并提供了具体的 React 代码示例。通过本文,读者可以更好地理解和应用 HOC,提高代码的复用性和可维护性。
52 8
|
22天前
|
缓存 前端开发 JavaScript
前端serverless探索之组件单独部署时,利用rxjs实现业务状态与vue-react-angular等框架的响应式状态映射
本文深入探讨了如何将RxJS与Vue、React、Angular三大前端框架进行集成,通过抽象出辅助方法`useRx`和`pushPipe`,实现跨框架的状态管理。具体介绍了各框架的响应式机制,展示了如何将RxJS的Observable对象转化为框架的响应式数据,并通过示例代码演示了使用方法。此外,还讨论了全局状态源与WebComponent的部署优化,以及一些实践中的改进点。这些方法不仅简化了异步编程,还提升了代码的可读性和可维护性。