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