common\js\floating-button.js

common\js\startup-ad.js
components\ns-mp-navbar\ns-mp-navbar.vue
This commit is contained in:
2026-10-12 15:41:28 +08:00
parent 571452cd30
commit df5be6045b
3 changed files with 411 additions and 0 deletions

View File

@@ -0,0 +1,247 @@
<template>
<!--
自绘导航栏:把原生导航栏左侧的 "<" 换成 "‹ 返回" 文字
背景:微信小程序原生导航栏的返回按钮是客户端系统控件,pages.json 的任何配置、
官方 <navigation-bar> 组件(只支持 title / front-color / background-color / loading)
都无法修改它的内容。要显示"返回"二字,只能关闭原生栏后自绘。
使用前提:
1. 该页面在 pages.json 中开启 "navigationStyle": "custom"(组件只负责渲染,不自动改配置)
2. 该页面不能是 web-view 页面 —— 官方明确 "navigationStyle: custom 对 web-view 组件无效",
且 web-view 会铺满整页覆盖其他组件,自绘的导航栏不会显示
布局:组件是普通流式节点(非 fixed),放在页面顶部即可把内容自然下推。
-->
<view
v-if="visible"
class="ns-mp-navbar"
:class="{ 'is-fixed': fixed }"
:style="{ background: bgColor, paddingTop: statusBarHeight + 'px' }"
>
<view class="ns-mp-navbar__inner" :style="{ height: navBarHeight + 'px' }">
<view class="ns-mp-navbar__side">
<view
v-if="showBack && canBack"
class="ns-mp-navbar__back"
hover-class="ns-mp-navbar__back--hover"
hover-stay-time="80"
@tap="onBack"
>
<text class="iconfont icon-back_light ns-mp-navbar__arrow" :style="{ color }"></text>
<text class="ns-mp-navbar__text" :style="{ color }">{{ backText }}</text>
</view>
<slot name="left"></slot>
</view>
<view class="ns-mp-navbar__title" :style="{ color }">{{ title }}</view>
<view class="ns-mp-navbar__side ns-mp-navbar__side--right">
<slot name="right"></slot>
</view>
</view>
</view>
</template>
<script>
// 状态栏 / 胶囊信息:用于算出与原生导航栏一致的布局高度
let systemInfo = {};
let menuButtonInfo = { top: 0, height: 32, right: 0, width: 0 };
try {
systemInfo = uni.getSystemInfoSync() || {};
} catch (e) {
systemInfo = {};
}
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ || MP-HARMONY
try {
menuButtonInfo = uni.getMenuButtonBoundingClientRect() || menuButtonInfo;
} catch (e) {}
// #endif
export default {
name: 'ns-mp-navbar',
props: {
// 中间标题
title: {
type: String,
default: ''
},
// 导航栏背景色
bgColor: {
type: String,
default: '#ffffff'
},
// 文字 / 图标颜色
color: {
type: String,
default: '#000000'
},
// 返回按钮文字(原生导航栏只能显示 "<",这里可自定义)
backText: {
type: String,
default: '返回'
},
// 是否显示返回按钮
showBack: {
type: Boolean,
default: true
},
// 是否悬浮在页面之上(沉浸式页面用;false 时占文档流,会把内容往下推)
fixed: {
type: Boolean,
default: false
},
// 无页面栈时(如分享直接进入)跳转的首页地址
homePath: {
type: String,
default: '/pages/index/index'
},
// 自定义返回逻辑
customBack: {
type: Function,
default: null
},
// H5 端是否渲染(H5 由 uni-app 自带头像栏,默认不渲染,避免双导航栏)
showOnH5: {
type: Boolean,
default: false
}
},
data() {
return {
statusBarHeight: systemInfo.statusBarHeight || 20,
navBarHeight: 44,
visible: true,
// 页面栈里是否还有上级页面(无上级页面时原生导航栏也不显示返回键)
canBack: true
};
},
computed: {
// 导航栏总高度(状态栏 + 内容区),页面如需自行占位可取该值
navbarHeight() {
return this.statusBarHeight + this.navBarHeight;
}
},
created() {
// 导航栏内容区高度:MP 端按胶囊位置推算,与原生导航栏保持一致;其余端用 44
// #ifdef MP
const statusBarHeight = this.statusBarHeight;
const h = (menuButtonInfo.top - statusBarHeight) * 2 + menuButtonInfo.height;
// 兜底:胶囊信息异常时退回 44
this.navBarHeight = h > 0 ? h : 44;
// #endif
// #ifdef H5
this.visible = this.showOnH5;
// #endif
},
mounted() {
// 页面栈只有一页(分享/扫码直达)时,原生导航栏也无返回键,这里保持一致
const pages = (typeof getCurrentPages === 'function' && getCurrentPages()) || [];
this.canBack = pages.length > 1;
// 把实际总高度抛给页面,便于页面修正内容区高度,避免多出一屏空白
this.$emit('ready', this.statusBarHeight + this.navBarHeight);
},
methods: {
onBack() {
if (typeof this.customBack === 'function') {
this.customBack();
return;
}
const pages = (typeof getCurrentPages === 'function' && getCurrentPages()) || [];
if (pages.length > 1) {
uni.navigateBack();
return;
}
// 顶层页面(分享 / 扫码直接进入):回首页
uni.switchTab({
url: this.homePath,
fail: () => {
uni.reLaunch({ url: this.homePath });
}
});
}
}
};
</script>
<style scoped lang="scss">
.ns-mp-navbar {
width: 100%;
box-sizing: border-box;
}
.ns-mp-navbar.is-fixed {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 990;
}
.ns-mp-navbar__inner {
position: relative;
display: flex;
align-items: center;
width: 100%;
box-sizing: border-box;
}
.ns-mp-navbar__side {
position: relative;
z-index: 1;
display: flex;
align-items: center;
height: 100%;
min-width: 160rpx;
padding-left: 20rpx;
box-sizing: border-box;
}
.ns-mp-navbar__side--right {
justify-content: flex-end;
padding-left: 0;
padding-right: 20rpx;
}
.ns-mp-navbar__back {
display: flex;
align-items: center;
padding: 10rpx 20rpx 10rpx 0;
}
.ns-mp-navbar__back--hover {
opacity: 0.5;
}
.ns-mp-navbar__arrow {
font-size: 34rpx;
line-height: 1;
}
.ns-mp-navbar__text {
margin-left: 2rpx;
font-size: 30rpx;
line-height: 1;
}
.ns-mp-navbar__title {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 0 160rpx;
font-size: 32rpx;
line-height: 1.2;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>