uniapp的navigator跳转功能

接下来,我将围绕一个常见的电商小程序来构建一系列连贯的使用场景。在这个过程中,我们将把 <navigator> 组件的所有关键属性和方法都串联起来,并详细解释它们在每个环节所扮演的角色和作用。

核心场景:构建一个电商小程序的用户购物流程

想象一下,我们正在开发一个名为"优品汇"的电商小程序。用户可以浏览商品、查看详情、加入购物车、下单支付、以及跳转到合作的客服小程序。这个流程几乎涵盖了 <navigator> 的所有核心功能。

准备工作:项目结构与 pages.json

请在你的 uni-app 项目中,确保有如下的目录结构,并将 pages.json 文件配置如下。这为我们所有的导航场景提供了基础。

目录结构 (部分):

perl 复制代码
├── pages
│   ├── index
│   │   └── index.vue
│   ├── product
│   │   ├── list.vue
│   │   └── detail.vue
│   ├── order
│   │   ├── list.vue
│   │   └── detail.vue
│   ├── payment
│   │   └── success.vue
│   └── tabBar
│       ├── cart
│       │   └── cart.vue
│       └── my
│           └── my.vue
├── static
│   └── ...
└── pages.json

pages.json 配置:

json 复制代码
{
	"pages": [
		{
			"path": "pages/index/index",
			"style": { "navigationBarTitleText": "优品汇首页" }
		},
		{
			"path": "pages/product/list",
			"style": { "navigationBarTitleText": "商品列表" }
		},
		{
			"path": "pages/product/detail",
			"style": { "navigationBarTitleText": "商品详情" }
		},
		{
			"path": "pages/order/list",
			"style": { "navigationBarTitleText": "我的订单" }
		},
		{
			"path": "pages/order/detail",
			"style": { "navigationBarTitleText": "订单详情" }
		},
		{
			"path": "pages/payment/success",
			"style": { "navigationBarTitleText": "支付成功" }
		},
		{
			"path": "pages/tabBar/cart/cart",
			"style": { "navigationBarTitleText": "购物车" }
		},
		{
			"path": "pages/tabBar/my/my",
			"style": { "navigationBarTitleText": "我的" }
		}
	],
	"globalStyle": {
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "优品汇",
		"navigationBarBackgroundColor": "#F8F8F8",
		"backgroundColor": "#F8F8F8"
	},
	"tabBar": {
		"list": [
			{
				"pagePath": "pages/index/index",
				"text": "首页"
			},
			{
				"pagePath": "pages/tabBar/cart/cart",
				"text": "购物车"
			},
			{
				"pagePath": "pages/tabBar/my/my",
				"text": "我的"
			}
		]
	}
}

场景一:从首页进入商品列表页(基础跳转与交互定制)

用户故事: 用户点击首页"限时抢购"入口,平滑跳转到商品列表页,并能看到清晰的点击反馈。

1. 首页 pages/index/index.vue (源页面)

html 复制代码
<template>
	<view class="content">
		<view class="promo-section">
			<!-- 
			  这是一个典型的页面跳转。
			  我们在这里定制了用户交互的每一个细节。
			-->
			<navigator
				url="/pages/product/list?activityId=promo123&from=home"
				open-type="navigate"
				hover-class="promo-hover"
				:hover-start-time="50"
				:hover-stay-time="200"
			>
				<view class="promo-card">
					<text class="promo-title">限时抢购</text>
					<text class="promo-desc">点击查看详情</text>
				</view>
			</navigator>
		</view>
	</view>
</template>

<script>
export default {
	data() {
		return {};
	}
};
</script>

<style>
.content {
	padding: 40rpx;
}
.promo-card {
	background-color: #e54d42;
	color: white;
	padding: 60rpx 40rpx;
	border-radius: 16rpx;
	text-align: center;
	box-shadow: 0 4px 10px rgba(229, 77, 66, 0.4);
}
.promo-title {
	font-size: 48rpx;
	font-weight: bold;
}
.promo-desc {
	font-size: 28rpx;
	margin-top: 10rpx;
	opacity: 0.9;
}
/* 自定义点击效果:轻微下沉和变暗 */
.promo-hover {
	opacity: 0.9;
	transform: scale(0.98);
	transition: all 0.2s;
}
</style>

2. 商品列表页 pages/product/list.vue (目标页面)

html 复制代码
<template>
	<view class="container">
		<view v-if="activityId" class="activity-banner">
			<text>当前活动ID:{{ activityId }}</text>
			<text>来源页面:{{ fromPage }}</text>
		</view>
		<view class="product-list">
			<text>这里是商品列表...</text>
		</view>
	</view>
</template>

<script>
export default {
	data() {
		return {
			activityId: '',
			fromPage: ''
		};
	},
	// onLoad生命周期函数用于接收页面参数
	onLoad(options) {
		console.log('接收到的页面参数:', options);
		if (options.activityId) {
			this.activityId = options.activityId;
		}
		if (options.from) {
			this.fromPage = options.from;
		}
	}
};
</script>

<style>
.container {
	padding: 20rpx;
}
.activity-banner {
	background-color: #fffbe6;
	border: 1px solid #ffe58f;
	padding: 20rpx;
	border-radius: 8rpx;
	margin-bottom: 20rpx;
	display: flex;
	flex-direction: column;
}
</style>

关键属性解析:

  • url: "/pages/product/list?activityId=promo123"

    • 作用: 定义了导航的目标路径。这里我们使用了相对路径,并附带了一个查询参数 activityId,这样商品列表页(list.vue)就能通过 onLoad 生命周期函数获取到这个参数,从而展示特定活动下的商品。这是页面间通信最常用、最基础的方式。
  • open-type: "navigate"

    • 作用: 这是最标准的跳转方式,它会"保留"当前页面(首页),然后"推入"一个新的页面(商品列表页)到页面栈中。用户可以从商品列表页通过左上角的返回按钮回到首页。这符合用户"进入-返回"的心智模型。
  • hover-class: "promo-hover"

    • 作用: 极大地提升了用户体验。当用户的指尖按下这个区域时,会立即应用 .promo-hover 这个 CSS 类,提供一个即时的视觉反馈(在这里是透明度和缩放效果)。这告诉用户:"系统已经响应了你的操作"。
  • hover-start-time: 50

    • 作用: 定义了从用户按下到 hover-class 生效的延迟时间(50毫秒)。这个值可以防止用户在快速划过屏幕时不小心触发点击效果,让交互更精准。
  • hover-stay-time: 200

    • 作用: 定义了用户手指松开后,点击效果还会"停留"的时间(200毫秒)。这给用户一种流畅、不生硬的感觉,尤其是在性能稍差的设备上,可以确保用户能看到完整的点击动画。 代码解析与运行指南:
  1. 运行项目,在首页点击"限时抢购"卡片。
  2. 你会观察到卡片有轻微下沉和变暗的动画效果,这是 hover-classhover-start-timehover-stay-time 共同作用的结果。
  3. 页面会跳转到"商品列表",并且页面顶部的黄色提示框会显示出我们从 url 中传递过来的参数 activityIdfrom。这验证了 onLoad 函数成功接收了参数。
  4. 你可以点击原生导航栏的返回按钮,会返回到首页,这是 open-type="navigate" 的效果。

场景二:从商品列表跳转到 TabBar 购物车页

用户故事: 在商品列表页,用户点击悬浮的购物车图标,直接切换到底部导航的购物车页面。

1. 商品列表页 pages/product/list.vue (在场景一的基础上增加)

html 复制代码
<template>
	<view class="container">
		<!-- ... (场景一中的代码) ... -->
		<view class="product-list">
			<text>这里是商品列表...</text>
			<!-- 在这里添加一个跳转到商品详情的链接,为场景五做准备 -->
			<navigator
				url="/pages/product/detail?id=P001"
				open-type="navigate"
				class="product-item-link"
				animation-type="fade-in"
				:animation-duration="400"
			>
				<button type="default">查看商品P001详情(App有渐变动画)</button>
			</navigator>
		</view>

		<!-- 购物车悬浮按钮 -->
		<navigator
			url="/pages/tabBar/cart/cart"
			open-type="switchTab"
			hover-class="none"
		>
			<view class="fab-cart-btn">
				<text>🛒</text>
			</view>
		</navigator>
	</view>
</template>

<script>
// ... (与场景一相同) ...
export default {
	data() {
		return {
			activityId: '',
			fromPage: ''
		};
	},
	onLoad(options) {
		console.log('接收到的页面参数:', options);
		if (options.activityId) {
			this.activityId = options.activityId;
		}
		if (options.from) {
			this.fromPage = options.from;
		}
	}
};
</script>

<style>
/* ... (场景一的样式) ... */
.container {
	padding: 20rpx;
}
.activity-banner {
	background-color: #fffbe6;
	border: 1px solid #ffe58f;
	padding: 20rpx;
	border-radius: 8rpx;
	margin-bottom: 20rpx;
	display: flex;
	flex-direction: column;
}
.product-item-link {
	margin-top: 40rpx;
}
.fab-cart-btn {
	position: fixed;
	bottom: 100rpx;
	right: 40rpx;
	width: 100rpx;
	height: 100rpx;
	background-color: #007aff;
	border-radius: 50%;
	display: flex;
	justify-content: center;
	align-items: center;
	font-size: 50rpx;
	color: white;
	box-shadow: 0 4px 12px rgba(0, 122, 255, 0.4);
}
</style>

2. 购物车页 pages/tabBar/cart/cart.vue (目标页面)

html 复制代码
<template>
	<view>
		<view class="title">购物车</view>
		<text>这里是您的购物车页面。</text>
	</view>
</template>

代码解析与运行指南:

  1. 从首页进入商品列表页。
  2. 点击右下角的蓝色圆形购物车按钮。
  3. 应用会立即切换到"购物车"Tab,并且底部的 TabBar 会高亮"购物车"项。
  4. 核心观察点: 此时,你无法通过返回手势或返回按钮回到"商品列表页"。这是因为 open-type="switchTab" 清空了所有非 TabBar 的页面栈,确保了导航的扁平化。
  5. hover-class="none" 确保了点击这个图标按钮时,它本身不会有任何多余的视觉变化。

场景三:下单成功后,使用 redirectreLaunch

用户故事: 用户支付成功后,可以选择"查看订单"(不希望再返回支付页)或"返回首页"(开始一次全新的会话)。

1. 支付成功页 pages/payment/success.vue

html 复制代码
<template>
	<view class="container">
		<view class="icon-success">✔</view>
		<text class="status-text">支付成功!</text>
		<view class="button-area">
			<!-- 
			  使用 reLaunch 返回首页。
			  这会清空所有页面栈,只留下首页。
			-->
			<navigator url="/pages/index/index" open-type="reLaunch">
				<button class="plain-btn">返回首页</button>
			</navigator>

			<!-- 
			  使用 redirect 跳转到订单页。
			  这会关闭当前页面,用订单列表页替换它。
			-->
			<navigator url="/pages/order/list" open-type="redirect">
				<button type="primary">查看订单</button>
			</navigator>
		</view>
	</view>
</template>

<script>
export default {
	data() {
		return {};
	}
};
</script>

<style>
.container {
	display: flex;
	flex-direction: column;
	align-items: center;
	padding-top: 150rpx;
}
.icon-success {
	font-size: 120rpx;
	color: #09bb07;
	border: 5px solid #09bb07;
	border-radius: 50%;
	width: 180rpx;
	height: 180rpx;
	display: flex;
	justify-content: center;
	align-items: center;
}
.status-text {
	font-size: 40rpx;
	margin-top: 40rpx;
	margin-bottom: 80rpx;
}
.button-area {
	display: flex;
	width: 100%;
	justify-content: space-around;
}
.plain-btn {
	background-color: white;
	border: 1px solid #ccc;
}
</style>

2. 订单列表页 pages/order/list.vue (目标页面)

html 复制代码
<template>
	<view>
		<text>这是您的订单列表。</text>
	</view>
</template>

代码解析与运行指南:

  1. 为了模拟,你可以先手动跳转到支付成功页(例如,在首页加一个临时的 <navigator url="/pages/payment/success">)。
  2. 测试 redirect 点击"查看订单"按钮。页面会跳转到订单列表。此时,点击导航栏返回按钮 ,你会发现你回到了进入支付成功页之前的那个页面 (比如首页),而不是支付成功页。这证明了 redirect 成功地替换了页面栈中的当前页。
  3. 测试 reLaunch 重新进入支付成功页。这次点击"返回首页"按钮。页面会跳转到首页。此时,页面栈被完全清空,你无法返回到任何之前的页面,就像刚打开小程序一样。

场景四:navigateBack, targethover-stop-propagation

用户故事: 在订单详情页,用户可以返回多级页面、跳转到客服小程序,并与页面内复杂组件进行无干扰的交互。

1. 订单详情页 pages/order/detail.vue

为了模拟此场景,你需要手动按顺序打开页面:首页 -> 我的(Tab) -> [添加一个按钮跳转到订单列表] -> [订单列表页添加按钮跳转到订单详情]。这样才能构造出足够深的页面栈。

html 复制代码
<template>
	<view class="container">
		<text class="title">订单详情</text>
		
		<!-- 场景4.1: 返回多级页面 -->
		<view class="card">
			<text>假设我们的页面路径是: 我的 -> 订单列表 -> 订单详情。</text>
			<text>点击下方按钮将直接返回"我的"页面。</text>
			<navigator open-type="navigateBack" :delta="2">
				<button type="default">返回"我的" (返回2级)</button>
			</navigator>
		</view>

		<!-- 场景4.2: 跳转到外部小程序 -->
		<view class="card">
			<text>点击下方按钮,将打开合作的客服小程序。</text>
			<!-- 注意: app-id需要真实存在且在manifest.json中配置 -->
			<navigator
				target="miniProgram"
				open-type="navigate"
				app-id="wxf8e0cf27a58a75e2" 
				path="pages/index/index"
			>
				<button type="primary">联系客服(跳转到"小程序示例")</button>
			</navigator>
		</view>
		
		<!-- 场景4.3: 阻止事件冒泡 -->
		<view class="card">
			<text>下方卡片整体可点击,但内部按钮的点击效果不会影响卡片。</text>
			<navigator url="/pages/product/detail?id=P002" class="product-card" hover-class="card-hover">
				<view class="product-info">
					<text>可点击的商品卡片</text>
					<text>点击空白处或文字,整个卡片会有点击效果。</text>
				</view>
				<!-- @click.native 确保在navigator内button的点击事件能触发 -->
				<button class="fav-button" :hover-stop-propagation="true" @click.native="onFavorite">
					收藏
				</button>
			</navigator>
		</view>

	</view>
</template>

<script>
export default {
	methods: {
		onFavorite() {
			uni.showToast({
				title: '收藏成功!',
				icon: 'none'
			});
			// 这里会执行收藏逻辑,但不会触发父级navigator的hover效果
		}
	}
}
</script>

<style>
.container { padding: 20rpx; }
.card { margin-bottom: 30rpx; padding: 20rpx; border: 1px solid #eee; border-radius: 8rpx; }
.title { font-size: 36rpx; font-weight: bold; margin-bottom: 20rpx; }
button { margin-top: 20rpx; }

.product-card {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 20rpx;
	background-color: #f9f9f9;
	border-radius: 8rpx;
}
.card-hover {
	background-color: #e0e0e0;
}
.fav-button {
	margin: 0; /* 重置按钮的默认margin */
	background-color: #ffc107;
	color: white;
}
</style>

代码解析与运行指南:

  1. navigateBack & delta: 确保你有至少3层页面栈(如 我的 -> 订单列表 -> 订单详情)。在订单详情页点击"返回'我的'"按钮,你会看到应用跳过了订单列表,直接回到了"我的"页面。
  2. target="miniProgram": 点击"联系客服"按钮。如果你的环境支持(如微信开发者工具或真机)且 app-id 有效(这里用的是微信官方的"小程序示例"appid),它会拉起另一个小程序。
  3. hover-stop-propagation:
    • 先点击"可点击的商品卡片"的文字或空白区域,整个卡片背景会变灰(card-hover 效果)。
    • 然后,只点击黄色的"收藏"按钮 。你会看到按钮有自己的点击效果,并且弹出了"收藏成功!"的提示,但整个卡片的背景不会 变灰。这证明了 hover-stop-propagation 成功阻止了点击态的冒泡。

场景五:为 App 端定制页面过渡动画

用户故事: 在 App 端,从商品列表点击某个商品时,希望商品详情页以"渐显"的方式出现,而不是平台默认的侧滑。

1. 商品列表页 pages/product/list.vue (在场景二的代码中已包含)

我们复用场景二中的代码,重点关注那个跳转到详情页的 <navigator>

html 复制代码
<!-- 在 pages/product/list.vue 中 -->
<navigator
    url="/pages/product/detail?id=P001"
    open-type="navigate"
    class="product-item-link"
    <!-- 以下两个属性是本场景核心 -->
    animation-type="fade-in"
    :animation-duration="400"
>
    <button type="default">查看商品P001详情(App有渐变动画)</button>
</navigator>

2. 商品详情页 pages/product/detail.vue (目标页面)

html 复制代码
<template>
	<view>
		<text>商品详情页</text>
		<text v-if="productId">商品ID: {{ productId }}</text>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				productId: ''
			}
		},
		onLoad(options) {
			this.productId = options.id
		}
	}
</script>

代码解析与运行指南:

  1. 重要: 此效果仅在 App 端可见。请使用 HBuilderX 将项目运行到手机或模拟器上。在小程序开发者工具或 H5 端,这两个属性会被忽略。
  2. 在 App 中,从首页进入商品列表页。
  3. 点击"查看商品P001详情"按钮。
  4. 你会观察到,商品详情页不是从右侧滑入的,而是以一个持续 400 毫秒的渐显动画出现。返回时,它会以"渐隐"动画消失。
  5. 这证明了 animation-typeanimation-duration 成功地定制了 App 端的原生转场动画,提升了应用的独特性和品质感。
相关推荐
今禾2 分钟前
" 当Base64遇上Blob,图像转换不再神秘,让你的网页瞬间变身魔法画布! "
前端·数据可视化
华科云商xiao徐7 分钟前
高性能小型爬虫语言与代码示例
前端·爬虫
十盒半价7 分钟前
深入理解 React useEffect:从基础到实战的全攻略
前端·react.js·trae
攀登的牵牛花8 分钟前
Electron+Vue+Python全栈项目打包实战指南
前端·electron·全栈
iccb10138 分钟前
我是如何实现在线客服系统的极致稳定性与安全性的
前端·javascript·后端
一大树9 分钟前
Vue3祖孙组件通信方法总结
前端·vue.js
不要进入那温驯的良夜10 分钟前
跨平台UI自动化-Appium
前端
海底火旺11 分钟前
以一个简单的React应用理解数据绑定的重要性
前端·css·react.js
不要进入那温驯的良夜12 分钟前
浏览器技术原理
前端
在泡泡里12 分钟前
前端 mcp 的使用
前端