wx-mini-weview
Version:
weixin UI
262 lines (233 loc) • 8.36 kB
text/typescript
/**
* 顶部导航栏组件
*
* 【返回导航规则详解】
* ------------------------------------------------------
* doBack 方法处理逻辑:
*
* 1. backUrl 和 backOpenType 参数组合情况:
* - backUrl 为空,backOpenType 任意值:
* • 尝试使用 wx.navigateBack 返回上一页
* • 如果页面栈中只有一个页面(无法返回),则跳转到首页(homePage)
*
* - backUrl 有值,backOpenType 为 'navigateBack':
* • 在页面栈中查找是否存在匹配 backUrl 的页面
* • 如果找到,计算 delta 并调用 wx.navigateBack 返回到该页面
* • 如果未找到,使用 wx.reLaunch 跳转到指定页面,避免导航断层
*
* - backUrl 有值,backOpenType 为 'navigate':
* • 使用 wx.navigateTo 保留当前页面并跳转
*
* - backUrl 有值,backOpenType 为 'redirect':
* • 使用 wx.redirectTo 关闭当前页面并跳转
*
* - backUrl 有值,backOpenType 为 'reLaunch':
* • 使用 wx.reLaunch 关闭所有页面并跳转
*
* - backUrl 有值,backOpenType 为空或非法值:
* • 默认使用 wx.redirectTo,在不增加页面栈深度的同时跳转
*
* 2. 页面匹配规则:
* - 当 backUrl 包含查询参数时,会将 URL 分为 path 和 query 两部分
* - 页面栈匹配时只比较 path 部分,忽略查询参数
* - 跳转时会保留原始的查询参数
*
* 3. 首页处理:
* - 组件提供 homePage 属性用于指定首页路径
* - 默认首页为 '/pages/yuenote/footprint/footprint'
*/
Component({
options: {
styleIsolation: 'apply-shared'
},
properties: {
title: {
type: String,
value: '导航栏',
},
backBtn: {
type: Boolean,
value: true
},
backUrl: {
type: String,
value: ''
},
backText: {
type: String,
value: ''
},
backOpenType: {
type: String, // 'navigate', 'redirect', 'reLaunch', 'navigateBack'
value: 'navigateBack'
},
homeUrl: {
type: String,
value: '/pages/yuenote/index/index'
},
navHeight: {
type: Number,
value: 44
},
backIcon: {
type: String,
value: 'bi-chevron-left'
},
homeIcon: {
type: String,
value: 'bi-house'
},
useHomeIconOnHomePage: {
type: Boolean,
value: true
},
hideBackBtnOnHomePage: {
type: Boolean,
value: true
}
},
data: {
statusBarHeight: 0,
totalHeight: 44,
backApplyIcon: 'bi-chevron-left',
isHomePage: false
},
lifetimes: {
attached() {
try {
const systemInfo = wx.getSystemInfoSync();
const statusBarHeight = systemInfo.statusBarHeight;
const totalHeight = statusBarHeight + this.properties.navHeight;
const homeUrl = this._normalizeUrl(this.properties.homeUrl);
const pages = getCurrentPages();
const currentPage = pages.length > 0 ? this._normalizeUrl(pages[pages.length-1].route) : '';
const isHomePage = currentPage === homeUrl;
this.setData({
statusBarHeight: statusBarHeight,
totalHeight: totalHeight,
backApplyIcon: this.properties.backIcon,
isHomePage: isHomePage
});
// 如果当前页面是首页且配置要使用首页图标,则设置首页图标
if (isHomePage && this.properties.useHomeIconOnHomePage) {
this.setData({ backApplyIcon: this.properties.homeIcon });
}
} catch (e) {
console.error('Failed to get system info:', e);
}
}
},
methods: {
_normalizeUrl(url) {
if (!url) return '';
return url.startsWith('/') ? url : '/' + url;
},
doBack: function() {
const pages = getCurrentPages();
const pagesLen = pages.length;
const homeUrl = this._normalizeUrl(this.properties.homeUrl);
const currentPage = pagesLen > 0 ? this._normalizeUrl(pages[pagesLen-1].route) : 'unknown';
console.log('[TopNav] 当前页面:', currentPage, '页面栈深度:', pagesLen,
'backUrl:', this.properties.backUrl || '空',
'backOpenType:', this.properties.backOpenType);
// 检查是否需要更改图标
let goingToHomePage = false;
if (!this.properties.backUrl) {
if (pagesLen <= 1) {
console.log('[TopNav] 原因:页面栈为空且无backUrl 方法:reLaunch 目标:', homeUrl);
goingToHomePage = true;
wx.reLaunch({
url: homeUrl
});
} else {
const prevPage = pagesLen > 1 ? this._normalizeUrl(pages[pagesLen-2].route) : '未知';
console.log('[TopNav] 原因:无backUrl且有上一页 方法:navigateBack 返回页面:', prevPage);
// 判断返回后是否到首页
goingToHomePage = prevPage === homeUrl;
wx.navigateBack({ delta: 1 });
}
} else {
// 标准化 backUrl
let backUrl = this._normalizeUrl(this.properties.backUrl);
goingToHomePage = backUrl === homeUrl;
let path = backUrl;
let query = '';
if (backUrl.includes('?')) {
const urlParts = backUrl.split('?');
path = urlParts[0];
query = '?' + urlParts[1];
// 再次检查是否回到首页(不含参数)
goingToHomePage = path === homeUrl;
}
switch (this.properties.backOpenType) {
case 'navigateBack':
let targetIndex = -1;
for (let i = 0; i < pagesLen; i++) {
const page = pages[i];
const pagePath = this._normalizeUrl(page.route);
if (pagePath === path) {
targetIndex = i;
break;
}
}
if (targetIndex >= 0) {
const delta = pagesLen - 1 - targetIndex;
console.log('[TopNav] 原因:页面栈中找到匹配页面 方法:navigateBack delta:', delta, '目标:', path);
wx.navigateBack({ delta: delta });
} else {
console.log('[TopNav] 原因:指定了backUrl但页面栈中无匹配 方法:reLaunch 目标:', backUrl);
wx.reLaunch({ url: backUrl });
}
break;
case 'navigate':
console.log('[TopNav] 原因:指定了navigate方式 方法:navigateTo 目标:', backUrl);
wx.navigateTo({
url: backUrl,
fail: (err) => console.error('[TopNav] navigateTo失败:', err)
});
break;
case 'redirect':
console.log('[TopNav] 原因:指定了redirect方式 方法:redirectTo 目标:', backUrl);
wx.redirectTo({
url: backUrl,
fail: (err) => console.error('[TopNav] redirectTo失败:', err)
});
break;
case 'reLaunch':
console.log('[TopNav] 原因:指定了reLaunch方式 方法:reLaunch 目标:', backUrl);
wx.reLaunch({
url: backUrl,
fail: (err) => console.error('[TopNav] reLaunch失败:', err)
});
break;
default:
console.log('[TopNav] 原因:未指定有效openType 方法:redirectTo(默认) 目标:', backUrl);
wx.redirectTo({
url: backUrl,
fail: (err) => console.error('[TopNav] redirectTo失败:', err)
});
break;
}
}
// 如果配置了使用首页图标且导航目标是首页,更新图标
if (goingToHomePage && this.properties.useHomeIconOnHomePage) {
this.setData({
backApplyIcon: this.properties.homeIcon
});
} else {
this.setData({
backApplyIcon: this.properties.backIcon
});
}
},
getTotalNavHeight: function() {
return this.data.totalHeight;
},
getStatusBarHeight: function() {
return this.data.statusBarHeight;
},
getNacvHeight: function() {
return this.properties.navHeight;
}
}
})