一步步教你用taro封装一个公司库的下拉组件

目录

前言

前言

需求介绍

核心代码部分

样式部分

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

总结1

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

总结2

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

总结3

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

总结4

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

总结5

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

总结6

实现效果


前言

我是歌谣 我有个兄弟 巅峰的时候排名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元素的显隐

实现效果

猜你喜欢

转载自blog.csdn.net/geyaoisnice/article/details/123681919