页面:pages/list/list.vue(列表页)、pages/detail/detail.vue(详情页)

学习内容v-for 列表循环渲染、列表点击事件、复杂对象路由传参、编码解码处理、列表→详情经典业务场景

学习时长:2 小时(40min 知识点 + 70min 编码 + 10min 问题整理)

前置环境:基于前面路由、本地存储知识点迭代,uView2 正常配置,tabBar 已生效


一、今日核心知识点笔记(摘抄存档)

  1. v-for 列表循环

    • 基础语法:v-for="(item, index) in 数组" :key="index"
    • item:当前循环的单条数据对象;index:当前数据下标(从 0 开始)
    • :key:列表唯一标识,提升渲染性能,循环列表必须添加
  2. 列表点击传参难点

    • 普通文本 / 数字可直接在 url 拼接传递;对象、数组不能直接拼接
    • 解决方案:JSON.stringify() 将对象转为字符串,配合 encodeURIComponent() 编码,避免特殊字符导致参数丢失
  3. 详情页接收参数

    • onLoad(options) 中获取路由参数
    • 先通过 decodeURIComponent() 解码,再用 JSON.parse() 转回 JS 对象
  4. 页面跳转选择 列表跳详情属于普通页面跳转,统一使用 uni.navigateTo,支持返回上一级页面。


二、分步实操步骤

  1. pages 目录下,分别新建 listdetail 两个页面;
  2. 打开 pages.json,将两个页面路径加入 pages 数组(无需加入 tabBar);
  3. 编写 list.vue:定义模拟列表数据,使用 v-for 渲染列表,绑定点击跳转方法;
  4. 编写 detail.vue:在 onLoad 接收、解析参数,渲染详情内容;
  5. Ctrl+S 保存全部文件,清理缓存后运行到微信开发者工具;
  6. 功能测试:点击不同列表项,查看详情页是否展示对应数据、返回功能是否正常。


三、pages.json 配置补充

新增页面后,在根目录 pages.json 补充页面路径,保证页面可正常访问:

{
	"easycom": {
		"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
	},
	"pages": [
		{  
			"path": "pages/login/login",
			"style": {
				"navigationBarTitleText": ""
			}
		},
		{  
			"path": "pages/mine/mine",
			"style": {
				"navigationBarTitleText": ""
			}
		},
		{
			"path": "pages/index/index",
			"style": {
				"navigationBarTitleText": ""
			}
		},
		{
			"path": "pages/msg/msg",
			"style": {
				"navigationBarTitleText": ""
			}
		},
		{
			"path": "pages/list/list",
			"style": {
				"navigationBarTitleText": ""
			}
		},
		{
			"path": "pages/detail/detail",
			"style": {
				"navigationBarTitleText": ""
			}
		}
	],
	"globalStyle": {
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "教务管理系统",
		"navigationBarBackgroundColor": "#ffffff",
		"backgroundColor": "#F5F5F5"
	},
	"tabBar": {
		"backgroundColor": "#333",
		"color": "#666",
		"selectedColor": "#007aff",
		"borderStyle": "black",
		"list": [
			{
				"pagePath": "pages/mine/mine",
				"text": "我的"
			},
			{
				"pagePath": "pages/msg/msg",
				"text": "消息"
			},
			{
				"pagePath": "pages/index/index",
				"text": "首页"
			}
		]
		
	}
}

四、完整代码 + 逐行超详细注释

4.1 列表页 pages/list/list.vue

<!-- 页面结构区域 -->
<template>
	<!-- 页面外层容器 -->
	<view class="list-wrap">
		<!-- 页面导航标题 -->
		<view class="page-title">学员信息列表</view>

		<!-- 
      列表循环渲染
      v-for:遍历 studentList 数组
      item:单条学员数据对象
      index:数据下标
      :key="index":列表唯一标识,必写
      @click="goToDetail(item)":点击当前条目,传递本条数据
    -->
		<view class="list-item" v-for="(item, index) in studentList" :key="index" @click="goToDetail(item)">
			<!-- 渲染单条列表内容 -->
			<view class="item-row">姓名:{{ item.name }}</view>
			<view class="item-row">科目:{{ item.subject }}</view>
			<view class="item-row">分数:{{ item.score }} 分</view>
			<view class="item-row">班级:{{ item.className }}</view>
		</view>
	</view>
</template>

<!-- 逻辑脚本区域 -->
<script>
	// Vue2 组件固定导出写法
	export default {
		// 响应式数据定义
		data() {
			return {
				// 模拟后端返回的学员列表数组
				studentList: [{
						id: 1,
						name: "张三",
						subject: "物理",
						score: 86,
						className: "高一(1)班"
					},
					{
						id: 2,
						name: "李四",
						subject: "数学",
						score: 92,
						className: "高一(2)班"
					},
					{
						id: 3,
						name: "王五",
						subject: "物理",
						score: 78,
						className: "高二(1)班"
					},
					{
						id: 4,
						name: "赵六",
						subject: "数学",
						score: 95,
						className: "高二(2)班"
					}
				]
			}
		},

		// 自定义方法集合
		methods: {
			/**
			 * 跳转到详情页方法
			 * @param {Object} row 当前点击的单条学员数据对象
			 */
			goToDetail(row) {
				// 1. 对象转 JSON 字符串(url 不支持直接传递对象)
				let rowStr = JSON.stringify(row)
				// 2. 编码:防止特殊字符、空格导致参数丢失/解析异常
				let encodeStr = encodeURIComponent(rowStr)

				// 3. 页面跳转,拼接参数
				uni.navigateTo({
					url: `/pages/detail/detail?stuInfo=${encodeStr}`
				})
			}
		},

		// 页面加载生命周期,今日无额外逻辑
		onLoad() {}
	}
</script>

<!-- 样式区域 scoped:样式隔离 -->
<style scoped>
	/* 页面整体容器 */
	.list-wrap {
		padding: 30rpx;
	}

	/* 页面标题 */
	.page-title {
		font-size: 38rpx;
		font-weight: bold;
		text-align: center;
		margin-bottom: 40rpx;
		color: #333;
	}

	/* 列表单项样式 */
	.list-item {
		padding: 25rpx;
		background-color: #f7f8fa;
		border-radius: 12rpx;
		margin-bottom: 20rpx;
		/* 点击反馈 */
		cursor: pointer;
	}

	/* 列表内单行文字 */
	.item-row {
		font-size: 28rpx;
		color: #555;
		line-height: 50rpx;
	}
</style>

4.2 详情页 pages/detail/detail.vue

<!-- 页面结构区域 -->
<template>
	<view class="detail-wrap">
		<view class="page-title">学员详情</view>

		<!-- 渲染解析后的学员详情数据 -->
		<view class="detail-card">
			<view class="detail-row">姓名:{{ stuInfo.name }}</view>
			<view class="detail-row">科目:{{ stuInfo.subject }}</view>
			<view class="detail-row">考试分数:{{ stuInfo.score }} 分</view>
			<view class="detail-row">所在班级:{{ stuInfo.className }}</view>
			<view class="detail-row">学员编号:{{ stuInfo.id }}</view>
		</view>

		<!-- 返回上一页按钮 -->
		<u-button type="primary" size="large" shape="round" @click="goBack" class="back-btn">
			返回列表
		</u-button>
	</view>
</template>

<!-- 逻辑脚本区域 -->
<script>
	export default {
		data() {
			return {
				// 用于接收并存储解析后的学员对象
				stuInfo: {}
			}
		},

		/**
		 * 页面加载生命周期
		 * options:路由传递过来的所有参数
		 */
		onLoad(options) {
			console.log("原始路由参数:", options)
			// 1. 解码:还原编码后的字符串
			let decodeStr = decodeURIComponent(options.stuInfo)
			// 2. JSON 字符串转回 JS 对象
			this.stuInfo = JSON.parse(decodeStr)
			console.log("解析后的学员数据:", this.stuInfo)
		},

		methods: {
			// 返回上一页
			goBack() {
				// delta:1 代表返回上一级页面
				uni.navigateBack({
					delta: 1
				})
			}
		}
	}
</script>

<!-- 样式区域 -->
<style scoped lang="scss">
	.detail-wrap {
		padding: 30rpx;
	}

	.page-title {
		font-size: 38rpx;
		font-weight: bold;
		text-align: center;
		margin-bottom: 40rpx;
		color: #333;
	}

	/* 详情卡片容器 */
	.detail-card {
		padding: 30rpx;
		background: #f7f8fa;
		border-radius: 12rpx;
		margin-bottom: 60rpx;
	}

	/* 详情单行内容 */
	.detail-row {
		font-size: 30rpx;
		color: #444;
		line-height: 60rpx;
	}

	/* 返回按钮边距 */
	.back-btn {
		margin-top: 20rpx;
	}
</style>

五、功能验收打卡(逐项勾选)

☐ 列表页正常渲染所有模拟学员数据,v-for 循环生效

☐ 每条列表项布局样式正常,点击有交互效果

☐ 点击任意列表条目,正常跳转到详情页

☐ 详情页完整展示对应学员的全部信息,数据匹配无误

☐ 控制台可正常打印原始参数、解析后对象,无报错

☐ 点击「返回列表」按钮,正常回到上一级列表页

☐ 理解 JSON.stringify / JSON.parseencodeURIComponent / decodeURIComponent 配套使用逻辑


六、重点拓展笔记(必记)

1. 传参完整流程(串联记忆)

列表页:对象 → JSON.stringify() → 编码encodeURIComponent() → 路由传递 详情页:解码decodeURIComponent() → JSON.parse() → 可用对象

2. 为什么要编码?

路由参数中如果包含空格、特殊符号、中文,会出现参数截断、乱码、丢失encodeURIComponent 可以对字符转义,保证参数完整传递。

3. 补充区分

  • 简单参数(字符串 / 数字):直接拼接 ?name=张三&score=88 即可,无需转 JSON
  • 复杂参数(对象 / 数组):必须走 序列化 + 编码 流程

4. 补充小技巧

如果数据量极大、结构复杂,不建议路由传参,优先使用 本地存储 uni.setStorageSync 中转。


七、拓展练习(选做,巩固知识点)

  1. 给列表新增「性别、年龄」字段,修改模拟数据,同步修改列表和详情展示;
  2. 新增一条空数据条目,观察页面渲染效果,做简单容错处理;
  3. 去掉编码 / 解码方法,故意制造乱码问题,加深对编码作用的理解。
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐