navBar.vue 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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,'leftWidth0':leftWidth=='0rpx'}]" 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',`len${PickerDataLens}`]" 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_left" />
  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. computed
  65. } from 'vue';
  66. const emit = defineEmits(['GoBack','CommonFilterData']);
  67. const props = defineProps({
  68. height: { //高度
  69. type: String,
  70. default: () => ''
  71. },
  72. leftWidth: { //导航栏左侧插槽宽度
  73. type: String,
  74. default: () => '96rpx'
  75. },
  76. rightWidth: { //导航栏右侧插槽宽度
  77. type: String,
  78. default: () => '96rpx'
  79. },
  80. title: { //标题
  81. type: String,
  82. default: () => ''
  83. },
  84. showHeaderborder: { //是否显示边框 默认不显示
  85. type: Boolean,
  86. default: false
  87. },
  88. backgroundColor: { //背景色
  89. type: String,
  90. default: () => '#FFFFFF'
  91. },
  92. backPath: { //返回路径
  93. type: String,
  94. default: () => ''
  95. },
  96. onlyTitle: { //是否只显示标题
  97. type: Boolean,
  98. default: true
  99. },
  100. filterPickerData: { //条件选择器
  101. type: Array,
  102. default: () => []
  103. },
  104. tabList: { //tabs
  105. type: Array,
  106. default: () => []
  107. },
  108. defaultTabValue:{
  109. type: [String,Number],
  110. default: () => ''
  111. },//默认值
  112. defaultTabBtnValue:{
  113. type: [String,Number],
  114. default: () => ''
  115. },//默认值
  116. tabBtns: { //tabBtns
  117. type: Array,
  118. default: () => []
  119. },
  120. showHeadSearchInput:{//是否显示头部搜索框
  121. type: Boolean,
  122. default: true
  123. },
  124. rightType:{//头部右侧内容
  125. type: String,
  126. default: 'searchBox'
  127. },
  128. showFilterPicker: { //是否显示条件选择器
  129. type: Boolean,
  130. default: false
  131. },
  132. showTabs: { //是否显示条件选择器tabs
  133. type: Boolean,
  134. default: false
  135. },
  136. showTabBtns: { //是否显示条件选择器tabBtns
  137. type: Boolean,
  138. default: false
  139. }
  140. });
  141. const state = reactive({
  142. searchWord: '', //关键字
  143. filterOpts:{
  144. valueIndex:0,
  145. index:0,
  146. filterPickerValue: []
  147. },//条件选择器选中的值
  148. tabsSelected: '', //tabs 默认选中
  149. tabBtnSelected: '',//tabBtns 默认选中
  150. searchInputStyles: { //搜索框样式
  151. borderColor: '#DCDFE6',
  152. color: '#333333'
  153. },
  154. searchInputPlaceholderStyle: 'color: #C0C4CC;fontSize: 28rpx' //搜索框样式
  155. })
  156. const PickerDataLens = computed(()=>{
  157. return props.filterPickerData.filter(item=>item?.list?.length > 0)?.length || 0;
  158. })
  159. watch(()=>props.tabList,(newVal, oldVal)=>{
  160. if(newVal){
  161. const firstValue = props?.tabList?.[0]?.value ?? '';
  162. state.tabsSelected = props.defaultTabValue!==''?props.defaultTabValue : firstValue; //tab 默认值
  163. }
  164. })
  165. watch(()=>props.tabBtns,(newVal, oldVal)=>{
  166. if(newVal){
  167. const firstValue = props?.tabBtns?.[0]?.value ?? '';
  168. state.tabBtnSelected = props.defaultTabBtnValue!==''?props.defaultTabBtnValue : firstValue; //tab 默认值
  169. }
  170. })
  171. //关键字搜索
  172. const HandleSearchInput = (e) => {
  173. state.searchWord = e;
  174. CommonFilterData('search');
  175. }
  176. //切换条件选择器 index:数组filterPickerData索引
  177. const ChangeFilterPicker = (e, index) => {
  178. const valueIndex = e.detail.value; //下拉框选中值的索引
  179. const selectedValue = props.filterPickerData?.[index]?.list?.[valueIndex]?.value ?? '';
  180. state.filterOpts.filterPickerValue[index] = selectedValue;
  181. //处理下一级默认值
  182. for(let i = 0; i < props.filterPickerData.length; i++){
  183. if(i > index){
  184. const list = props.filterPickerData?.[i]?.list || [];
  185. state.filterOpts.filterPickerValue[i] = list.length > 0 ? list[0].value : '';
  186. }
  187. }
  188. state.filterOpts.valueIndex = valueIndex;
  189. state.filterOpts.index = index;
  190. CommonFilterData('filterPicker');
  191. }
  192. //tabs切换
  193. const SelectTabsValue = (value) => {
  194. state.tabsSelected = value;
  195. CommonFilterData('tabs');
  196. }
  197. //tabBtns切换
  198. const SelectTabBtnsValue = (value) => {
  199. state.tabBtnSelected = value;
  200. CommonFilterData('tabBtns');
  201. }
  202. //条件发生改变进行数据查询
  203. const CommonFilterData = (type) => {
  204. emit('CommonFilterData',{
  205. searchWord:state.searchWord,
  206. filterOpts:state.filterOpts,
  207. tabsSelected:state.tabsSelected,
  208. tabBtnSelected:state.tabBtnSelected
  209. },type);
  210. }
  211. const GoBack = () => {
  212. if (props.backPath == 'myIndex') {
  213. uni.redirectTo({
  214. url: '/pages/my/index'
  215. });
  216. } else if (props.backPath == 'workspace') { //跳转工作台
  217. uni.redirectTo({
  218. url: '/pages/workspace/index'
  219. });
  220. } else {
  221. emit('GoBack');
  222. }
  223. }
  224. onMounted(() => {
  225. const firstValue = props?.tabList?.[0]?.value ?? '';
  226. const firstBtnValue = props?.tabBtns?.[0]?.value || '';
  227. state.tabsSelected = props.defaultTabValue!==''?props.defaultTabValue : firstValue; //tab 默认值
  228. state.tabBtnSelected = props.defaultTabBtnValue!==''?props.defaultTabBtnValue : firstBtnValue; //tabBtns 默认值
  229. state.filterOpts.filterPickerValue = props.filterPickerData.map(item => item?.defaultValue ?? '');
  230. })
  231. </script>
  232. <style scoped lang="scss">
  233. :deep(.uni-navbar__header) {
  234. padding: 0;
  235. position: relative;
  236. z-index: 999;
  237. }
  238. :deep(.uni-navbar__header-container) {
  239. padding: 0;
  240. }
  241. </style>