#yyds干货盘点# 一步步教你用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元素的显隐
实现效果
© 版权声明
文章版权归作者所有,未经允许请勿转载。