先看一下最终效果
直接上代码
html
<div className="brand-list">
{/* 显示字母 */}
<div className="show-letter" style={{ display: this.state.showLetter }}>
{this.state.showLetter_text}
</div>
{/* 右侧导航 */}
<div className="right-nav" onTouchStart={this.fnStart.bind(this)} onTouchMove={this.fnMove.bind(this)} onTouchEnd={this.fnEnd.bind(this)} ref='right-nav'>
{this.state.navData.map((el, i) =>
<div className="item" key={i} >
{el}
</div>
)}
</div>
{/* 头部 */}
<div className="header " ref="header">
<div className="iconfont back" onClick={this.back.bind(this)}>

</div>
<div className="title">
选择品牌
</div>
</div>
{/* 内容 */}
<div className="brand-content" ref="content" onScroll={this.domScroll.bind(this)}>
{/* 猜你喜欢 */}
<div className="guess-like" ref="guess-like">
<div className="guess-like-title">
猜你喜欢
</div>
<div className="guess-like-con">
<div className="item">
<img src={car_icon1} alt="" />
<div className="text">
大众
</div>
</div>
<div className="item">
<img src={car_icon2} alt="" />
<div className="text">
沃尔沃
</div>
</div>
<div className="item">
<img src={car_icon3} alt="" />
<div className="text">
日产
</div>
</div>
<div className="item">
<img src={car_icon4} alt="" />
<div className="text">
本田
</div>
</div>
</div>
</div>
{/* 不限品牌 */}
<div className="unlimited" ref="unlimited">
<div className="title" ref="title">
⭐
</div>
<div className="unlimited-con">
不限品牌
</div>
</div>
{/* 首字母排序 */}
<div className="list" ref="list">
{this.state.data.map((el, i) =>
<div className={this.returnClass(el)} key={i}>
<div className="item-con">
<div className="car_icon">
<img src={this.returnsrc(el)} alt="" />
</div>
<div className="car_name">
{
el.mod
}
</div>
</div>
</div>
)}
</div>
</div>
</div>
css
.brand-list {
width: 750px;
background-color: #f5f5f5;
}
.brand-list .show-letter {
width: 200px;
height: 200px;
background-color: #db0303;
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
z-index: 20;
border-radius: 30px;
text-align: center;
line-height: 200px;
font-size: 100px;
color: #fff;
}
.brand-list .right-nav {
position: fixed;
right: 24px ;
top: 480px;
z-index: 20;
color: #db0303;
font-size: 18px;
text-align: center;
}
.brand-list .right-nav .item {
line-height: 30px;
}
.brand-list .header {
position: fixed;
height: 100px;
width: 100%;
background-color: #fff;
z-index: 10;
}
.brand-list .header .back {
font-size: 38px;
position: absolute;
height: 100%;
left: 30px;
line-height: 100px;
}
.brand-list .header .title {
width: 100%;
height: 100%;
text-align: center;
line-height: 100px;
font-size: 30px;
}
.brand-list .brand-content {
height: 100vh;
overflow: scroll;
box-sizing: border-box;
background-color: #f5f5f5;
padding-top: 100px;
}
.brand-list .brand-content::-webkit-scrollbar {
display: none;
}
.brand-list .brand-content .guess-like {
height: 260px;
background-color: #fff;
margin-bottom: 24px ;
margin-top: 24px;
}
.brand-list .brand-content .guess-like .guess-like-title {
height: 58px;
border-bottom: 2px solid #e9e9e9;
padding-left: 30px;
font-size: 22px;
line-height: 58px;
}
.brand-list .brand-content .guess-like .guess-like-con {
display: flex;
justify-content: space-around;
align-items: center;
padding-top: 38px;
}
.brand-list .brand-content .guess-like .guess-like-con .item {
width: 25%;
text-align: center;
}
.brand-list .brand-content .guess-like .guess-like-con .item img {
height: 65px;
}
.brand-list .brand-content .guess-like .guess-like-con .item .text {
font-size: 28px;
padding-top: 10px;
}
.brand-list .brand-content .unlimited {
height: 205px;
background-color: #fff;
margin-bottom: 24px ;
}
.brand-list .brand-content .unlimited .title {
height: 84px;
border-bottom: 2px solid #e9e9e9;
padding-left: 30px;
font-size: 22px;
line-height: 84px;
}
.brand-list .brand-content .unlimited .unlimited-con {
line-height: 122px;
font-size: 28px;
padding-left: 30px;
}
.brand-list .brand-content .list {
background-color: #fff;
}
.brand-list .brand-content .list .title {
height: 84px;
font-size: 22px;
line-height: 84px;
}
.brand-list .brand-content .list .title .item-con {
position: relative;
height: 84px;
border-bottom: 2px solid #e9e9e9;
padding-left: 30px;
background-color: #fff;
}
.brand-list .brand-content .list .title .item-con .car_icon {
display: none !important;
}
.brand-list .brand-content .list .title .item-con .car_name {
font-size: 22px;
}
.brand-list .brand-content .list .title .fixed {
position: fixed;
top: 100px;
left: 0;
right: 0;
margin: auto;
padding-left: 30px;
height: 84px;
border-bottom: 2px solid #e9e9e9;
background-color: #fff;
}
.brand-list .brand-content .list .title .fixed .car_icon {
display: none !important;
}
.brand-list .brand-content .list .title .fixed .car_name {
font-size: 22px;
}
.brand-list .brand-content .list .item {
height: 124px;
}
.brand-list .brand-content .list .item .item-con {
height: 124px;
display: flex;
align-items: center;
}
.brand-list .brand-content .list .item .item-con .car_icon {
height: 124px;
width: 154px;
text-align: center;
line-height: 124px;
overflow: hidden;
}
.brand-list .brand-content .list .item .item-con .car_icon img {
width: 75px;
height: 75px;
}
.brand-list .brand-content .list .item .item-con .car_name {
flex: 1;
height: 100%;
line-height: 124px;
font-size: 28px;
border-bottom: 2px solid #e9e9e9;
}
js逻辑代码
class BrandList extends Component {
constructor(...args) {
super(...args)
this.Init()
}
// 初始化
Init() {
this.brandList = []//存放数据
this.tops = []//存放内容标题距离顶部的距离
this.childs = []//存放标题元素
this.rightTops = []//存放右边导航的位置
this.navData = ['猜', '⭐']//右边导航数据
this.state = {
data: [],
navData: [],
showLetter: 'none',//控制提示文字
showLetter_text: 'A'//控制显示文字
}
}
// 获取数据
async getData() {
this.brandList = await getBrand({ phone: 1 })
}
// 返回图片
returnsrc(item) {
if (item.mod.length === 1) {
return '#'
}
if (item.state) {
return `http://www.ibugthree.com/${item.icon_src}`;
} else {
return `http://www.ibugthree.com/default.gif`;
}
}
// 判断类名
returnClass(item) {
// console.log(item.mod.length);
if (item.mod.length === 1) {
return 'title'
} else {
return 'item'
}
}
// 滚动时
domScroll(e) {
this.scrollTop = e.target.scrollTop
for (let i = 0; i < this.brandList.length; i++) {
if(this.child[i].offsetTop-this.scrollTop<this.viewHeight){
this.brandList[i].state=true;
}
}
this.setState({
data: this.brandList,
})
for (let i = 0; i < this.tops.length; i++) {
if (this.scrollTop > this.tops[i] && this.scrollTop < this.tops[i + 1]) {
this.childs[i].children[0].className = 'fixed'
} else {
this.childs[i].children[0].className = 'item-con'
}
}
}
// 点击导航
fnStart(e) {
this.y = e.touches[0].pageY - this.refs['right-nav'].offsetTop;
for (let i = 0; i < this.rightTops.length; i++) {
if (this.y >= this.rightTops[i] && this.y < this.rightTops[i + 1]) {
this.refs.content.scrollTop = this.tops[i - 1] - this.refs['guess-like'].offsetHeight - this.refs.unlimited.offsetHeight
this.setState({
showLetter: 'block',
showLetter_text: this.navData[i]
})
}
if (this.y >= this.rightTops[i] && this.rightTops[i + 1] === undefined) {
this.refs.content.scrollTop = this.refs.content.scrollHeight
this.setState({
showLetter: 'block',
showLetter_text: this.navData[i]
})
}
}
}
fnMove(e) {
this.y = e.touches[0].pageY - this.refs['right-nav'].offsetTop
for (let i = 0; i < this.rightTops.length; i++) {
if (this.y >= this.rightTops[i] && this.y < this.rightTops[i + 1]) {
this.refs.content.scrollTop = this.tops[i - 1] - this.refs['guess-like'].offsetHeight - this.refs.unlimited.offsetHeight
this.setState({
showLetter: 'block',
showLetter_text: this.navData[i]
})
}
if (this.y >= this.rightTops[i] && this.rightTops[i + 1] === undefined) {
this.refs.content.scrollTop = this.refs.content.scrollHeight;
this.setState({
showLetter: 'block',
showLetter_text: this.navData[i]
})
}
}
}
fnEnd() {
this.setState({
showLetter: 'none'
})
}
// 延迟加载图片
lazyLoad() {
this.viewHeight = document.documentElement.clientHeight;
for (let i = 0; i < this.brandList.length; i++) {
let top = this.child[i].offsetTop
this.brandList[i].top = top;
if (top > this.viewHeight) {
this.brandList[i].state = false;
} else {
this.brandList[i].state = true;
}
}
this.setState({
data: this.brandList,
})
}
// 返回主页
back(){
Control.go(-1)
}
async componentDidMount() {
await this.getData()
this.setState({
data: this.brandList,
})
// 得到 A-Z 的标题
for (let i = 0; i < this.brandList.length; i++) {
if (this.brandList[i].mod.length === 1) {
this.navData.push(this.brandList[i].mod)
}
}
this.setState({
navData: this.navData
})
// 获取距离顶部的距离
this.child = this.refs.list.children;
for (let i = 0; i < this.child.length; i++) {
if (this.child[i].className === 'title') {
this.tops.push(this.child[i].getBoundingClientRect().y - this.refs.header.offsetHeight)
this.childs.push(this.child[i])
}
}
// 获取右边导航的位置
this.right_nav_child = this.refs['right-nav'].children;
for (let i = 0; i < this.right_nav_child.length; i++) {
this.rightTops.push(this.right_nav_child[i].offsetTop)
}
// 延迟加载车辆图片
this.lazyLoad()
}
具体的实现逻辑思路后续会补上,先把代码存到这里