# 混入
vue
mixins
官方文档 (opens new window),在阅读本文档前,请对该方法的使用有了解。
# 目录结构
└─ src
└─ mixins # 混入
├─ getInfiniteData.js # 无限滚动加载
└─ preventScroll.js # 页面禁止滚动
# getInfiniteData.js
无限滚动加载
export const getInfiniteData = {
// 初始化一些数据
data() {
return {
loading: false, // 页面接口请求loading
noData: false, // 无数据
noMoreData: false, // 无更多数据
isError: false, // 接口报错
list: [], // 接口返回 data 中的列表数据
total: 0, // 列表数据总条数
page: 1, // 当前页码
per_page: 20, // 每页返回数量
form: {}, // 查询条件
};
},
computed: {
// 是否显示加载骨架屏动画
isShowSkeleton() {
// 只有接口请求中并且当前为第一页时才显示骨架屏,否则显示页底的 <m-loadmore /> 组件
return this.loading && this.page === 1;
},
},
mounted() {
// 调用加载方法,该方法定义在 `v-infinite-scroll="loadMore"` 指令中
this.loadMore();
},
methods: {
/**
* @desc 分页获取更多数据
* @param Function fn 接口请求方法,在 api 文件夹在定义的方法
* @param Object ...args 接口请求参数,可以未多个,使用...运算符对参数进行分解
* @return 无返回结果,相关数据已挂载在当前组件的 vue 实例上
*/
async getData(fn, ...args) {
// 接口请求失败时阻止继续请求,不然滚动加载会一直触发接口请求
if (this.isError) return;
// 设置无更多数据时标志,当前为第一页且无数据时,可以再次触发请求
if (this.noMoreData && this.page === 1 && this.list.length === 0) {
this.noMoreData = false;
}
// 接口请求中或者无更多数据时,拦截请求
if (this.loading || this.noMoreData) return;
// 接口请求标志
this.loading = true;
// 请求参数
let params = {
page: this.page,
per_page: this.per_page,
...this.form
};
/**
* @desc 接口请求
* @param ...args 多个请求参数,需要与 api 接口定义一致
* @param params 请求query中携带参数
* @return code 状态码 200 为成功
* @return data 数据列表
* @return total 数据总条数
*/
const { code, data, total } = await fn(...args, params);
// 成功
if (code === 200) {
// 是否无数据,当前为第一页且返回数据为空
if (this.page === 1 && data.length === 0) {
this.noData = true;
} else {
this.noData = false;
}
this.isError = false;
// 返回成功后当前页码+1
this.page++;
// 返回的数据追加到原有列表中
this.list.push(...data);
this.total = total || 0
// 返回数据条数小于设置的每页请求条数时,则没有更多数据了
if (data.length < this.per_page) {
this.noMoreData = true;
}
} else {
// 失败时设置失败标志位为 true,阻止滚动继续发起请求
this.isError = true;
}
// 渲染完成后隐藏加载动画
this.$nextTick(() => {
this.loading = false;
});
},
},
}
# 使用示例
<!-- 页面滚动触底时加载指令 -->
<div v-infinite-scroll="loadMore">
<!-- 省略列表内容 -->
<list-item v-for="item in list">列表内容</list-item>
<!-- 加载更多组件 -->
<m-loadmore :loading="loading" v-if="!isShowSkeleton" />
</div>
// 引入混入内容
import { getInfiniteData } from "@/mixins/getInfiniteData";
//
export default {
// 注入混入内容
mixins: [getInfiniteData],
methods: {
// 页面滚动时会调用 loadMore 方法,getData 方法在上面的 mixins 里面定义了
loadMore() {
this.getData(request, ...params);
},
}
}
# preventScroll.js
解决滚动穿透
该混入是为了解决弹窗页面滚动穿透问题,所谓滚动穿透,即弹窗页面滚动时,弹窗下层的页面也会随着滚动。
如项目中影视评分、评论等弹出层页面。
解决方案是在弹窗展示时, body
元素增加 overflow: hidden
样式,弹窗隐藏时,删除 overflow: hidden
样式。
以下的 overflow-hidden
类名即为该样式的全局名称。
// 解决滚动穿透
export const preventScroll = {
mounted() {
this.$preventScroll(true);
},
beforeDestroy() {
this.$preventScroll(false);
},
}
// 给body元素添加或移除 overflow: hidden 样式
export const preventScroll = function (prevent = true) {
if (prevent) {
document.body.classList.add("overflow-hidden");
} else {
document.body.classList.remove("overflow-hidden");
}
}