navBar.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <template>
  2. <!-- 头部 -->
  3. <uni-nav-bar :class="{'custom_uni_nav_bar':!onlyTitle,'custom_navbar_only_title':onlyTitle,'custom_only_title_back_icon':!showHeadSearchInput}"
  4. :height="`${height}rpx`" :backgroundColor="backgroundColor" :title="title" color="#333333" :fixed="true"
  5. :border="showHeaderborder" :statusBar="true" :leftWidth="leftWidth" :rightWidth="rightWidth">
  6. <!-- 返回按钮 -->
  7. <template v-slot:left>
  8. <uni-icons class="left_icon" type="left" color="#333333" @click="GoBack()" />
  9. </template>
  10. <!-- 表头内容 -->
  11. <view :class="['nav_head',{'only_title':!showHeadSearchInput}]" v-if="!onlyTitle">
  12. <text class="nav_title">{{title}}</text>
  13. <template v-if="showHeadSearchInput">
  14. <uni-easyinput v-if="rightType=='searchBox'" class="search_box" v-model="state.searchWord" trim="all" :styles="state.searchInputStyles"
  15. :placeholderStyle="state.searchInputPlaceholderStyle" placeholder="请输入关键字搜索" @input="HandleSearchInput">
  16. <template #left>
  17. <image src="@/static/image/overview/search.png" class="search_icon"></image>
  18. </template>
  19. </uni-easyinput>
  20. <template v-else>
  21. <slot name="headRightIcon" />
  22. </template>
  23. </template>
  24. </view>
  25. <!-- 条件选择器 -->
  26. <view class="filter_picker" v-if="showFilterPicker">
  27. <template v-for="(item,index) in filterPickerData" :key="index">
  28. <picker class="item_filter_picker" mode="selector" v-if="item?.list?.length > 0" :range="item.list" :value="item.valueIndex" range-key="label" style="width: calc((100% - 32rpx * 2) / 3);" @change="(e)=>ChangeFilterPicker(e,index)">
  29. <view class="filter_item">
  30. <text class="filter_text">{{ item?.list?.[item.valueIndex]?.label || '' }}</text>
  31. <uni-icons type="down" size="16" color="#999999"></uni-icons>
  32. </view>
  33. </picker>
  34. </template>
  35. </view>
  36. <slot name="tabs_top_content" />
  37. <!-- tabs -->
  38. <view class="scroll_tabs" v-if="showTabs && tabList.length > 0">
  39. <scroll-view class="scroll_tabs_view" scroll-x="true" scroll-left="0" :show-scrollbar="false">
  40. <view :class="['tab_item',{'selected':item.value===state.tabsSelected}]" v-for="item in tabList" :key="item.value" @click="SelectTabsValue(item.value)">
  41. {{item.label}}
  42. </view>
  43. </scroll-view>
  44. <slot name="tabs_right_content" />
  45. </view>
  46. <!-- tabs 按钮 -->
  47. <scroll-view v-if="showTabBtns && tabBtns.length > 0" class="scroll_tab_btn" scroll-x="true" scroll-left="0" :show-scrollbar="false">
  48. <slot name="tab_btns_lef" />
  49. <view :class="['tab_item',{'selected':item.value===state.tabBtnSelected}]" v-for="item in tabBtns" :key="item.value" @click="SelectTabBtnsValue(item.value)">
  50. {{item.label}}
  51. </view>
  52. </scroll-view>
  53. <slot name="tabs_bottom_content" />
  54. </uni-nav-bar>
  55. </template>
  56. <script setup>
  57. import uniNavBar from '@/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue';
  58. import uniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.vue';
  59. import uniEasyinput from '@/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue';
  60. import {
  61. reactive,
  62. onMounted,
  63. watch
  64. } from 'vue';
  65. const emit = defineEmits(['GoBack','CommonFilterData']);
  66. const props = defineProps({
  67. height: { //高度
  68. type: String,
  69. default: () => ''
  70. },
  71. leftWidth: { //导航栏左侧插槽宽度
  72. type: String,
  73. default: () => '96rpx'
  74. },
  75. rightWidth: { //导航栏右侧插槽宽度
  76. type: String,
  77. default: () => '96rpx'
  78. },
  79. title: { //标题
  80. type: String,
  81. default: () => ''
  82. },
  83. showHeaderborder: { //是否显示边框 默认不显示
  84. type: Boolean,
  85. default: false
  86. },
  87. backgroundColor: { //背景色
  88. type: String,
  89. default: () => '#FFFFFF'
  90. },
  91. backPath: { //返回路径
  92. type: String,
  93. default: () => ''
  94. },
  95. onlyTitle: { //是否只显示标题
  96. type: Boolean,
  97. default: true
  98. },
  99. filterPickerData: { //条件选择器
  100. type: Array,
  101. default: () => []
  102. },
  103. tabList: { //tabs
  104. type: Array,
  105. default: () => []
  106. },
  107. defaultTabValue:{
  108. type: [String,Number],
  109. default: () => ''
  110. },//默认值
  111. defaultTabBtnValue:{
  112. type: [String,Number],
  113. default: () => ''
  114. },//默认值
  115. tabBtns: { //tabBtns
  116. type: Array,
  117. default: () => []
  118. },
  119. showHeadSearchInput:{//是否显示头部搜索框
  120. type: Boolean,
  121. default: true
  122. },
  123. rightType:{//头部右侧内容
  124. type: String,
  125. default: 'searchBox'
  126. },
  127. showFilterPicker: { //是否显示条件选择器
  128. type: Boolean,
  129. default: false
  130. },
  131. showTabs: { //是否显示条件选择器tabs
  132. type: Boolean,
  133. default: false
  134. },
  135. showTabBtns: { //是否显示条件选择器tabBtns
  136. type: Boolean,
  137. default: false
  138. }
  139. });
  140. const state = reactive({
  141. searchWord: '', //关键字
  142. filterOpts:{
  143. valueIndex:0,
  144. index:0,
  145. filterPickerValue: []
  146. },//条件选择器选中的值
  147. tabsSelected: '', //tabs 默认选中
  148. tabBtnSelected: '',//tabBtns 默认选中
  149. searchInputStyles: { //搜索框样式
  150. borderColor: '#DCDFE6',
  151. color: '#333333'
  152. },
  153. searchInputPlaceholderStyle: 'color: #C0C4CC;fontSize: 28rpx' //搜索框样式
  154. })
  155. watch(()=>props.tabList,(newVal, oldVal)=>{
  156. if(newVal){
  157. const firstValue = props?.tabList?.[0]?.value ?? '';
  158. state.tabsSelected = props.defaultTabValue!==''?props.defaultTabValue : firstValue; //tab 默认值
  159. }
  160. })
  161. watch(()=>props.tabBtns,(newVal, oldVal)=>{
  162. if(newVal){
  163. const firstValue = props?.tabBtns?.[0]?.value ?? '';
  164. state.tabBtnSelected = props.defaultTabBtnValue!==''?props.defaultTabBtnValue : firstValue; //tab 默认值
  165. }
  166. })
  167. //关键字搜索
  168. const HandleSearchInput = (e) => {
  169. state.searchWord = e;
  170. CommonFilterData('search');
  171. }
  172. //切换条件选择器 index:数组filterPickerData索引
  173. const ChangeFilterPicker = (e, index) => {
  174. const valueIndex = e.detail.value; //下拉框选中值的索引
  175. const selectedValue = props.filterPickerData?.[index]?.list?.[valueIndex]?.value ?? '';
  176. state.filterOpts.filterPickerValue[index] = selectedValue;
  177. //处理下一级默认值
  178. for(let i = 0; i < props.filterPickerData.length; i++){
  179. if(i > index){
  180. const list = props.filterPickerData?.[i]?.list || [];
  181. state.filterOpts.filterPickerValue[i] = list.length > 0 ? list[0].value : '';
  182. }
  183. }
  184. state.filterOpts.valueIndex = valueIndex;
  185. state.filterOpts.index = index;
  186. CommonFilterData('filterPicker');
  187. }
  188. //tabs切换
  189. const SelectTabsValue = (value) => {
  190. state.tabsSelected = value;
  191. CommonFilterData('tabs');
  192. }
  193. //tabBtns切换
  194. const SelectTabBtnsValue = (value) => {
  195. state.tabBtnSelected = value;
  196. CommonFilterData('tabBtns');
  197. }
  198. //条件发生改变进行数据查询
  199. const CommonFilterData = (type) => {
  200. emit('CommonFilterData',{
  201. searchWord:state.searchWord,
  202. filterOpts:state.filterOpts,
  203. tabsSelected:state.tabsSelected,
  204. tabBtnSelected:state.tabBtnSelected
  205. },type);
  206. }
  207. const GoBack = () => {
  208. if (props.backPath == 'myIndex') {
  209. uni.redirectTo({
  210. url: '/pages/my/index'
  211. });
  212. } else if (props.backPath == 'workspace') { //跳转工作台
  213. uni.redirectTo({
  214. url: '/pages/workspace/index'
  215. });
  216. } else {
  217. emit('GoBack');
  218. }
  219. }
  220. onMounted(() => {
  221. const firstValue = props?.tabList?.[0]?.value ?? '';
  222. const firstBtnValue = props?.tabBtns?.[0]?.value || '';
  223. state.tabsSelected = props.defaultTabValue!==''?props.defaultTabValue : firstValue; //tab 默认值
  224. state.tabBtnSelected = props.defaultTabBtnValue!==''?props.defaultTabBtnValue : firstBtnValue; //tabBtns 默认值
  225. state.filterOpts.filterPickerValue = props.filterPickerData.map(item => item?.defaultValue ?? '');
  226. })
  227. </script>
  228. <style scoped lang="scss">
  229. :deep(.uni-navbar__header) {
  230. padding: 0;
  231. position: relative;
  232. z-index: 999;
  233. }
  234. :deep(.uni-navbar__header-container) {
  235. padding: 0;
  236. }
  237. </style>