Loading Views On Demand[按需加载View]

本文介绍如何在Android应用中使用ViewStub来减少内存占用并提升加载效率,通过实例展示如何创建和加载ViewStub布局,以及其在减少资源消耗方面的优势。

原文详见:http://developer.android.com/training/improving-layouts/loading-ondemand.html

有时一些很复杂的视图却又很少用到。如果我们在需要的时候再载入,这样可以减少内存的使用并且给用户带来流畅的体验。



Define a ViewStub ViewStub是一个轻量级的view,没有占有空间,没有花费draw的资源,也没有参与在任何一个layout里面。不仅创建它仅需要很少的系统资源,而且存留在View的层级也是个比较不花费资源的动作。每一个ViewStub简单的包含一个android:layout的属性来指定待创建的布局文件。   

下面是一个包含Progress bar的ViewStub例子,这对于overlay来说是透明的,progress bar仅仅会在需要导入的时候才会可见。
  1.     <ViewStub  
            android:id="@+id/stub_import"  
            android:inflatedId="@+id/panel_import"  
            android:layout="@layout/progress_overlay"  
            android:layout_width="fill_parent"  
            android:layout_height="wrap_content"  
            android:layout_gravity="bottom" />  

Load the ViewStub Layout [载入ViewStub的布局]

当你想要载入在ViewStub中定义的布局的时候,可以calling setVisibility(View.VISIBLE) or call inflate().

((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
一旦被设置可见或者被创建,这个ViewStub组件则从View层级中消失,它被创建出来的布局所替代,而且这个布局的ID就是ViewStub里面用android:inflatedId属性所定义的。
(用来定义这个ViewStub的ID的属性andoid:id直到被可见才是有效的)。

Note:ViewStub的一个缺陷是目前并不支持创建包含有<merge>标签的布局文件。
<!-- * @Author: wh * @Date: 2025-09-03 10:16:22 * @LastEditors: wh * @LastEditTime: 2025-09-05 11:21:37 --> <template> <view v-if="template"> <s-layout title="首页" navbar="custom" tabbar="/pages/index/index"> <scroll-view class="home-scroll" scroll-y="true" :style="{ height: scrollHeight + 'px' }" > <view class="home"> <view class="banner"> <view class="banner-container" @touchstart="handleTouchStart" @touchend="handleTouchEnd" > <view class="banner-scroll" :style="{ transform: `translateX(-${currentIndex * 100}%)`, transition: isAutoScroll ? 'transform 0.5s ease' : 'none', }" > <view class="banner-item" v-for="(item, index) in swiperData.items" :key="index" @click="handleBannerClick(item)" > <image :src="item.imgUrl" mode="aspectFill" class="banner-img" ></image> </view> </view> <view class="banner-indicator"> <view class="indicator-dot" v-for="(item, index) in swiperData.items" :key="index" :class="{ 'indicator-dot--active': index === currentIndex }" ></view> </view> </view> </view> <view class="computing"> <view class="computing_con"> <view class="title"> <span>算力中心</span> <span class="more" @click="computingMore">更多</span> </view> <s-menu-grid :data="computingData" :styles="computingData.style" @item-click="handleComputingItemClick" /> </view> </view> <view class="special"> <view class="special_con"> <view class="title"> <span>专区</span> <span class="more" @click="zoneMore">更多</span> </view> <view class="special-content"> <view v-for="(item, index) in specialData" :key="index" class="special-card" @click="handleZoneClick()" > <view class="special-img-container"> <image :src="item.logoFilePath" mode="aspectFill" class="special-img" ></image> </view> <view class="special-text"> <text class="special-title">{{ item.name }}</text> <text class="special-subtitle" v-if="item.subtitle">{{ item.subtitle }}</text> </view> </view> </view> </view> </view> <view class="product"> <view class="product_con"> <view class="title"> <span>推荐商品</span> </view> <view class="content"> <view v-for="(item, index) in productList" :key="index" class="product-card" :class="{ 'reverse-layout': index % 2 === 1 }" @click="handleProductClick(item.id)" > <view class="product-img"> <image :src="item.image" mode="aspectFill" class="product-img__inner" ></image> </view> <view class="product-info"> <view class="product-title">{{ item.productName }}</view> <view class="product-price"> <text class="product-01">{{ item.productTypeName }}</text> <text class="product-02">{{ item.price || "面议" }}</text> </view> <text class="product-name">{{ item.storeName }}</text> <text class="product-subtitle">{{ item.productDesc }}</text> </view> </view> </view> </view> </view> </view> </scroll-view> </s-layout> </view> </template> <script setup> import { ref, computed, onMounted, onUnmounted } from "vue"; import { onLoad, onPageScroll, onPullDownRefresh } from "@dcloudio/uni-app"; import sheep from "@/sheep"; import CommonApi from "@/sheep/api/common/index"; import ProductApi from "@/sheep/api/product/index"; import ZoneApi from "@/sheep/api/zone/index"; // 隐藏原生tabBar uni.hideTabBar({ fail: () => {} }); const currentIndex = ref(0); // 当前显示的Banner索引 const touchStartX = ref(0); // 触摸起始X坐标 const touchEndX = ref(0); // 触摸结束X坐标 const autoScrollTimer = ref(null); // 自动轮播定时器 const isAutoScroll = ref(true); // 是否开启自动滚动(用于控制过渡动画) const swiperData = ref({ autoplay: true, // 是否自动轮播 interval: 5000, // 轮播间隔(毫秒) items: [ { imgUrl: "https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/banner-01.png", link: "", // 点击跳转链接 }, { imgUrl: "https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/banner-02.png", link: "", }, { imgUrl: "https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/banner-03.png", link: "", }, { imgUrl: "https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/banner-04.png", link: "", }, ], }); const handleTouchStart = (e) => { touchStartX.value = e.touches[0].clientX; isAutoScroll.value = false; clearInterval(autoScrollTimer.value); }; const handleTouchEnd = (e) => { touchEndX.value = e.changedTouches[0].clientX; const diffX = touchEndX.value - touchStartX.value; if (diffX > 50) { currentIndex.value = currentIndex.value === 0 ? swiperData.value.items.length - 1 : currentIndex.value - 1; } else if (diffX < -50) { currentIndex.value = currentIndex.value === swiperData.value.items.length - 1 ? 0 : currentIndex.value + 1; } if (swiperData.value.autoplay) { startAutoScroll(); } isAutoScroll.value = true; // 恢复动画 }; // 点击Banner转链接 const handleBannerClick = (item) => { // if (item.link) { // if (item.link.includes("pages/index/category")) { // uni.reLaunch({ url: item.link }); // } else if (item.link.includes("pages/special")) { // uni.navigateTo({ url: item.link }); // } else { // uni.navigateTo({ url: item.link }); // } // } }; // 开启自动轮播 const startAutoScroll = () => { if (!swiperData.value.autoplay) return; clearInterval(autoScrollTimer.value); autoScrollTimer.value = setInterval(() => { currentIndex.value = currentIndex.value === swiperData.value.items.length - 1 ? 0 : currentIndex.value + 1; }, swiperData.value.interval); }; onUnmounted(() => { clearInterval(autoScrollTimer.value); }); const scrollHeight = ref(1000); const navigationBarData = ref({ title: "", description: "", navBarHeight: 55, backgroundColor: "#415EE8", backgroundImage: "", styleType: "normal", alwaysShow: true, showGoBack: true, bgType: "color", bgColor: "#415EE8", }); const productList = ref([]); const computingData = ref({ column: 3, list: [ { title: "卡时售卖", titleColor: "#333", subtitle: "", subtitleColor: "#bbb", badge: { show: false, textColor: "#fff", bgColor: "#FF6000", text: "1" }, iconUrl: "https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/kssm.png", url: "/pages/index/category?tab=computing&category=gpu", }, { title: "节点售卖", titleColor: "#333", subtitle: "", subtitleColor: "#bbb", badge: { show: false, textColor: "#fff", bgColor: "#FF6000" }, iconUrl: "https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/jdian.png", url: "/pages/index/category?tab=computing&category=cpu", }, { title: "token售卖", titleColor: "#333", subtitle: "", subtitleColor: "#bbb", badge: { show: false, textColor: "#fff", bgColor: "#FF6000" }, iconUrl: "https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/token.png", url: "/pages/index/category?tab=computing&category=memory", }, ], }); const isZoneLoading = ref(false); const isProductLoading = ref(false); const specialData = ref([]); const template = computed(() => sheep.$store("app").template?.user); const handleComputingItemClick = (item, index) => { if (item.clickHandler) { item.clickHandler(); } else { const categories = ["gpu", "cpu", "memory"]; const category = categories[index] || "gpu"; goToComputingWithCategory(category); } }; const goToComputingWithCategory = (category = "gpu") => { uni.reLaunch({ url: `/pages/index/category?tab=computing&category=${category}`, }); }; const computingMore = () => { uni.reLaunch({ url: "/pages/index/category?tab=computing" }); }; const handleZoneClick = () => { uni.switchTab({ url: "/pages/index/category?tab=product" }); }; const zoneMore = () => { uni.navigateTo({ url: "/pages/special/special-zone" }); }; const handleProductClick = (id) => { uni.navigateTo({ url: `/pages/product/details?id=${id}` }); }; const ZoneList = async (reset = false) => { if (isZoneLoading.value) return; isZoneLoading.value = true; try { const res = await ZoneApi.getZoneList("1", "4"); if (res && res.success && res.data?.records) { specialData.value = res.data.records; } } catch (error) { console.error("专区接口请求失败:", error); } finally { isZoneLoading.value = false; } }; const loadDemandList = async (reset = false) => { if (isProductLoading.value) return; isProductLoading.value = true; try { const res = await ProductApi.getRecommendList("", "HOT", "PRODUCT"); if (res && res.success && res.data) { productList.value = res.data.map((item) => ({ id: item.id, productName: item.productName, productDesc: item.productDesc, image: item.displayFiles?.length > 0 ? item.displayFiles[0].thumbnailUrl || item.displayFiles[0].fileUrl : "/static/img/default-product.png", productTypeName: item.productTypeName, storeName: item.storeName, price: item.price, })); } } catch (error) { console.error("推荐商品接口请求失败:", error); } finally { isProductLoading.value = false; } }; onMounted(() => { if (swiperData.value.autoplay) { startAutoScroll(); } }); onLoad((options) => { uni.hideTabBar({ fail: () => {} }); ZoneList(true); loadDemandList(true); // 小程序识别二维码 if (options.scene) { const sceneParams = decodeURIComponent(options.scene).split("="); options[sceneParams[0]] = sceneParams[1]; } // 预览模板 if (options.templateId) { sheep.$store("app").init(options.templateId); } // 进入指定页面 if (options.page) { sheep.$router.go(decodeURIComponent(options.page)); } }); onPullDownRefresh(() => { sheep.$store("app").init(); setTimeout(() => { uni.stopPullDownRefresh(); }, 800); }); onPageScroll(() => {}); </script> <style lang="scss" scoped> @import "@/sheep/scss/style/_index.scss"; </style>这个是首页的代码,<template> <s-layout title="商城" tabbar="/pages/index/category" navbar="normal" :bgStyle="{}" > <view class="demand-hall"> <!-- 顶部搜索栏 --> <view class="search-bar"> <view class="search-input full-width"> <uni-icons type="search" size="18" color="#999"></uni-icons> <input type="text" :placeholder="activeTab === 'product' ? '搜索产品' : '搜索算力服务'" v-model="searchKeyword" @confirm="handleSearch" /> </view> </view> <!-- Tab分类 --> <view class="tab-bar"> <view class="tab-item" :class="{ active: activeTab === 'product' }" @click="switchTab('product')" > 产品广场 </view> <view class="tab-item" :class="{ active: activeTab === 'computing' }" @click="switchTab('computing')" > 算力中心 </view> </view> <!-- 产品广场内容 --> <view v-if="activeTab === 'product'"> <!-- 分类筛选栏 --> <scroll-view class="category-bar"> <view class="category-con"> <view class="category-item cp-item" v-for="item in categories" :key="item.id" :class="{ active: activeCategory === item.id }" @click="openFilterDrawer(item)" > {{ item.name }} </view> </view> </scroll-view> <!-- 排序栏 --> <view class="sort-bar"> <view class="sort-item" :class="{ active: !currentSort.active }" @click="handleDefaultSort" > <text>综合排序</text> </view> <view class="sort-item" v-for="item in sortOptions" :key="item.key" :class="{ active: currentSort.active && currentSort.key === item.key, }" @click="handleSort(item)" > <text>{{ item.name }}</text> <view class="sort-icons"> <uni-icons :type="getSortIconType(item.key, 'asc')" size="14" :color="getSortIconColor(item.key, 'asc')" ></uni-icons> <uni-icons :type="getSortIconType(item.key, 'desc')" size="14" :color="getSortIconColor(item.key, 'desc')" ></uni-icons> </view> </view> </view> <!-- 产品列表 --> <scroll-view class="demand-list" scroll-y @scrolltolower="loadMore"> <!-- 筛选标签 --> <view class="filter-tags" v-if="selectedFilters.length > 0"> <view class="filter-tag" v-for="(tag, index) in selectedFilters" :key="index" > <text>{{ tag }}</text> <uni-icons type="close" size="20" color="#999" class="delete-icon" @click.stop="handleTagDelete(index)" ></uni-icons> </view> </view> <!-- 产品内容 --> <view class="demand-grid"> <view v-if="demandList.length === 0 && !isLoading" class="empty-state" > <!-- <text>暂无产品数据</text> --> </view> <view class="demand-item" v-for="item in sortedDemandList" :key="item.id" @click="navigateToDetail(item.id)" > <view class="category-img"> <image class="demand-image" :src="item.thumbnailUrl" mode="aspectFill" ></image> </view> <view class="demand-info"> <text class="demand-title">{{ item.productName }}</text> <view class="demand-meta"> <text class="unit">{{ item.productTypeName }}</text> </view> <text class="demand-sort">{{ item.storeName }}</text> <text class="demand-price">{{ item.price || "面议" }}</text> <view class="demand-stats"> <text>{{ item.productDesc }}</text> </view> </view> </view> </view> <!-- 加载状态 --> <view class="load-status"> <uni-load-more :status="isLoading ? 'loading' : noMoreData ? 'noMore' : 'more'" ></uni-load-more> </view> </scroll-view> </view> <!-- 算力中心内容 --> <view v-if="activeTab === 'computing'"> <!-- 算力分类 --> <view class="category-bar"> <view class="category-con sl-con"> <view class="category-item sl-item" v-for="item in computingCategories" :key="item.id" :class="{ active: activeComputingCategory === item.id }" @click="selectComputingCategory(item.id)" > {{ item.name }} </view> </view> </view> <!-- 算力服务列表 --> <scroll-view class="computing-list" scroll-y @scrolltolower="loadMoreComputing" > <view class="computing-grid"> <!-- 无数据状态 --> <view v-if="computingList.length === 0 && !isComputingLoading" class="empty-state" > <text>暂无算力服务数据</text> </view> <!-- 算力服务项 --> <view class="computing-item" v-for="item in computingList" :key="item.id" @click="navigateToComputingDetail(item.id)" > <view class="computing-info"> <view class="computing-top"> <text class="computing-title">{{ item.packageName }}</text> <view class="computing-price">{{ item.price || "面议" }}</view> </view> <view class="computing-specs" v-for="(spec, idx) in item.specs" :key="idx" > <view class="spec-row"> <text class="spec-name">{{ spec.name }}</text> <text class="spec-type">{{ spec.type }}</text> </view> </view> </view> </view> </view> <!-- 加载状态 --> <view class="load-status"> <uni-load-more :status="computingNoMoreData ? 'noMore' : 'more'" ></uni-load-more> </view> </scroll-view> </view> <!-- 筛选侧边栏 (仅产品广场) --> <filter-drawer ref="filterDrawerRef" :filter-options="currentFilterOptions" :selected-options="selectedOptions" @update:selectedOptions="updateSelectedOptions" @confirm="onFilterConfirm" @close="onFilterClose" v-if="activeTab === 'product' && currentFilterOptions.length > 0" /> </view> </s-layout> </template> <script setup> import { ref, reactive, computed, onMounted, nextTick } from "vue"; import { onShow, onPageScroll, onPullDownRefresh, onReachBottom, onLoad, onReady, } from "@dcloudio/uni-app"; import sheep from "@/sheep"; import FilterDrawer from "./components/filter-drawer.vue"; import CommonApi from "@/sheep/api/common/index"; import ProductApi from "@/sheep/api/product/index"; import { handleAuthAndOrgCheck } from "@/sheep/utils/authHandler"; // 隐藏原生tabBar uni.hideTabBar({ fail: () => {}, }); // 当前激活的Tab const activeTab = ref("product"); // 切换Tab const switchTab = (tab) => { activeTab.value = tab; // 切换Tab时重置搜索关键词 searchKeyword.value = ""; }; // 搜索关键词 const searchKeyword = ref(""); // 数据配置 const config = { categories: [ { id: "DIC000003", name: "场景" }, { id: "DIC000001", name: "类型" }, { id: "DIC000004", name: "专区" }, ], }; // 分类数据 const categories = ref(config.categories); // 当前选中的分类 const activeCategory = ref(""); // 排序选项 const sortOptions = ref([ { key: "sales", name: "销量" }, { key: "price", name: "价格" }, { key: "views", name: "浏览量" }, ]); // 当前排序方式 const currentSort = ref({ key: "", order: "", // asc 或 desc active: false, //是否激活排序 }); // 筛选选项数据 const filterOptions = ref([ { id: "DIC000003", name: "场景", options: [], }, { id: "DIC000001", name: "类型", options: [], }, { id: "DIC000004", name: "专区", options: [], }, ]); //默认综合排序 const handleDefaultSort = () => { currentSort.value = { key: "", order: "", active: false, }; queryParams.orderColumn = ""; // 清空排序维度 queryParams.isAsc = undefined; // 清空排序方向 loadDemandList(true); }; // 当前显示的筛选选项 const currentFilterOptions = computed(() => { if (!activeCategory.value) return []; // 返回对应分类的筛选选项 const category = filterOptions.value.find( (cat) => cat.id === activeCategory.value ); return category ? [category] : []; }); // 选中的筛选条件 const selectedFilters = ref([]); const selectedOptions = reactive({ DIC000003: [], // 场景 DIC000001: [], // 类型 DIC000004: [], // 专区 }); // 产品列表数据 const demandList = ref([]); const page = ref(1); const pageSize = ref(10); const isLoading = ref(false); const noMoreData = ref(false); const queryParams = reactive({ current: 1, size: 10, queryType: "PRODUCT", belongDomain: "", sceneCatalog: "", productType: "", orderColumn: "", isAsc: undefined, }); // 排序后的产品列表 const sortedDemandList = computed(() => { // 未激活排序:返回原始列表 if (!currentSort.value.active) { return demandList.value; } // 激活排序:按当前维度和方向排序 return [...demandList.value].sort((a, b) => { const valueA = a[currentSort.value.key] || 0; const valueB = b[currentSort.value.key] || 0; return currentSort.value.order === "asc" ? valueA - valueB : valueB - valueA; }); }); // 算力中心相关数据 const computingCategories = ref([ { id: "gpu", name: "卡时售卖" }, { id: "cpu", name: "节点/集群售卖" }, { id: "memory", name: "token售卖" }, ]); const activeComputingCategory = ref("gpu"); //算力中心内容 const computingStaticData = { // 卡时售卖数据 gpu: [ { id: "gpu-package1", packageName: "套餐一", specs: [ { name: "NV H800", type: "GPU", }, { name: "8468处理器,24核", type: "CPU", }, ], price: "面议", }, { id: "gpu-package2", packageName: "套餐二", specs: [ { name: "NV H800", type: "GPU", }, { name: "8468处理器,48核", type: "CPU", }, ], price: "面议", }, { id: "gpu-package3", packageName: "套餐三", specs: [ { name: "NV H800", type: "GPU", }, { name: "8468处理器,72核", type: "CPU", }, ], type: "CPU", price: "面议", }, ], // 节点/集群售卖数据 cpu: [ { id: "cpu-package1", packageName: "套餐一", specs: [ { name: "8*NV H800", type: "GPU", }, { name: "8468处理器,48C/96T,16GT/s,105M Cache", type: "CPU", }, { name: "2T DDR5-4800 ECC RDIMM", type: "内存", }, { name: "INTEL P5530,3.84T NVME*8", type: "数据盘", }, { name: "NV ConnectX-7 400Gb/s NDR IB*8", type: "算力网络", }, { name: "NV Connectx-7 IB NDR 200G单口", type: "存储网络", }, ], price: "面议", }, { id: "cpu-package2", packageName: "套餐二", specs: [ { name: "8*NV H800 *N", type: "GPU", }, { name: "8468处理器,48C/96T,16GT/s,105M Cache", type: "CPU", }, { name: "2T DDR5-4800 ECC RDIMM", type: "内存", }, { name: "INTEL P5530,3.84T NVME*8", type: "数据盘", }, { name: "NV ConnectX-7 400Gb/s NDR IB*8", type: "算力网络", }, { name: "NV Connectx-7 IB NDR 200G单口", type: "存储网络", }, ], price: "面议", }, { id: "cpu-package3", packageName: "套餐三", specs: [ { name: "8*NV H800 *128/256", type: "GPU", }, { name: "8468处理器,48C/96T,16GT/s,105M Cache", type: "CPU", }, { name: "2T DDR5-4800 ECC RDIMM", type: "内存", }, { name: "INTEL P5530,3.84T NVME*8", type: "数据盘", }, { name: "NV ConnectX-7 400Gb/s NDR IB*8", type: "算力网络", }, { name: "NV Connectx-7 IB NDR 200G单口", type: "存储网络", }, ], price: "面议", }, ], // token售卖数据 memory: [ { id: "memory-package1", packageName: "SFT训练", specs: [ { name: "qwen1.5-7b-chat", type: "模型规格", }, { name: "SFT训练", type: "训练方式", }, ], price: "面议", }, { id: "memory-package2", packageName: "LoRA更新", specs: [ { name: "llama2-7b-base", type: "模型规格", }, { name: "LoRA更新", type: "训练方式", }, ], price: "面议", }, { id: "memory-package3", packageName: "模型评测", specs: [ { name: "llama2-7b-base", type: "模型规格", }, { name: "模型评测", type: "训练方式", }, ], price: "面议", }, ], }; const computingList = ref([]); const computingPage = ref(1); const isComputingLoading = ref(false); const computingNoMoreData = ref(false); // 筛选组件引用 const filterDrawerRef = ref(null); //场景 类型 领域 const state = reactive({ loadStatus: "", pageNum: 1, pageSize: 99, }); // 初始化数据 onMounted(() => { loadDemandList(); loadComputingList(true); }); // 加载产品列表 const loadDemandList = async (reset = false) => { if (isLoading.value) return; if (reset) { queryParams.current = 1; noMoreData.value = false; demandList.value = []; } isLoading.value = true; try { let res = await ProductApi.getProductList( queryParams.current, queryParams.size, queryParams.queryType, queryParams.belongDomain, queryParams.sceneCatalog, queryParams.productType, queryParams.orderColumn, queryParams.isAsc, searchKeyword.value ); let records = []; let hasNext = false; if (res.data && Array.isArray(res.data)) { records = res.data; hasNext = records.length >= queryParams.size; } else if ( res.data && res.data.data && Array.isArray(res.data.data.records) ) { records = res.data.data.records; hasNext = res.data.data.hasNext || false; } else if ( res.data && res.data.records && Array.isArray(res.data.records) ) { records = res.data.records; hasNext = res.data.hasNext || false; } else { hasNext = false; } //处理数据 const processedRecords = records.map((item) => ({ id: item.id || item.productId || Math.random().toString(), productName: item.productName || "-", thumbnailUrl: (item.displayFiles && item.displayFiles.length > 0 && item.displayFiles[0].thumbnailUrl) || item.imageUrl || "/static/images/default-product.png", storeName: item.storeName || "-", publishTime: item.publishTime || "-", productDesc: item.productDesc || "-", productTypeName: item.productTypeName || "-", price: item.price || null, sales: item.saleCount || item.sales || 0, views: item.viewCount || item.views || 0, })); if (reset) { demandList.value = processedRecords; } else { demandList.value = [...demandList.value, ...processedRecords]; } noMoreData.value = !hasNext; queryParams.current++; } catch (error) { } finally { isLoading.value = false; } }; // 加载算力服务列表 const loadComputingList = async (reset = false) => { if (reset) { computingList.value = computingStaticData[activeComputingCategory.value] || []; } }; // 获取排序图标类型 const getSortIconType = (key, direction) => { // 无论是否激活,方向匹配时直接返回对应箭头图标 return direction === "asc" ? "arrowup" : "arrowdown"; }; // 获取排序图标颜色 const getSortIconColor = (key, direction) => { const { active, key: currentKey, order: currentOrder } = currentSort.value; if (active && currentKey === key && currentOrder === direction) { return "#007aff"; } return "#999"; }; // 处理排序 const handleSort = (sortItem) => { const { key } = sortItem; const currentKey = currentSort.value.key; const currentOrder = currentSort.value.order; if (!currentSort.value.active) { currentSort.value = { key, order: "asc", active: true }; } else if (currentKey === key && currentOrder === "asc") { currentSort.value.order = "desc"; } else if (currentKey === key && currentOrder === "desc") { currentSort.value = { key: "", order: "", active: false }; } else { currentSort.value = { key, order: "asc", active: true }; } queryParams.orderColumn = currentSort.value.active ? currentSort.value.key : ""; queryParams.isAsc = currentSort.value.active ? currentSort.value.order === "asc" ? "true" : "false" : undefined; loadDemandList(true); }; // 处理筛选标签删除 const handleTagDelete = async (tagIndex) => { const deletedTag = selectedFilters.value[tagIndex]; let targetCategoryId = ""; let targetOptionIndex = -1; for (const categoryId of Object.keys(selectedOptions)) { const optionIndex = selectedOptions[categoryId].findIndex( (option) => option.name === deletedTag && option.subOptionId !== "all" ); if (optionIndex > -1) { targetCategoryId = categoryId; targetOptionIndex = optionIndex; break; } } if (targetCategoryId && targetOptionIndex > -1) { selectedOptions[targetCategoryId].splice(targetOptionIndex, 1); } selectedFilters.value.splice(tagIndex, 1); // 场景筛选 queryParams.sceneCatalog = selectedOptions.DIC000003.filter( (option) => option.subOptionId !== "all" ) .map((option) => option.subOptionId) .join(","); // 类型筛选 queryParams.productType = selectedOptions.DIC000001.filter( (option) => option.subOptionId !== "all" ) .map((option) => option.subOptionId) .join(","); // 专区筛选 queryParams.belongDomain = selectedOptions.DIC000004.filter( (option) => option.subOptionId !== "all" ) .map((option) => option.subOptionId) .join(","); queryParams.current = 1; await loadDemandList(true); }; // 选择算力分类 const selectComputingCategory = (categoryId) => { activeComputingCategory.value = categoryId; loadComputingList(true); }; // 加载更多 const loadMore = () => { if (!noMoreData.value && !isLoading.value) { loadDemandList(); } }; // 加载更多算力服务 const loadMoreComputing = () => { computingNoMoreData.value = true; }; // 打开筛选抽屉 const openFilterDrawer = async (category) => { activeCategory.value = category.id; await nextTick(); // 获取场景 类型 领域 await getTypeData(activeCategory.value); await nextTick(); filterDrawerRef.value.open(); }; // 更新选中的选项 const updateSelectedOptions = (newOptions) => { Object.keys(newOptions).forEach((key) => { selectedOptions[key] = newOptions[key]; }); updateSelectedFilters(); }; // 筛选确认 const onFilterConfirm = (selectedOptions) => { updateSelectedFilters(); queryParams.sceneCatalog = ""; queryParams.productType = ""; queryParams.belongDomain = ""; queryParams.sceneCatalog = selectedOptions.DIC000003.filter( (item) => item.subOptionId !== "all" ) .map((item) => item.subOptionId) .join(","); queryParams.productType = selectedOptions.DIC000001.filter( (item) => item.subOptionId !== "all" ) .map((item) => item.subOptionId) .join(","); queryParams.belongDomain = selectedOptions.DIC000004.filter( (item) => item.subOptionId !== "all" ) .map((item) => item.subOptionId) .join(","); queryParams.current = 1; loadDemandList(true); }; // 筛选关闭 const onFilterClose = () => { activeCategory.value = ""; }; // 更新选中的筛选标签 const updateSelectedFilters = () => { selectedFilters.value = []; for (const section in selectedOptions) { selectedOptions[section].forEach((option) => { if (option.subOptionId !== "all") { selectedFilters.value.push(option.name); } }); } }; // 搜索处理 const handleSearch = () => { if (activeTab.value === "product") { loadDemandList(true); } else { loadComputingList(true); } }; // 跳转到产品详情 const navigateToDetail = (id) => { uni.navigateTo({ url: `/pages/product/details?id=${id}`, }); }; // 跳转到算力申请 const navigateToComputingDetail = (id) => { handleAuthAndOrgCheck(`/pages/computing/apply`); }; // 监听页面滚动到底部 onReachBottom(() => { if (activeTab.value === "product") { loadMore(); } else { loadMoreComputing(); } }); // 获取码值数据 async function getTypeData(id) { state.loadStatus = "loading"; try { let res = await CommonApi.getCommonList(state.pageNum, state.pageSize, id); if (res.data && Array.isArray(res.data)) { const currentCategory = categories.value.find((cat) => cat.id === id); if (currentCategory) { const mainCategoryOption = { id: currentCategory.id, name: currentCategory.name, children: [], }; mainCategoryOption.children.push({ id: "all", name: "全部", }); res.data.forEach((item) => { mainCategoryOption.children.push({ id: item.value, name: item.label, }); }); const filterCategory = filterOptions.value.find((cat) => cat.id === id); if (filterCategory) { filterCategory.options = [mainCategoryOption]; } } } } catch (error) { } finally { state.loadStatus = ""; } } const handlePageParams = (options) => { if (options && options.tab) { const newTab = options.tab; if (activeTab.value !== newTab) { activeTab.value = newTab; if (newTab === "computing") { if ( options.category && computingCategories.value.some((cat) => cat.id === options.category) ) { activeComputingCategory.value = options.category; } else { activeComputingCategory.value = computingCategories.value[0]?.id || "gpu"; } loadComputingList(true); } else { loadDemandList(true); } return true; } } return false; }; onLoad(async (options) => { // 处理参数 handlePageParams(options); // 预先加载所有分类数据 for (const category of categories.value) { await getTypeData(category.id); } // 如果参数没有导致Tab变化,加载默认数据 if (!handlePageParams(options)) { if (activeTab.value === "product") { loadDemandList(); } else { loadComputingList(true); } } }); onShow(() => { const pages = getCurrentPages(); const currentPage = pages[pages.length - 1]; if (currentPage && currentPage.options) { handlePageParams(currentPage.options); } }); </script> <style lang="scss" scoped> @import "@/sheep/scss/style/_category.scss"; </style>这个是商城页面的代码,我想在首页的算力中心跳转到商城的算力中心对应的tab栏,这两个页面都是tab底部跳转页面
09-06
根据原作 https://pan.quark.cn/s/459657bcfd45 的源码改编 Classic-ML-Methods-Algo 引言 建立这个项目,是为了梳理和总结传统机器学习(Machine Learning)方法(methods)或者算法(algo),和各位同仁相互学习交流. 现在的深度学习本质上来自于传统的神经网络模型,很大程度上是传统机器学习的延续,同时也在不少时候需要结合传统方法来实现. 任何机器学习方法基本的流程结构都是通用的;使用的评价方法也基本通用;使用的一些数学知识也是通用的. 本文在梳理传统机器学习方法算法的同时也会顺便补充这些流程,数学上的知识以供参考. 机器学习 机器学习是人工智能(Artificial Intelligence)的一个分支,也是实现人工智能最重要的手段.区别于传统的基于规则(rule-based)的算法,机器学习可以从数据中获取知识,从而实现规定的任务[Ian Goodfellow and Yoshua Bengio and Aaron Courville的Deep Learning].这些知识可以分为四种: 总结(summarization) 预测(prediction) 估计(estimation) 假想验证(hypothesis testing) 机器学习主要关心的是预测[Varian在Big Data : New Tricks for Econometrics],预测的可以是连续性的输出变量,分类,聚类或者物品之间的有趣关联. 机器学习分类 根据数据配置(setting,是否有标签,可以是连续的也可以是离散的)和任务目标,我们可以将机器学习方法分为四种: 无监督(unsupervised) 训练数据没有给定...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值