一步步教你用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 (
{clear && applicantName && (
<span className="taro-text at-icon
at-icon-close-circle at-input__icon-close">
<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}
>
${popWidth}px
}} >
{dataSource.length > 0 && dataSource.map(item => { return (
); })}
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-listitem{ padding:20px; font-size: 28px; } .at-listitem::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元素的显隐
实现效果
编辑
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南