我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Vue3重构函数透传示例解析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Vue3重构函数透传示例解析

一、来源

之前做 vue 手机端需求开发时,遇到多个相似列表页面:

列表页面+下拉刷新和上拉加载+占位图(无数据+断网)...

就想能不能复用同一个页面,传入不同的数据和单元格即可;经过一个多月的思考(查询js 的特性 + Vue3官方文档),最终在官方文档:

截屏2023-02-17 08.17.09.png

找到解决办法: 属性透传方法

原理如下:

截屏2023-02-17 08.42.48.png

二、使用示例

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 '@/components/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 重构函数透传的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Vue3重构函数透传示例解析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Vue3重构函数透传示例解析

这篇文章主要为大家介绍了Vue3重构函数透传示例解析
2023-02-17

Flutter重构属性透传及函数透传使用示例

这篇文章主要为大家介绍了Flutter重构属性透传及函数透传使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-08

Flutter重构属性透传及函数透传如何使用

这篇文章主要介绍“Flutter重构属性透传及函数透传如何使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Flutter重构属性透传及函数透传如何使用”文章能帮助大家解决问题。一、来源今天在研究
2023-07-04

Vue3源码解析watch函数实例

这篇文章主要为大家介绍了Vue3源码解析watch函数实例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

Swift 重构重载运算符示例解析

这篇文章主要为大家介绍了Swift 重构重载运算符示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-03-13

InputStream数据结构示例解析

这篇文章主要为大家介绍了InputStream数据结构示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

Java 重载、重写、构造函数的实例详解

Java 重载、重写、构造函数的实例详解方法重写1、重写只能出现在继承关系之中。当一个类继承它的父类方法时,都有机会重写该父类的方法。一个特例是父类的方法被标识为final。重写的主要优点是能够定义某个子类型特有的行为。class Anim
2023-05-31

Linux中可重入函数与不可重入函数的示例分析

这篇文章主要为大家展示了“Linux中可重入函数与不可重入函数的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Linux中可重入函数与不可重入函数的示例分析”这篇文章吧。Linux 中可
2023-06-09

函数重写示例解析:实战案例中的应用精髓

问题:如何扩展现有函数以满足新需求而无需修改原始函数?解决方案:使用函数重写:1. 创建一个继承原始函数特性的新函数,并提供更新的处理逻辑。2. 在系统中使用新函数处理特定情况,而原始函数继续处理其他情况。优点:可扩展性,隔离性,可重用性。
函数重写示例解析:实战案例中的应用精髓
2024-05-03

C/C++函数原理传参示例详解

这篇文章主要为大家介绍了C/C++函数原理传参示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-12-08

编程热搜

目录