navBar.vue 7.5 KB

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