更新记录

1.0.5(2025-12-23) 下载此版本

修复顶部和底部Navigation已知bug

1.0.4(2025-12-11) 下载此版本

新增drawer方向:上下和居中

1.0.3(2025-12-09) 下载此版本

允许部分配置启用

查看更多

平台兼容性

uni-app(4.66)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 快应用-华为 快应用-联盟

liaction-scaffold

一个基于UniApp和Vue 2的Flutter Scaffold-like组件,提供高度可配置的AppBar、顶部导航栏、底部导航栏、抽屉、悬浮操作按钮(FAB)和SnackBar等功能。

功能特性

  • AppBar: 可配置的顶部应用栏,支持自定义标题、背景色、文字颜色等
  • 顶部导航栏: 基于liaction-tabs的可滚动顶部导航
  • 底部导航栏: 基于liaction-tabs的底部导航
  • 抽屉: 支持左、右、上、下、居中五种位置,可配置宽度、高度、点击遮罩是否关闭、主内容是否偏移等
  • 悬浮操作按钮(FAB): 支持自定义图标、颜色、大小等
  • SnackBar: 底部提示条,支持自定义消息、操作按钮、持续时间等
  • 高度可配置: 所有组件都支持丰富的配置选项
  • 支持插槽: 所有组件都支持自定义插槽

安装

在UniApp项目中通过插件市场安装,或直接将组件复制到项目中。

配置选项

AppBar配置

属性 类型 默认值 说明
show Boolean true 是否显示AppBar
title String '' 标题文本
backgroundColor String '#007AFF' 背景颜色
textColor String '#FFFFFF' 文字颜色
height String '44px' 高度
paddingTop String '0px' 顶部内边距
leading String '' 返回按钮图标
actions Array [] 操作按钮数组
onBackPress Function null 返回按钮点击回调,返回true表示拦截返回

TopNavigation配置

属性 类型 默认值 说明
show Boolean true 是否显示顶部导航
items Array [] 导航项数组,每个项包含id、text、badge等属性
currentIndex Number 0 当前激活的索引
backgroundColor String '#FFFFFF' 背景颜色
textColor String '#666666' 文字颜色
activeColor String '#007AFF' 激活项颜色
height String '48px' 高度
scrollEnabled Boolean false 是否支持滚动
tabsConfig Object {} liazction-tabs组件配置

tabsConfig配置

属性 类型 默认值 说明
showBadge Boolean false 是否显示徽章
badgePosition String 'top-right' 徽章位置
badgeSize String '16px' 徽章大小
badgeColor String '#FF3B30' 徽章颜色
tabFlex Boolean true 是否平均分配宽度
indicatorWidth String 'content' 指示器宽度
tabFontSize String '14px' 文字大小
tabPadding String '12px' 内边距

BottomNavigationBar配置

属性 类型 默认值 说明
show Boolean true 是否显示底部导航
items Array [] 导航项数组,每个项包含id、text、badge等属性
currentIndex Number 0 当前激活的索引
backgroundColor String '#FFFFFF' 背景颜色
textColor String '#666666' 文字颜色
activeColor String '#007AFF' 激活项颜色
height String '50px' 高度
scrollEnabled Boolean false 是否支持滚动
tabsConfig Object {} liazction-tabs组件配置

Drawer配置

属性 类型 默认值 说明
position String 'left' 抽屉位置,可选值:'left'、'right'、'top'、'bottom'、'center'
width String 动态计算 抽屉宽度,默认根据位置计算:左右抽屉75%,上下抽屉100%,居中抽屉80%
height String 动态计算 抽屉高度,默认根据位置计算:左右抽屉100%,上下抽屉50%,居中抽屉50%
closeOnOverlayClick Boolean true 点击遮罩是否关闭抽屉
mainContentShift Object { left: true, right: true, top: false, bottom: false } 控制主内容是否偏移,可配置不同位置的偏移行为

FloatingActionButton配置

属性 类型 默认值 说明
show Boolean true 是否显示FAB
icon String '+' 图标
backgroundColor String '#007AFF' 背景颜色
color String '#FFFFFF' 文字颜色
size String '56px' 大小
right String '20px' 距离右侧距离
bottom String '20px' 距离底部距离

SnackBar配置

属性 类型 默认值 说明
message String '' 消息文本
action Object null 操作按钮配置,包含text和onClick属性
backgroundColor String '#333333' 背景颜色
textColor String '#FFFFFF' 文字颜色
duration Number 3000 持续时间(毫秒)

其他配置

属性 类型 默认值 说明
backgroundColor String '#FFFFFF' 页面背景颜色
enableStatusBarVar Boolean true 是否启用状态栏高度CSS变量
enableWindowBottomVar Boolean true 是否启用窗口底部CSS变量

事件说明

事件名 参数 说明
appbar-leading-click AppBar返回按钮点击事件
appbar-action-click index AppBar操作按钮点击事件,返回索引
top-nav-click index 顶部导航项点击事件,返回索引
bottom-nav-click index 底部导航项点击事件,返回索引
fab-click FAB点击事件
snackbar-action-click SnackBar操作按钮点击事件

插槽说明

插槽名 说明
default 主内容区域
drawer 抽屉内容
appbar AppBar完整自定义内容
appbar-leading AppBar左侧内容
appbar-title AppBar标题内容
appbar-actions AppBar右侧操作按钮
top-nav 顶部导航自定义内容
bottom-nav 底部导航自定义内容
fab FAB自定义内容

方法说明

方法名 参数 说明
openDrawer 打开抽屉
closeDrawer 关闭抽屉
toggleDrawer 切换抽屉状态
displaySnackBar options 显示SnackBar,options包含message、action、duration等属性
hideSnackBar 隐藏SnackBar

使用示例

抽屉位置示例

展示如何配置不同位置的抽屉:

<template>
  <liaction-scaffold 
    :app-bar="appBar"
    :drawer="drawer"
    ref="scaffoldRef"
  >
    <!-- 内容区域 -->
    <view class="content">
      <text class="title">抽屉位置演示</text>
      <view class="button-group">
        <button type="primary" @click="openLeftDrawer">打开左侧抽屉</button>
        <button type="primary" @click="openRightDrawer">打开右侧抽屉</button>
        <button type="primary" @click="openTopDrawer">打开顶部抽屉</button>
        <button type="primary" @click="openBottomDrawer">打开底部抽屉</button>
        <button type="primary" @click="openCenterDrawer">打开居中抽屉</button>
      </view>
    </view>

    <!-- 抽屉内容 -->
    <template #drawer>
      <view class="drawer-content">
        <text class="drawer-title">{{ drawer.position }} 抽屉</text>
        <text class="drawer-info">这是一个{{ drawer.position }}位置的抽屉示例</text>
        <button type="default" @click="$refs.scaffoldRef.closeDrawer">关闭抽屉</button>
      </view>
    </template>
  </liaction-scaffold>
</template>

<script>
export default {
  data() {
    return {
      // AppBar配置
      appBar: {
        show: true,
        title: '抽屉位置演示',
        backgroundColor: '#007AFF',
        textColor: '#FFFFFF'
      },

      // 抽屉配置
      drawer: {
        position: 'left',
        closeOnOverlayClick: true,
        mainContentShift: {
          left: true,
          right: true,
          top: false,
          bottom: false
        }
      }
    }
  },
  methods: {
    // 打开左侧抽屉
    openLeftDrawer() {
      this.drawer.position = 'left';
      this.$refs.scaffoldRef.openDrawer();
    },

    // 打开右侧抽屉
    openRightDrawer() {
      this.drawer.position = 'right';
      this.$refs.scaffoldRef.openDrawer();
    },

    // 打开顶部抽屉
    openTopDrawer() {
      this.drawer.position = 'top';
      this.$refs.scaffoldRef.openDrawer();
    },

    // 打开底部抽屉
    openBottomDrawer() {
      this.drawer.position = 'bottom';
      this.$refs.scaffoldRef.openDrawer();
    },

    // 打开居中抽屉
    openCenterDrawer() {
      this.drawer.position = 'center';
      this.$refs.scaffoldRef.openDrawer();
    }
  }
}
</script>

<style scoped>
.content {
  padding: 20px;
  background-color: #F5F5F5;
  min-height: 100vh;
}

.title {
  font-size: 20px;
  font-weight: 600;
  text-align: center;
  margin-bottom: 30px;
  display: block;
}

.button-group {
  display: flex;
  flex-direction: column;
  gap: 15px;
  padding: 0 20px;
}

.button-group button {
  margin: 0;
}

.drawer-content {
  padding: 20px;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
}

.drawer-title {
  font-size: 24px;
  font-weight: 600;
  color: #007AFF;
}

.drawer-info {
  font-size: 16px;
  color: #666666;
  text-align: center;
}
</style>

普通示例

<template>
  <liaction-scaffold 
    :app-bar="appBar"
    :top-navigation="topNavigation"
    :bottom-navigation-bar="bottomNavigationBar"
    :drawer="drawer"
    :floating-action-button="floatingActionButton"
    :background-color="backgroundColor"
    @appbar-leading-click="handleAppBarLeadingClick"
    @appbar-action-click="handleAppBarActionClick"
    @top-nav-click="handleTopNavClick"
    @bottom-nav-click="handleBottomNavClick"
    @fab-click="handleFabClick"
  >
    <!-- 内容区域 -->
    <view class="content">
      <text>这是页面内容</text>
    </view>

    <!-- 抽屉内容 -->
    <template #drawer>
      <view class="drawer-content">
        <text>抽屉内容</text>
      </view>
    </template>
  </liaction-scaffold>
</template>

<script>
export default {
  data() {
    return {
      // AppBar配置
      appBar: {
        show: true,
        title: 'Scaffold演示',
        backgroundColor: '#007AFF',
        textColor: '#FFFFFF'
      },

      // 顶部导航配置
      topNavigation: {
        show: true,
        items: [
          { id: 'all', text: '全部' },
          { id: 'news', text: '新闻' },
          { id: 'sports', text: '体育' }
        ],
        tabsConfig: {
          showBadge: false,
          tabFlex: true
        }
      },

      // 底部导航配置
      bottomNavigationBar: {
        show: true,
        items: [
          { id: 'home', text: '首页'},
          { id: 'category', text: '分类' },
          { id: 'profile', text: '我的' }
        ],
        tabsConfig: {
          showBadge: true
        }
      },

      // 抽屉配置
      drawer: {
        width: '280px',
        position: 'left',
        closeOnOverlayClick: true
      },

      // FAB配置
      floatingActionButton: {
        show: true,
        icon: '+',
        backgroundColor: '#007AFF'
      },

      // 背景颜色
      backgroundColor: '#F5F5F5'
    }
  },
  methods: {
    // 处理AppBar返回按钮点击
    handleAppBarLeadingClick() {
      console.log('AppBar返回按钮点击');
    },

    // 处理AppBar操作按钮点击
    handleAppBarActionClick(index) {
      console.log('AppBar操作按钮点击,索引:', index);
    },

    // 处理顶部导航点击
    handleTopNavClick(index) {
      console.log('顶部导航点击,索引:', index);
    },

    // 处理底部导航点击
    handleBottomNavClick(index) {
      console.log('底部导航点击,索引:', index);
    },

    // 处理FAB点击
    handleFabClick() {
      console.log('FAB点击');
      // 显示SnackBar
      this.$refs.scaffoldRef.displaySnackBar({
        message: 'FAB被点击了',
        duration: 2000
      });
    }
  }
}
</script>

自定义底部导航

<liaction-scaffold 
  :app-bar="appBar"
  :bottom-navigation-bar="bottomNavigationBar"
  @bottom-nav-click="handleBottomNavClick"
>
  <!-- 主内容 -->
  <view class="content">
    <text>这是页面内容</text>
  </view>

  <!-- 自定义底部导航 -->
  <template #bottom-nav>
    <view class="custom-bottom-nav">
      <view 
        v-for="(item, index) in bottomNavigationBar.items" 
        :key="item.id"
        class="nav-item"
        :class="{ 'active': bottomNavigationBar.currentIndex === index }"
        @click="handleBottomNavItemClick(index)"
      >
        <uni-icons 
          :type="item.icon" 
          size="24px" 
          :color="bottomNavigationBar.currentIndex === index ? '#007AFF' : '#666666'"
        ></uni-icons>
        <text 
          class="nav-text"
          :style="{
            color: bottomNavigationBar.currentIndex === index ? '#007AFF' : '#666666'
          }"
        >
          {{ item.text }}
        </text>
      </view>
    </view>
  </template>
</liaction-scaffold>

<style scoped>
.custom-bottom-nav {
  display: flex;
  align-items: center;
  justify-content: space-around;
  height: 50px;
  background-color: #FFFFFF;
  box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1);
  width: 100%;
}

.nav-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 1;
  height: 100%;
  cursor: pointer;
  padding: 4px 0;
}

.nav-item.active {
  font-weight: 600;
}

.nav-text {
  font-size: 12px;
  margin-top: 4px;
}
</style>

<script>
export default {
  data() {
    return {
      appBar: {
        title: '自定义底部导航',
        backgroundColor: '#007AFF',
        textColor: '#FFFFFF'
      },
      bottomNavigationBar: {
        items: [
          { id: 'home', icon: 'home', text: '首页' },
          { id: 'category', icon: 'grid', text: '分类' },
          { id: 'discover', icon: 'compass', text: '发现' },
          { id: 'profile', icon: 'person', text: '我的' }
        ],
        currentIndex: 0
      }
    }
  },
  methods: {
    handleBottomNavClick(index) {
      console.log('底部导航点击,索引:', index);
    },
    handleBottomNavItemClick(index) {
      // 更新当前索引
      this.bottomNavigationBar.currentIndex = index;
      // 触发事件
      this.$emit('bottom-nav-click', index);
      // 可以在这里添加额外的逻辑
      console.log('自定义底部导航项点击,索引:', index);
    }
  }
}
</script>

自定义顶部导航

<liaction-scaffold 
  :app-bar="appBar"
  :top-navigation="topNavigation"
  @top-nav-click="handleTopNavClick"
>
  <!-- 主内容 -->
  <view class="content">
    <text>这是页面内容</text>
  </view>

  <!-- 自定义顶部导航 -->
  <template #top-nav>
    <view class="custom-top-nav">
      <view 
        v-for="(item, index) in topNavigation.items" 
        :key="item.id"
        class="nav-item"
        :class="{ 'active': topNavigation.currentIndex === index }"
        @click="handleTopNavItemClick(index)"
      >
        <text 
          class="nav-text"
          :style="{
            color: topNavigation.currentIndex === index ? '#007AFF' : '#666666',
            fontWeight: topNavigation.currentIndex === index ? '600' : 'normal'
          }"
        >
          {{ item.text }}
        </text>
      </view>
    </view>
  </template>
</liaction-scaffold>

<style scoped>
.custom-top-nav {
  display: flex;
  align-items: center;
  height: 48px;
  background-color: #FFFFFF;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  overflow-x: auto;
  white-space: nowrap;
}

.nav-item {
  display: flex;
  align-items: center;
  padding: 0 20px;
  height: 100%;
  cursor: pointer;
  position: relative;
}

.nav-item.active {
  border-bottom: 2px solid #007AFF;
}

.nav-text {
  font-size: 14px;
}

</style>

<script>
export default {
  data() {
    return {
      appBar: {
        title: '自定义顶部导航',
        backgroundColor: '#007AFF',
        textColor: '#FFFFFF'
      },
      topNavigation: {
        items: [
          { id: 'all', text: '全部' },
          { id: 'news', text: '新闻' },
          { id: 'sports', text: '体育' },
          { id: 'entertainment', text: '娱乐' },
          { id: 'technology', text: '科技' }
        ],
        currentIndex: 0
      }
    }
  },
  methods: {
    handleTopNavClick(index) {
      console.log('顶部导航点击,索引:', index);
    },
    handleTopNavItemClick(index) {
      // 更新当前索引
      this.topNavigation.currentIndex = index;
      // 触发事件
      this.$emit('top-nav-click', index);
    }
  }
}
</script>

自定义AppBar

您可以通过appbar插槽来自定义整个AppBar的外观和行为,实现完全个性化的顶部导航栏:

<liaction-scaffold 
  :app-bar="appBar"
  @appbar-leading-click="handleAppBarLeadingClick"
>
  <!-- 主内容 -->
  <view class="content">
    <text>这是页面内容</text>
  </view>

  <!-- 自定义AppBar -->
  <template #appbar>
    <view class="custom-appbar">
      <!-- 左侧返回按钮 -->
      <view class="appbar-left" @click="handleAppBarLeadingClick">
        <uni-icons type="back" size="24px" color="#FFFFFF"></uni-icons>
      </view>

      <!-- 中间标题 -->
      <view class="appbar-center">
        <text class="appbar-title">自定义AppBar</text>
      </view>

      <!-- 右侧操作按钮 -->
      <view class="appbar-right">
        <uni-icons type="search" size="24px" color="#FFFFFF" @click="handleSearchClick"></uni-icons>
        <uni-icons type="bell" size="24px" color="#FFFFFF" @click="handleBellClick" class="bell-icon">
          <view class="notification-badge">3</view>
        </uni-icons>
      </view>
    </view>
  </template>
</liaction-scaffold>

<style scoped>
.custom-appbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 44px;
  background: linear-gradient(90deg, #007AFF 0%, #0056B3 100%);
  padding: 0 16px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

.appbar-left,
.appbar-right {
  display: flex;
  align-items: center;
}

.appbar-left {
  width: 44px;
  height: 44px;
  justify-content: flex-start;
}

.appbar-center {
  flex: 1;
  text-align: center;
}

.appbar-title {
  color: #FFFFFF;
  font-size: 18px;
  font-weight: 600;
}

.appbar-right {
  width: 88px;
  height: 44px;
  justify-content: flex-end;
}

.bell-icon {
  position: relative;
  margin-left: 20px;
}

.notification-badge {
  position: absolute;
  top: -4px;
  right: -8px;
  background-color: #FF3B30;
  color: #FFFFFF;
  font-size: 12px;
  padding: 2px 6px;
  border-radius: 10px;
  min-width: 18px;
  text-align: center;
}
</style>

<script>
export default {
  data() {
    return {
      appBar: {
        show: true,
        backgroundColor: '#007AFF',
        textColor: '#FFFFFF'
      }
    }
  },
  methods: {
    handleAppBarLeadingClick() {
      console.log('自定义AppBar返回按钮点击');
      // 可以在这里添加返回逻辑
      // uni.navigateBack();
    },
    handleSearchClick() {
      console.log('搜索按钮点击');
    },
    handleBellClick() {
      console.log('通知按钮点击');
    }
  }
}
</script>

许可证

MIT License

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。