山软创新实训前端开发记录
【创新实训】前端开发记录(一):基础篇
【创新实训】前端开发记录(二):主页面
【创新实训】前端开发记录(三):特殊效果
渐变标题栏
效果描述
电影详情展示页的标题栏会随着页面的向下滚动,颜色逐渐由半透明变为不透明。类似于Material Design
中CollapsingToolbarLayout
的效果。
实现思路
如下图的红色框部分的高度是设定的,为300px。我们只需要让标题栏在滚动到300px时改变它的颜色即可。红框部分的模糊背景可以使用CSS中的filter: blur
进行模糊即可。
代码实现
滚动触发器
Material-UI
提供了useScrollTrigger
函数钩子来监听页面滚动事件。我们只需要设定这个监听器的触发阈值为300px即可。
const trigger = useScrollTrigger({
disableHysteresis: true,
threshold: 300,
target: window ? window() : undefined,
});
该trigger
会返回一个布尔值,用来表示页面是否滚动超过了阈值。根据此布尔值我们调整AppBar
的class
即可。
return React.cloneElement(children, { className: trigger ? classes.appBar : classes.transAppBar });
样式部分的设定如下。为了增加渐变的效果,我们给定AppBar
的transition
为500ms。
appBar: {
width: '100%',
backgroundColor: '#3f51b5',
transition: '500ms'
},
transAppBar: {
width: '100%',
backgroundColor: 'rgba(0, 0, 0, 0.3)',
transition: '500ms'
}
主页搜索状态保存
在之前的版本中,主页搜索栏和列表翻页的状态是无法保存的,即打开了详情页后再返回主页,数据都会被重置。要解决这个问题有两种解决方案:
- 详情页在新标签页中打开
- 跳转前保存主页状态,返回时再恢复
方案1较为简单,只需在a
元素中加上target="_blank"
属性即可。但方案一带来的缺点就是,在详情页的推荐或历史记录中打开新的电影详情页,将会导致过多的标签页被打开,严重影响性能(尤其是对于一个标签页占用一个进程的浏览器来说)。
方案2较为负责,但使用体验很好,所有操作只需在一个标签页中即可完成。
实现思路
手动处理页面跳转。在跳转前先将主页的状态保存至localStorage
,再次返回主页时先检查localStorage
中是否有保存的状态,如有则取出,否则使用默认状态。
代码实现
首先是localStorage
的封装工具,提供存储和取出的操作。在执行取出操作后,将localStorage
中保存的状态删除,以免造成重进主页状态无法恢复的BUG。
export const storeState = (state, id = 'home') => {
localStorage.setItem('state_util_' + id, JSON.stringify(state))
}
export const fetchState = (id = 'home') => {
var data = localStorage.getItem('state_util_' + id) ?? '{}'
localStorage.removeItem('state_util_' + id)
return JSON.parse(data)
}
在主页面的componentDidMount()
方法中进行状态取出和恢复。
componentDidMount() {
var tmpState = fetchState()
if (Object.keys(tmpState).length > 0) {
this.setState(tmpState)
} else {
this.doSearch(this.state.searchData);
}
}
再手动处理下详情页的跳转。在列表页的代码中,取消Link的to属性,使用onClick属性调用我们自己的函数处理跳转。
const handleClick = (history, id) => {
storeState(this.state)
history.replace('/detail/' + id)
}
const pushDetail = (handleClick, history, id, home = false) => {
if (!home) {
// 非主页点击,直接跳转就行
history.replace('/detail/' + id)
} else {
handleClick(history, id)
}
}
<div
className={classes.hoverCover}
onClick={() => pushDetail(...)}>
...
</div>