navBar.vue 6.6 KB

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