跳转到city
页面隐藏底部tab-bar
1.方法一:配置路由参数
① 在city
路由的meta
配置一个变量
② 在app.vue
通过useRoute()
拿到当前活跃的路由对象
{
path: "/city",
component: () => import(..),
meta: {
hideTabBar: true
}
}
③ 用v-if
判断
<tab-bar v-if="!route.meta.hideTabBar" />
哪一个页面想要隐藏,就在相应的路由配置meta
2.方法二:
在commom.css
中定义一个类
{
position: relative;
z-index: 9;
height: 100vh;
background-color: #fff;
// 只在div内滚动,不要在整体页面内滚动
overflow-y: auto;
}
在组件中直接发送网络请求缺点
- 如果网络请求太多,那么页面组件中就包含大量的对于网络请求和数据的处理逻辑
- 如果页面封装了很多的子组件,子组件需要这些数据,只能通过
props
一步步传过去
①city.vue
需要使用数据,在store
中的actions
调用函数,actions
调用service
中的city.js
发送网络请求,发送完的网络请求保存到store
中的state
里面,再将state
中的数据提供给city.vue
使用
city
页面,搜索框和tab
菜单栏这个top
固定,下面内容content
滚动
方法一:fixed
固定定位
①缺点一:遮挡部分内容。在下面的content
给一个margin
②缺点二:滚动条问题(不好解决)
方法二:局部滚动
给content
一个固定的高度,再设置overflow-y: auto
// 98px是top的高度
height: cacl(100vh - 98px);
overflow-y: hidden;
设置完全局还是有滚动条,给body
设置overflow: hidden
通过tab
拿到对应content
的数据
因为tabActive
拿到的是索引,网络请求发过来的数据是对象,所以必须拿到tabs
对应的key
(key
在v-for
可以拿到),所以想办法用tabActive
绑定key
,可以绑定name
属性,tabs
的tabActive
就会拿到name
,而不是索引
cityGroups
的tabs
切换时渲染速度的问题
因为数据比较多,每次切换都要重新渲染,速度的效率有点低。
将数据传递过去,在父组件通过v-show
根据当前的key
进行切换,就不需要重新渲染了
点击城市在首页回显
1.监听城市的点击
2.将城市保存在store
中,最好保存整个对象,给一个城市名字默认值
3.回退到上一个页面
4.更改首页展示的城市
搜索跳转按钮,顺带传数据
1.在router.push
的时候可以将数据传过去
const searchBtnClick = () => {
router.push({
path: "/search",
query: {
startDate: startDate.value,
endDate: endDate.value,
currentCity: currentCity.value.cityName
}
})
}
2.在相应的页面拿到数据进行展示
const searchBtnClick = () => {
router.push({
path: '/search',
query: {
startDate: startDate.value,
endDate: endDate.value,
currentCity: currentCity.value?.cityName
}
})
}
商品列表滑动到底部加载更多数据
每页展示20
条数据
1.配置params
export function getHouseList() {
return HyRequest.get({
url: "/home/houselist",
params: {
page: 1
}
})
}
2.store
保存数据时是push
,而不是赋新的值,每次请求数据都会多加20
条数据
3.在store
管理currentPage
4.每次请求currentPage++
async fetchHouseList() {
const res = await getHouseList(this.currentPage ++ )
this.houseList.push(...res.data)
}
home
滚动到底部自动加载新的内容
区分windows
滚动还是元素内滚动
1.监听用户什么时候滚动到底部(windows
)
scrollTop + clientscroll >= scrollHeight
2.封装成hooks
3.当滚动到底部时需要进行什么操作
① 可以传入一个回调函数,但是如果要进行多个操作就要传入多个回调函数
在调用的地方
useScroll(() => {
homeStore.fetchHouselistData()
}
② 在hooks
里面定义一个变量isReachBottom
,通过return
传递出去
const { isReachBottom } = useScroll
watch(isReachBottom, (newValue) => {
// 执行相应的逻辑
})
useScroll
import { onMounted, onUnmounted, ref } from "vue"
export default function useScroll() {
const isReachBottom = ref(false)
function scrollListenerHandler() {
const scrollTop = document.documentElement.scrollTop
const clientScroll = document.documentElement.clientHeight
const scrollHeight = document.documentElement.scrollHeight
if (scrollTop + clientScroll >= scrollHeight) {
console.log("~~~ 滚动到底部了")
isReachBottom.value = true
}
}
onMounted(() => {
window.addEventListener("scroll", scrollListenerHandler)
})
onUnmounted(() => {
window.removeEventListener("scroll", scrollListenerHandler)
})
return { isReachBottom }
}
使用的地方
const { isReachBottom } = useScroll()
watch(isReachBottom, (newValue) => {
if (newValue) {
homeStore.fetchHouseList().then(() => {
isReachBottom.value = false
})
}
搜索框
需求:默认情况下是不显示的,滚动到100
再显示这个搜索框
1.可以再次复用useScroll
,把三个scroll
的值变成响应式,将这三个值return
返回出去,解构的时候也没有顺序要求
2.在用到的地方监听scrollTop
,将控制显示的变量设为true
有时间了解一下搜索框的小图标怎么做的
.end .date::after {
content: " ";
width: 0;
height: 0;
border: 4px solid #666;
border-color: rgba(0, 0, 0, 0) rgba(0, 0, 0, 0) rgba(0, 0, 0, 0) #666;
-webkit-border-radius: 3px;
border-radius: 3px;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
position: absolute;
bottom: 0px;
right: -12px;
}
优化
监听scroll
时防抖和节流的使用
防抖:类似于王者荣耀的游戏回城,一直点是没有用的,只执行最后一次。(例子不对,结论对)
节流:类似于王者荣耀的技能冷却,点了之后一段时间再次点击是无效的。
优化一:滚动到底部
优化二:监听显示搜索框
使用underscore
库
bug
:直接在url
路由跳转底部的activetabbar
不改变
const route = useRoute()
watch(route, (newRoute) => {
const index = tabBarData.findIndex(item => newRoute.path === item.path)
// 如果没拿到值,默认返回-1,防止如果进入city页面,没有匹配到
if (index === -1) return
currentIndex.value = index
})
loading
加载动画图标
1.封装成组件
2.居中、蒙版
3.控制显示和隐藏
3.1,控制显示的变量,很多地方都会用到,可以放到mainStore
中,方便使用
3.2. 当用户点击蒙版,图标隐藏
3.3.1. 法一:发送网络请求的地方很多,只要进行网络请求都会通过request
方法,开始请求前是true
,请求完是false
(这个方法不好)
3.3.2. 法二:可以使用拦截器:请求拦截器和相应拦截器
constructor(baseURL, timeout=10000) {
this.instance = axios.create({
baseURL,
timeout
})
this.instance.interceptors.request.use(config => {
mainStore.isLoading = true
return config
}, err => {
return err
})
this.instance.interceptors.response.use(res => {
mainStore.isLoading = false
return res
}, err => {
mainStore.isLoading = false
return err
})
}
商品页面跳转到详情页
1.监听item
的点击
2.跳转到详情页detail
3.携带对应的参数houseId
,用于请求数据展示数据
问题:组件上可以使用@click
吗,它会绑定到组件的根元素上
在组件上挂载的属性会传递到$attrs
上,如果只有一个根元素,默认传递到根元素。如果有多个根元素,会报警告,需要明确通过$attrs
进行使用
3.1.1 可以通过动态路由拿到商品对应的id
轮播图指示器
1.数据整理
1.1. key
做类别,value
做对象,保存数据
详情页tabs
栏
1.窗口内滚动,对usecroll
传入Ref
,对ref
进行监听滚动
2.修改usescroll
的hooks
3.写好tabControl
组件,滚动到300
再显示,emit
发送事件将index
传递出来
const emit = defineEmits(['handleItemClick'])
const currentIndex = ref(0)
const handleItemClick = (index) => {
currentIndex.value = index
emit('handleItemClick', index)
}
4.拿到每一个组件的ref
实例,可以通过函数。以便拿到它的scrollTop
const listRefs = []
const getSectionRef = (value) => {
listRefs.push(value.$el)
}
5.点击item跳到对应的位置,使用scrlooTo方法
const itemClick = (index) => {
detailRef.value.scrollTo({
top: listRefs[index].offsetTop - 44,
behavior: "smooth"
})
}
优化
1.给每个组件增加name
属性
<detail-comment name="评论" :ref="getSectionRef" :detail-comment="mainPart?.dynamicModule?.commentModule" />
<detail-order name="须知" :ref="getSectionRef" :detail-order="mainPart?.dynamicModule?.rulesModule" />
2.定义对象存储数据,类型为key
是name
,value
是组件的ref
const sectionRefs = ref({})
const getSectionRef = (value) => {
if (!value) return
const name = value.$el.getAttribute('name')
sectionRefs.value[name] = value.$el
}
3.name
改为动态的
const names = computed(() => {
return Object.keys(sectionRefs.value)
})
4.点击跳转优化,拿到key
和value
const itemClick = (index) => {
const key = Object.keys(sectionRefs.value)[index]
const el = sectionRefs.value[key]
let offset = el.offsetTop - 44
detailRef.value.scrollTo({
top: offset,
behavior: "smooth"
})
}
详情页tabControl
页面滚动匹配索引
1.监听scrollTop
的改变
2.拿到所有item
的offsetTop
,保存到数组中
3.写匹配算法
4.判断的时候加上tabControl
的高度,匹配的位置是tabControl
的底部
点击tabs
的跳动bug
处理
用一个变量isClick
记录,当点击tabs
的时候,isClick
置为true
,取消watch
里面逻辑的执行,直接return
。当点击滚动到目标位置的时候,isClick
置为false
,开始执行watch
里面的逻辑,
keep alive
<router-view v-slot="{ Component }">
<keep-alive include="home">
<component :is="Component" />
</keep-alive>
</router-view>
两个bug
home
页面改为页面内滚动
const homeRef = ref()
const { isReachBottom, scrollTop } = useScroll(homeRef)
.home {
height: 100vh;
padding-bottom: 60px;
box-sizing: border-box;
overflow-y: auto;
}
否则切换到其他页面发送的网络请求会有bug
watch(isReachBottom, (newValue) => {
if (newValue) {
homeStore.fetchHouseList().then(() => {
isReachBottom.value = false
})
}
})
跳转回home
时,保留原来的位置
onActivated(() => {
homeRef.value?.scrollTo({
top: scrollTop.value
})
})