乐于分享
好东西不私藏

uni-app开发极简入门(11):表格与表单

uni-app开发极简入门(11):表格与表单

在移动客户端,通常来说表格页用的比较少,多是元素很丰富的页面,不过考虑到表格页还是很基础的且我个人没有美术资源,搞不来那么漂亮的页面了,就写个简简单单的表格页。

创建pages/user/user.vue:

<template>    <viewclass="container">        <!-- 数据列表 -->        <viewclass="list-item"v-for="item in userList":key="item.id" @click="handleItemClick(item)">            {{ item.id }},{{item.name}},{{item.idCard}}        </view>        <!-- 加载状态 -->        <viewclass="loading-wrapper">            <textv-if="isRefreshing"class="loading-text">加载中...</text>            <textv-if="!hasMore"class="no-more">没有更多数据了</text>        </view>    </view></template><scriptlang='ts'setupname='UniUser'>    import {        onMounted,        ref    } from 'vue'    import {        BaseResponse,        Page    } from '../../common/params'    import {        UserDetail    } from '../user/userVo'    import {        request    } from '../../utils/request'    import {        onShow    } from "@dcloudio/uni-app"    import {        onPullDownRefresh,        onReachBottom    } from '@dcloudio/uni-app';    // 类型定义    const isRefreshing = ref(false// 下拉刷新状态    const isLoading = ref(false// 加载状态    const userList = ref < UserDetail[] > ([])    const page = ref(1)    const pageSize = 20    const hasMore = ref(true)    const scrollViewHeight = ref('100vh')    // POST请求    const getUserList = async (initData: boolean = true) => {        try {            isLoading.value = true            isRefreshing.value = true            if (initData) {                page.value = 1            }            const res = await request < BaseResponse < Page < UserDetail[] >>> ({                url'/user/page',                method'POST',                data: {                    page: page.value,                    pageSize: pageSize                },                header: {                    'Content-Type''application/json'                }            })            if (res.code === 0) {                const response = res.data as unknown as Page < UserDetail[] >                    if (initData) {                        userList.value = response.list                    } else {                        userList.value = [...userList.value, ...response.list]                    }                hasMore.value = userList.value.length < response.total                page.value++                uni.showToast({                    title'列表获取成功',                    icon'success'                })            } else {                throw new Error(res.msg)            }        } catch (error) {            uni.showToast({                title'获取失败',                icon'none'            })            console.error('POST请求错误:', error)        } finally {            isLoading.value = false            isRefreshing.value = false            uni.stopPullDownRefresh();//很重要,数据请求无论成功或失败,都要通过此方法管边下拉刷新的加载动画,否则动画会一直持续        }    }    const handleItemClick = (item: UserDetail) => {        uni.navigateTo({            url`/pages/user/userDetail?id=${item.id}` // 跳转到详情页并传递id参数        });    }    // 下拉刷新处理    // 监听下拉刷新事件    onPullDownRefresh(() => {        console.log("下拉刷新");        if (isLoading.value) {            return        }        getUserList()    });    // 监听上拉触底事件    onReachBottom(() => {        console.log("上拉加载");        if (isLoading.value || !hasMore.value) {            return        }        getUserList(false)    });    /**     * onShow是页面切出去再切回来,就执行。与之对应的是onHide     * onMounted是页面第一次加载执行,页面切出去再切回来,不执行。与之对应的是onUnmounted     */    onMounted(() => {        console.log("列表页面加载")        // 计算滚动区域高度(根据实际布局调整)        const systemInfo = uni.getSystemInfoSync()        scrollViewHeight.value = `calc(${systemInfo.windowHeight}px - 100px)` // 示例中减去顶部高度        // 初始化加载数据        getUserList()    })</script><stylescoped>    .container {        height100vh;        display: flex;        flex-direction: column;    }    .scroll-view {        flex1;        height100%;    }    .list-item {        padding24rpx;        border-bottom1rpx solid #eee;        font-size28rpx;    }    .loading-wrapper {        padding30rpx 0;        text-align: center;    }    .loading-text {        color#999;        font-size26rpx;        display: flex;        align-items: center;        justify-content: center;    }    .no-more {        color#ccc;        font-size26rpx;        text-align: center;    }    /* 加载动画 */    .loading-text::after {        content'';        display: inline-block;        width20rpx;        height20rpx;        border3rpx solid #ddd;        border-radius50%;        border-top-color#007AFF;        margin-left10rpx;        animation: spin 0.6s linear infinite;    }</style>
  • 服务端的接口代码就不放了。

  • BaseResponse、UserDetail这些代码之前的文章都有,也不放了。

  • 跳转之详情页,我只用url传了一个id,如果传复杂对象,可用前文讲到的EventChannel。

  • 网络请求相关代码都简单,不讲了。

  • 主要是下拉刷新、下拉加载,实现的方案有很多,我使用了uni-app原生的onPullDownRefresh,onReachBottom,与之对应的也要修改pages.json。

修改pages.json中的”pages”:

{    "path": "pages/user/user",    "style": {        "navigationBarTitleText": "原生用户",        "enablePullDownRefresh": true    }}

设置配置项enablePullDownRefresh为true,开启下拉刷新。

详情页pages/user/userDetail:

<template>    <viewclass="container">        <scroll-viewscroll-yclass="scroll-view">            <!-- 自定义卡片容器 -->            <viewv-if="userDetail.id"class="custom-card">                <viewclass="card-header">                    <textclass="card-title">用户详情</text>                </view>                <viewclass="card-body">                    <viewclass="detail-item">                        <textclass="label">用户ID:</text>                        <textclass="value">{{ userDetail.id }}</text>                    </view>                    <viewclass="detail-item">                        <textclass="label">姓名:</text>                        <textclass="value">{{ userDetail.name }}</text>                    </view>                    <viewclass="detail-item">                        <textclass="label">身份证:</text>                        <textclass="value">{{ userDetail.idCard }}</text>                    </view>                    <viewclass="detail-item">                        <textclass="label">手机号:</text>                        <textclass="value">{{ userDetail.phone }}</text>                    </view>                    <viewclass="detail-item">                        <textclass="label">性别:</text>                        <textclass="value">{{ displayGender }}</text>                    </view>                    <viewclass="detail-item">                        <textclass="label">地址:</text>                        <textclass="value">{{ userDetail.address }}</text>                    </view>                </view>            </view>            <!-- 自定义加载状态 -->            <viewv-if="loading"class="loading-wrapper">                <viewclass="loading-content">                    <textclass="loading-text">加载中...</text>                </view>            </view>        </scroll-view>    </view></template><scriptlang='ts'setupname='UserDetail'>    import {        ref,        onMounted,        computed    } from 'vue'    import {        onLoad    } from "@dcloudio/uni-app"    import {        UserDetail    } from './userVo';    import {        BaseResponse    } from '../../common/params';    import {        request    } from '../../utils/request';    // 用户详情数据    const userDetail = ref < UserDetail > ({        id'-',        name'-',        idCard'-',        phone'-',        gender'male',        birthDate'2021-01-01',        address'-'    })    const loading = ref(false)    // 计算属性显示性别    const displayGender = computed(() => {        return userDetail.value.gender === 'male' ? '男' : '女'    })    const fetchUserDetail = async (id: string) => {        try {            loading.value = true            const res = await request < BaseResponse < UserDetail >> ({                url'/user/getUserById',                data: {                    userId: id                }            })            if (res.code === 0) {                const response = res.data as unknown as UserDetail                userDetail.value = response                uni.showToast({                    title'用户详情获取成功',                    icon'success'                })            } else {                throw new Error(res.msg)            }        } catch (error) {            uni.showToast({                title'获取失败:' + error.message,                icon"error"            })            console.error('POST请求错误:', error)        } finally {            loading.value = false        }    }    // 从路由参数获取ID    onLoad((options: any) => {        const userId = options.id as string        if (userId) {            fetchUserDetail(userId)        } else {            uni.showToast({                title'用户ID无效',                icon'none'            })            uni.navigateBack()        }    })</script><stylescoped>    .container {        padding20rpx;        height100vh;        background-color#f8f8f8;    }    .scroll-view {        height100%;    }    .custom-card {        margin20rpx;        background#fff;        border-radius16rpx;        box-shadow0 4rpx 12rpx rgba(0000.08);    }    .card-header {        padding24rpx 32rpx;        border-bottom2rpx solid #f0f0f0;    }    .card-title {        font-size34rpx;        font-weight600;        color#333;    }    .card-body {        padding32rpx;    }    .detail-item {        display: flex;        justify-content: space-between;        align-items: center;        padding24rpx 0;    }    .detail-item:not(:last-child) {        border-bottom1rpx solid #eee;    }    .label {        color#666;        font-size28rpx;        flex-shrink0;    }    .value {        color#333;        font-size30rpx;        max-width70%;        text-align: right;        word-break: break-all;    }    .loading-wrapper {        display: flex;        justify-content: center;        padding60rpx 0;    }    .loading-content {        display: flex;        flex-direction: column;        align-items: center;    }    .loading-icon {        width80rpx;        height80rpx;        margin-bottom20rpx;        animation: rotate 1s linear infinite;    }    .loading-text {        font-size26rpx;        color#999;    }    @keyframes rotate {        from {            transformrotate(0deg);        }        to {            transformrotate(360deg);        }    }</style>

通过onLoad从路由参数获取ID。


本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » uni-app开发极简入门(11):表格与表单

评论 抢沙发

5 + 7 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮