Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
DCloud
hello uni-app x
提交
c58f613c
H
hello uni-app x
项目概览
DCloud
/
hello uni-app x
通知
5992
Star
90
Fork
162
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
18
列表
看板
标记
里程碑
合并请求
1
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
H
hello uni-app x
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
18
Issue
18
列表
看板
标记
里程碑
合并请求
1
合并请求
1
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
c58f613c
编写于
9月 16, 2023
作者:
H
hdx
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: custom-tab-bar
上级
4ab10b70
变更
9
显示空白变更内容
内联
并排
Showing
9 changed file
with
553 addition
and
2 deletion
+553
-2
pages.json
pages.json
+11
-2
pages/tabBar/template.uvue
pages/tabBar/template.uvue
+16
-0
pages/template/custom-tab-bar/custom-tab-bar-tab1.uvue
pages/template/custom-tab-bar/custom-tab-bar-tab1.uvue
+60
-0
pages/template/custom-tab-bar/custom-tab-bar-tab2.uvue
pages/template/custom-tab-bar/custom-tab-bar-tab2.uvue
+24
-0
pages/template/custom-tab-bar/custom-tab-bar.uvue
pages/template/custom-tab-bar/custom-tab-bar.uvue
+150
-0
pages/template/custom-tab-bar2/custom-tab-bar2-tab1.uvue
pages/template/custom-tab-bar2/custom-tab-bar2-tab1.uvue
+60
-0
pages/template/custom-tab-bar2/custom-tab-bar2-tab2.uvue
pages/template/custom-tab-bar2/custom-tab-bar2-tab2.uvue
+24
-0
pages/template/custom-tab-bar2/custom-tab-bar2.uvue
pages/template/custom-tab-bar2/custom-tab-bar2.uvue
+208
-0
static/fonts/uni-icon.ttf
static/fonts/uni-icon.ttf
+0
-0
未找到文件。
pages.json
浏览文件 @
c58f613c
...
...
@@ -895,7 +895,16 @@
"navigationBarTitleText"
:
"自定义导航栏"
,
"navigationStyle"
:
"custom"
}
},
{
"path"
:
"pages/template/custom-tab-bar/custom-tab-bar"
,
"style"
:
{
"navigationBarTitleText"
:
"自定义TabBar"
}
},
{
"path"
:
"pages/template/custom-tab-bar2/custom-tab-bar2"
,
"style"
:
{
"navigationBarTitleText"
:
"自定义TabBar2"
}
}
],
"globalStyle"
:
{
...
...
pages/tabBar/template.uvue
浏览文件 @
c58f613c
...
...
@@ -167,6 +167,22 @@ export default {
open: false,
pages: [] as Page[],
},
{
id: 'custom-tab-bar',
url: 'custom-tab-bar',
name: '自定义TabBar',
open: false,
pages: [
{
name: '滚动切换图标',
url:'custom-tab-bar'
},
{
name: '凹口',
url:'custom-tab-bar2'
},
] as Page[],
},
{
id: 'calendar',
url: 'calendar',
...
...
pages/template/custom-tab-bar/custom-tab-bar-tab1.uvue
0 → 100644
浏览文件 @
c58f613c
<template>
<list-view ref="listView" class="list" :rebound="false" :scroll-y="true" @scrolltolower="loadData()"
@scroll="onScroll">
<list-item class="list-item" v-for="(item, index) in dataList" :key="index">
<text class="title">{{item.title}}</text>
</list-item>
</list-view>
</template>
<script>
type ListItem = {
title : string
}
export default {
data() {
return {
dataList: [] as ListItem[]
}
},
created() {
this.loadData()
},
methods: {
loadData() {
let index = this.dataList.length
for (let i = 0; i < 10; i++) {
this.dataList.push({
title: index.toString(),
} as ListItem)
index++
}
},
onScroll(e : ScrollEvent) {
uni.$emit('tabchange', e.detail.scrollTop)
},
scrollTop(top : number) {
(this.$refs["listView"] as Element).setAttribute('scrollTop', top)
}
}
}
</script>
<style>
.list {
flex: 1;
background-color: #ffffff;
}
.list-item {
flex-direction: row;
padding: 30px;
border-bottom: 1px solid #dbdbdb;
}
.title {
font-size: 16px;
text-align: center;
}
</style>
\ No newline at end of file
pages/template/custom-tab-bar/custom-tab-bar-tab2.uvue
0 → 100644
浏览文件 @
c58f613c
<template>
<view class="page">
<button type="primary">登录</button>
</view>
</template>
<script>
export default {
data() {
return {
}
},
created() {
},
methods: {
}
}
</script>
<style>
.page {
padding: 15px;
}
</style>
\ No newline at end of file
pages/template/custom-tab-bar/custom-tab-bar.uvue
0 → 100644
浏览文件 @
c58f613c
<template>
<view class="custom-tab-bar">
<view class="tab-view">
<tab1 ref="tab1" v-if="tabList[0].init" v-show="selectedIndex==0"></tab1>
<tab2 ref="tab2" v-if="tabList[1].init" v-show="selectedIndex==1"></tab2>
</view>
<view class="tab-bar">
<view class="tab-item">
<view ref="tab-item1" class="tab-item-content" @click="onTabClick(0)">
<text class="tab-item-icon tab-item-icon1 uni-icon" :class="selectedIndex==0 ? 'tab-item-text-active' : ''">
{{'\ue6be'}}
</text>
</view>
</view>
<view class="tab-item">
<view ref="tab-item2" class="tab-item-content" @click="onTabClick(1)">
<text class="tab-item-icon uni-icon"
:class="selectedIndex==1 ? 'tab-item-text-active' : ''">{{'\ue699'}}</text>
<text class="tab-item-text" :class="selectedIndex==1 ? 'tab-item-text-active' : ''">
我的
</text>
</view>
</view>
</view>
</view>
</template>
<script>
import tab1 from './custom-tab-bar-tab1.uvue';
import tab2 from './custom-tab-bar-tab2.uvue';
type TabItem = {
init : boolean,
preload : boolean,
}
export default {
components: {
tab1,
tab2
},
data() {
return {
tabList: [
{
init: false
} as TabItem,
{
init: false
} as TabItem,
] as TabItem[],
selectedIndex: -1
}
},
onLoad() {
uni.$on('tabchange', this.onTabPageEvent)
},
onUnload() {
uni.$off('tabchange', this.onTabPageEvent)
},
onReady() {
this.setSelectedIndex(0)
},
methods: {
onTabClick(index : number) {
this.setSelectedIndex(index);
if (index == 0) {
(this.$refs["tab1"]! as ComponentPublicInstance).$callMethod('scrollTop', 0)
}
},
onTabPageEvent(top : number) {
const tabItem1 = this.$refs["tab-item1"] as Element
const angle = top < 50 ? 0 : 180
tabItem1.style.setProperty('transform', `rotate(${angle}deg)`)
},
setSelectedIndex(index : number) {
if (this.selectedIndex === index) {
return
}
if (!this.tabList[index].init) {
this.tabList[index].init = true
}
this.selectedIndex = index
}
}
}
</script>
<style>
@font-face {
font-family: "UniIcon";
src: url('@/static/fonts/uni-icon.ttf');
}
.uni-icon {
font-family: "UniIcon";
font-size: 18px;
font-style: normal;
}
.custom-tab-bar {
flex: 1;
}
.tab-view {
flex: 1;
}
.tab-view-item {
flex: 1;
}
.tab-bar {
background-color: #f0f0f0;
border-top: 1px solid #dbdbdb;
flex-direction: row;
height: 56px;
}
.tab-item {
flex: 1;
}
.tab-item-content {
margin: auto;
transition: transform 0.3s;
}
.tab-item-icon {
color: #555;
font-size: 12px;
text-align: center;
}
.tab-item-text {
color: #555;
font-size: 12px;
margin-top: 4px;
text-align: center;
}
.tab-item-text-active {
color: #007AFF;
}
.tab-item-icon1 {
font-size: 30px !important;
font-weight: bold;
}
</style>
\ No newline at end of file
pages/template/custom-tab-bar2/custom-tab-bar2-tab1.uvue
0 → 100644
浏览文件 @
c58f613c
<template>
<list-view ref="listView" class="list" :rebound="false" :scroll-y="true" @scrolltolower="loadData()"
@scroll="onScroll">
<list-item class="list-item" v-for="(item, index) in dataList" :key="index">
<text class="title">{{item.title}}</text>
</list-item>
</list-view>
</template>
<script>
type ListItem = {
title : string
}
export default {
data() {
return {
dataList: [] as ListItem[]
}
},
created() {
this.loadData()
},
methods: {
loadData() {
let index = this.dataList.length
for (let i = 0; i < 10; i++) {
this.dataList.push({
title: index.toString(),
} as ListItem)
index++
}
},
onScroll(e : ScrollEvent) {
uni.$emit('tabchange', e.detail.scrollTop)
},
scrollTop(top : number) {
(this.$refs["listView"] as Element).setAttribute('scrollTop', top)
}
}
}
</script>
<style>
.list {
flex: 1;
background-color: #ffffff;
}
.list-item {
flex-direction: row;
padding: 30px;
border-bottom: 1px solid #dbdbdb;
}
.title {
font-size: 16px;
text-align: center;
}
</style>
\ No newline at end of file
pages/template/custom-tab-bar2/custom-tab-bar2-tab2.uvue
0 → 100644
浏览文件 @
c58f613c
<template>
<view class="page">
<button type="primary">登录</button>
</view>
</template>
<script>
export default {
data() {
return {
}
},
created() {
},
methods: {
}
}
</script>
<style>
.page {
padding: 15px;
}
</style>
\ No newline at end of file
pages/template/custom-tab-bar2/custom-tab-bar2.uvue
0 → 100644
浏览文件 @
c58f613c
<template>
<view class="tabs">
<view class="tab-view">
<tab1 ref="tab1" v-if="tabList[0].init" v-show="selectedIndex==0"></tab1>
<tab2 ref="tab2" v-if="tabList[1].init" v-show="selectedIndex==1"></tab2>
</view>
<view ref="tabbar" class="tab-bar">
<view class="tab-item">
<view ref="tab-item1" class="tab-item-content" @click="onTabClick(0)">
<text class="tab-item-icon uni-icon"
:class="selectedIndex==0 ? 'tab-item-text-active' : ''">{{'\ue644'}}</text>
<text class="tab-item-text" :class="selectedIndex==0 ? 'tab-item-text-active' : ''">
列表
</text>
</view>
</view>
<view class="tab-item">
<view class="btn-plus">
<text class="btn-plus-text">+</text>
</view>
</view>
<view class="tab-item">
<view ref="tab-item2" class="tab-item-content" @click="onTabClick(1)">
<text class="tab-item-icon uni-icon"
:class="selectedIndex==1 ? 'tab-item-text-active' : ''">{{'\ue699'}}</text>
<text class="tab-item-text" :class="selectedIndex==1 ? 'tab-item-text-active' : ''">
我的
</text>
</view>
</view>
</view>
</view>
</template>
<script>
import tab1 from './custom-tab-bar2-tab1.uvue';
import tab2 from './custom-tab-bar2-tab2.uvue';
type TabItem = {
init : boolean,
preload : boolean,
}
export default {
components: {
tab1,
tab2
},
data() {
return {
tabList: [
{
init: false
} as TabItem,
{
init: false
} as TabItem,
] as TabItem[],
selectedIndex: -1,
$tabBarNode: null as null | Element,
$tabBarWidth: 0,
$drawContext: null as null | DrawableContext,
}
},
onReady() {
this.setSelectedIndex(0)
this.$tabBarNode = this.$refs['tabbar'] as Element
this.$tabBarWidth = this.$tabBarNode?.offsetWidth as number
this.$drawContext = this.$tabBarNode!.getDrawableContext()
this._renderTabbar()
},
methods: {
onTabClick(index : number) {
this.setSelectedIndex(index);
if (index == 0) {
(this.$refs["tab1"]! as ComponentPublicInstance).$callMethod('scrollTop', 0)
}
},
onTabPageEvent(top : number) {
const tabItem1 = this.$refs["tabs-item1"] as Element
const angle = top < 50 ? '0deg' : '180deg'
tabItem1.style.setProperty('transform', `rotate(${angle})`)
},
setSelectedIndex(index : number) {
if (this.selectedIndex === index) {
return
}
if (!this.tabList[index].init) {
this.tabList[index].init = true
}
this.selectedIndex = index
},
_renderTabbar() {
const ctx = this.$drawContext!
ctx.reset()
const plus_radius = 40
const plus_offset = 8
const center = this.$tabBarWidth / 2
const plus_x1 = center - plus_radius - plus_offset
const plus_x2 = center + plus_radius + plus_offset
const center_x = center
const center_y = plus_radius
const control_o = 15
const control_x = 4.8
const control_y = 4.4
ctx.fillStyle = "dodgerblue"
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(plus_x1, 0)
ctx.bezierCurveTo(plus_x1 + control_o, 0, plus_x1 + control_x, center_y - control_y, center, center_y)
ctx.bezierCurveTo(plus_x2 - control_x, center_y - control_y, plus_x2 - control_o, 0, plus_x2, 0)
ctx.lineTo(plus_x2, 0)
ctx.lineTo(this.$tabBarWidth, 0)
ctx.lineTo(this.$tabBarWidth, 52)
ctx.lineTo(0, 52)
ctx.lineTo(0, 0)
ctx.stroke()
ctx.fill()
ctx.update()
}
}
}
</script>
<style>
@font-face {
font-family: "UniIcon";
src: url('@/static/fonts/uni-icon.ttf');
}
.uni-icon {
font-family: "UniIcon";
font-size: 16px;
font-style: normal;
}
.tabs {
flex: 1;
background-color: #fff;
overflow: visible;
}
.tab-view {
flex: 1;
}
.tab-view-item {
flex: 1;
}
.tab-bar {
flex-direction: row;
height: 56px;
overflow: visible;
}
.tab-item {
flex: 1;
position: relative;
overflow: visible;
}
.tab-item-content {
margin: auto;
}
.tab-item-icon {
color: #ccc;
font-size: 12px;
text-align: center;
margin-bottom: 4px;
}
.tab-item-text {
color: #ccc;
font-size: 12px;
text-align: center;
}
.tab-item-text-active {
color: #fff;
}
.btn-plus {
width: 70px;
height: 70px;
border-radius: 50px;
background-color: #FE5722;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.5);
margin-left: auto;
margin-right: auto;
margin-top: -35px;
align-items: center;
justify-content: center;
overflow: visible;
}
.btn-plus-text {
color: #fff;
font-size: 32px;
}
</style>
\ No newline at end of file
static/fonts/uni-icon.ttf
0 → 100644
浏览文件 @
c58f613c
文件已添加
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录