Vue3 重构函数透传示例解析
导读:收集整理的这篇文章主要介绍了Vue3 重构函数透传示例解析,觉得挺不错的,现在分享给大家,也给大家做个参考。 目录一、来源列表页面+下拉刷新和上拉加载+占位图(无数据+断网)...二、使...
收集整理的这篇文章主要介绍了Vue3 重构函数透传示例解析,觉得挺不错的,现在分享给大家,也给大家做个参考。 目录
- 一、来源
- 列表页面+下拉刷新和上拉加载+占位图(无数据+断网)...
- 二、使用示例
- 最后、总结
一、来源
之前做 vue 手机端需求开发时,遇到多个相似列表页面:
列表页面+下拉刷新和上拉加载+占位图(无数据+断网)...
就想能不能复用同一个页面,传入不同的数据和单元格即可;经过一个多月的思考(查询js 的特性 + Vue3官方文档),最终在官方文档:
找到解决办法: 属性透传方法
原理如下:
二、使用示例
1、VRefreshListDemo.vue
template>
navbar class="navbar" isleftarrow navBarTITle="数据透传" closeWebview isFixed />
VRefreshList :requestfc="requestFC" :requestErrorFC="requestErrorFC" :requestParamsChange="tag" :pageindexInitial="pageIndexInitial" >
template v-slot="slotPRops">
messageInteractiveCell class="page-view__cell" v-for="(e, index) in slotProps.list" :key="index" :imgUrl="deliverDataObj(e)?.activityUserIcon" :imgUrlRight="getResizedAliOSSImageUrl(e, 64)" :text="formatContentTitle(e)" :detailText="formatContentDetails(e)" :tag="formatDateNoYear(e.pushTime)" @click="clickCell(e)" >
/MessageInteractiveCell>
/template>
/VRefreshList>
/template>
script SETUP>
import navbar From '@/@R_512_480@s/navbar.vue';
import VRefreshList from './VRefreshList.vue';
import MessageInteractiveCell from '@/views/message/components/MessageInteractiveCell.vue';
import {
getcurrentInstance, ref, reactive, computed, watch, onmounted, onActivated}
from 'vue';
import {
onBeforeRouteLeave }
from 'vue-router';
import {
Toast }
from 'vant';
import {
useStore }
from 'vuex';
import {
DropdownMenu, DropdownItem }
from 'vant';
import {
NET_MSG_ERROR }
from '@/service/request/apiMessage';
import {
hasNet, goToPage, goToPageForResult }
from '@/utils/uplusApi';
import * as RQ from '@/service/request/request.js';
import * as MessageContant from '@/views/message/MessageContant.js';
import {
formatDateWithYear, formatDateNoYear, jumpURL, getResizedAliOSSImageUrl, deliverDataObj,}
from '@/views/message/MessageCommonUtil';
import icon_interactive from '@/assets/images/icon_interactive_base64';
import icon_like from '@/assets/images/icon_like_base64';
import icon_evaluation from '@/assets/images/icon_evaluation_base64';
const store = useStore();
const currentInstance = getCurrentInstance();
const {
$platform, $vtoast, $debounce, $gio}
= currentInstance.appContext.config.globalProPErties;
onBeforeRouteLeave(() =>
{
$vtoast.clear();
}
);
// 初始创建页面刚进来加载一次onMounted(() =>
{
// console.LOG('MessageList ->
onMounted');
// $vtoast.loading({
}
);
// onRefresh();
}
);
onActivated(() =>
{
console.log('ContentList.vue ->
onActivated');
// $vtoast.loading({
}
);
// onMore();
}
);
const businessType = ref(store.getters.msgType || '0');
const pageIndexInitial = ref(1);
/// 获取历史消息async function requestFC(options) {
const {
isRefresh, page, pageSize, lastObj}
= options;
console.log(`VRefreshListDemo requestFC:${
JSON.stringify(isRefresh)}
,${
page}
`);
const timestamp = Date.now();
let msgTime = formatDateWithYear(timestamp);
if (!isRefresh &
&
lastObj) {
msgTime = lastObj.pushTime;
}
const params = {
msgTime: msgTime, queryTag: 1, querySize: pageSize, businessType: businessType.value, }
;
if (['20'].includes(businessType.value) &
&
store.getters.msgBelong &
&
store.getters.msgBelongType) {
params.belong = store.getters.msgBelong;
params.belongType = store.getters.msgBelongType;
}
const items = await RQ.getMsgHistory(params);
return items;
}
async function requestErrorFC(error) {
Toast(JSON.stringify(error));
}
const clickCell = (obj) =>
{
if (!hasNet.value) {
Toast(NET_MSG_ERROR);
return;
}
const url = formatContentreviewPage(obj);
jumpURL(url);
}
;
function formatContentTitle(e) {
const activityUserObj = deliverDataObj(e);
// const result = decodeURIComponent(activityUserObj?.activityUserNickName ?? '');
const result = decodeURIComponent(e.message.data.body.view?.title ?? '-');
return result;
}
function formatContentDetails(e) {
const result = decodeURIComponent(e.message.data.body.view?.title ?? '-');
return result;
}
function formatContentReviewPage(e) {
const result = e.message.data.body.extData?.reviewPage;
return result;
}
/script>
style scoped lang='scss'>
.page-view{
position: relative;
margin-top: 46px;
height: calc(100vh - 46px);
overflow: scroll;
}
.navbar{
height: 46px;
}
:deep .van-pull-refresh{
top: 46px;
}
/style>
2、VRefreshList.vue 源码
VRefreshCustom 是“上拉刷新和下拉加载+占位图”的封装
template>
VRefreshCustom v-model:refreshing="refreshing" v-model:loading="loading" :onRefresh="onRefresh" :loadMore="onMore" :finished="finished" :loadingText="loadingText" :finishedText="finishedText" :netstatus="netStatus" :clickVNet="clickVNet" :isSuccess="isSuccess" >
slot :list="list">
/slot>
/VRefreshCustom>
/template>
script setup>
import VRefreshCustom from './VRefreshCustomNew.vue';
import {
getCurrentInstance, ref, reactive, computed, watch, onMounted, onActivated}
from 'vue';
import {
onBeforeRouteLeave }
from 'vue-router';
import {
Toast }
from 'vant';
import {
NET_MSG_ERROR }
from '@/service/request/apiMessage';
import {
hasNet, goToPage, goToPageForResult }
from '@/utils/uplusApi';
const currentInstance = getCurrentInstance();
const {
$platform, $vtoast, }
= currentInstance.appContext.config.globalProperties;
onBeforeRouteLeave(() =>
{
$vtoast.clear();
console.log('离开 MessageInteractivePage.vue');
}
);
const props = defineProps({
requestFC: {
type: Function, required: true, description: '接口请求方法', }
, requestErrorFC: {
type: Function, description: '接口请求错误回调方法', }
, pageIndexInitial: {
type: Number, default: 1, }
, pageSize: {
type: Number, default: 30, }
, requestParamsChange: {
type: String, }
, loadingText: {
type: String, default: '', }
, finishedText: {
type: String, default: '', }
,}
);
const pageIndex = ref(props.pageIndexInitial);
const refreshing = ref(false);
const isSuccess = ref(false);
const loading = ref(false);
const finished = ref(false);
/// -1 请求失败;
0无数据;
1 正常列表,有数据;
const netStatus = ref(1);
const list = reactive([]);
const clickVNet = () =>
{
$vtoast.loading({
}
);
onRefresh();
}
;
///下拉刷新const onRefresh = async () =>
{
console.log('VRefreshList onRefresh');
pageIndex.value = props.pageIndexInitial;
if (!hasNet.value) {
// netStatus.value = -1;
refreshing.value = false;
// 下拉刷新加载状态结束 isSuccess.value = false;
// 下拉刷新成功失败 loading.value = false;
// 加载状态结束 finished.value = true;
// 数据全部加载完成 $vtoast.clear();
Toast(NET_MSG_ERROR);
return;
}
refreshing.value = true;
loading.value = false;
requestList(true);
}
;
// 上拉获取更多const onMore = async () =>
{
console.log('VRefreshList onMore');
pageIndex.value++;
refreshing.value = false;
loading.value = true;
requestList(false);
}
;
/// 获取历史消息const requestList = async () =>
{
try {
netStatus.value = 1;
const params = {
isRefresh: refreshing.value, page: pageIndex.value, pageSize: props.pageSize, lastObj: list.length >
0 ? list[list.length - 1] : undefined, }
;
const items = await props.requestFC(params);
// console.log(`VRefreshList items:${
items.length}
`);
if (refreshing.value) {
list.splice(0, list.length);
}
if (list.length === 0 &
&
items.length === 0) {
refreshing.value = false;
isSuccess.value = true;
loading.value = false;
// 加载状态结束 finished.value = true;
// 数据全部加载完成 netStatus.value = 0;
return;
}
if (items.length) {
list.push(...items);
}
console.log(`${
location.hash}
list:${
list.length}
, items:${
items.length}
`);
loading.value = false;
// 加载状态结束 finished.value = (items.length props.pageSize);
// 数据全部加载完成 if(refreshing.value){
isSuccess.value = true;
}
netStatus.value = list.length === 0 ? 0 : 1;
}
catch (error) {
console.log(`${
location.hash}
error: ${
JSON.stringify(error)}
, refreshing: ${
refreshing.value}
, hasNet.value:${
hasNet.value}
`);
finished.value = true;
// 数据全部加载完成 isSuccess.value = false;
// 下拉刷新成功失败 if (!hasNet.value) {
netStatus.value = -1;
}
else {
netStatus.value = 0;
}
if (!error) {
return;
}
props.requestErrorFC &
&
await props.requestErrorFC(error);
}
finally {
$vtoast.clear();
refreshing.value = false;
loading.value = false;
// 加载状态结束 }
}
;
watch(() =>
props.requestParamsChange, (newValue, oldValue) =>
{
console.log('watch requestParamsChange', newValue, oldValue);
if (newValue !== oldValue) {
scrollToTop(listEl);
onRefresh();
}
}
);
watch(() =>
hasNet.value, (newValue, oldValue) =>
{
// console.log('hasNet.value', newValue, oldValue);
if (newValue) {
onRefresh();
}
}
);
let listEl;
onMounted(() =>
{
listEl = document.getElementById('van-list');
// console.log(listEl);
}
);
const scrollToTop = (e) =>
e.scrollIntoView({
block: 'start' }
);
/script>
最后、总结
1、此文重构方法的意义在于我可以通过封装一个列表组件,然后同类页面只需要传请求方法即可,极大的提高开发效率(vue 中组件亦可是页面);
2、核心是通过 Vue3 属性支持 Function 进而实现函数透传,虽然官方文档只是一笔带过,但确实是核心特性之一;
3、Function 类型无论在 Swift、Dart/Flutter、JS/TS 中都是一等公民;可以帮助我们扩展代码重构边界。在实现此次封装之前我也不知道能做到什么程度,不过最终效果非常理想;
4、姐妹篇 Flutter 重构: 属性透传/函数透传
以上就是Vue3 重构函数透传示例解析的详细内容,更多关于Vue3 重构函数透传的资料请关注其它相关文章!
您可能感兴趣的文章:- vue前端重构computed及watch组件通信等实用技巧整理
- 测试平台开发vue组件化重构前端代码
- 使用vue3重构拼图游戏的实现示例
- 记一次用ts+vuecli4重构项目的实现
- 使用vue重构资讯页面的实例代码解析
- 利用vue重构有赞商城的思路以及总结整理
声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!
若转载请注明出处: Vue3 重构函数透传示例解析
本文地址: https://pptw.com/jishu/609361.html
