search.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. <template>
  2. <view :class="['search-box' , searchType === 2 ? '': 'search-box-bg']" @touchmove="(e) => {return false}"
  3. :style="{'top': setTop(statusBarHeight)}">
  4. <view class="search-frame">
  5. <text v-if="[1,2].includes(searchType)" class="search-icon iconfont_nvue">&#xe653;</text>
  6. <text v-else class="back-icon search-icon iconfont_nvue" @click.stop="$emit('clearSearch')">&#xe65f;</text>
  7. <!-- <image class="search-icon" src="/static/map/icon_01.png" mode="scaleToFill"></image> -->
  8. <input confirm-type="search" ref="searchInputRef" class="search-input" :auto-blur="true" type="text"
  9. placeholder="请输入关键字" v-model="keyWord_" @focus="onSearchFocus()" @blur="onSearchBlur()"
  10. @confirm="getMapList" />
  11. </view>
  12. <!-- 选择类型 -->
  13. <!-- <view :class="['classify-box', searchType === 2 ? '': 'hide-element' ]" ref="searchTypeRefs2">
  14. <block v-for="(item , index) in classifyTree" :key="`hot__${index}`">
  15. <view class="classify-item" v-if="index<5" :key="`hot_${index}`" @click.stop="selectHotClassify(item)">
  16. <image class="classify-icon" :src="item.icon" mode="aspectFit" />
  17. <text class="classify-text nvue-one-row">{{item.name}}</text>
  18. </view>
  19. <view class="classify-item" v-if="index === 5" @click.stop="onMore()" :key="`hot_${index}`">
  20. <image class="classify-icon" src="@/static/map/moer.png" mode="aspectFit">
  21. </image>
  22. <text class="classify-text">更多</text>
  23. </view>
  24. </block>
  25. </view> -->
  26. <!-- 选择类型 -->
  27. <view :class="['hot-classify', searchType === 2 ? '': 'hide-element' ]" ref="searchTypeRefs2">
  28. <scroll-view class="scroll-condition" scroll-x="true" :show-scrollbar="false">
  29. <template v-if=" classifyTree && classifyTree.length > 0 ">
  30. <block v-for="(item , index) in classifyTree" :key="`hot__${index}`">
  31. <view v-if="index<5" class="auto-width-item hot-item" @click.stop="selectHotClassify(item)"
  32. :key="`hot_${index}`">
  33. <image class="hot-item-icon" :src="item.icon"></image>
  34. <text class="hot-item-text">{{item.name}}</text>
  35. </view>
  36. </block>
  37. <view class="auto-width-item hot-item" @click.stop="onMore()" :key="`hot_${index}`">
  38. <image class="hot-item-icon" src="@/static/map/moer.png"></image>
  39. <text class="hot-item-text">更多</text>
  40. </view>
  41. </template>
  42. </scroll-view>
  43. </view>
  44. <!-- 筛选条件 -->
  45. <view :class="['condition-box' , [3,4,5].includes(searchType) ? '' : 'hide-element' ]">
  46. <!-- v-if="[3,4,5].includes(searchType)" -->
  47. <view class="condition-label" ref="searchTypeRefs345_lable"
  48. :style="{'border-bottom-width':[3,4,5].includes(searchType)?'1rpx':0}">
  49. <view class="label-item" @click.stop="selectLabel(searchType , 4)">
  50. <text
  51. class="label-item-text nvue-one-row">{{ activeDistance ? activeDistance.label : '位置距离' }}</text>
  52. <image :class="['label-item-icon' , searchType === 4 ? 'active-condition-label' : '' ]"
  53. src="@/static/map/icon_02.png" mode="aspectFit"></image>
  54. </view>
  55. <view class="label-item" @click.stop="selectLabel(searchType , 5)">
  56. <text
  57. class="label-item-text nvue-one-row">{{ activeClassify ? activeClassify.name : '全部分类' }}</text>
  58. <image :class="['label-item-icon' , searchType === 5 ? 'active-condition-label' : '' ]"
  59. src="@/static/map/icon_02.png" mode="scaleToFill"></image>
  60. </view>
  61. </view>
  62. <view
  63. :class="[ searchType === 3 &&classifyTree && classifyTree[oneClassifyIndex] &&classifyTree[oneClassifyIndex].children.length >0 ? '': 'hide-element' ]">
  64. <view class="condition-val" ref="searchTypeRefs3">
  65. <scroll-view class="scroll-condition" scroll-x="true" :show-scrollbar="false">
  66. <template v-if=" classifyTree[oneClassifyIndex] && classifyTree[oneClassifyIndex].children">
  67. <block v-for="(item , index) in classifyTree[oneClassifyIndex].children"
  68. :key="`classify__${index}`">
  69. <view class="auto-width-item" :key="`classify_${index}`">
  70. <view class="auto-width-item-v" @click.stop="selectHotClassify(item)">
  71. <text
  72. :class="['condition-item-v' , activeClassify && activeClassify.id=== item.id ? 'active-condition-val' : '' ]">
  73. {{ item.name }}
  74. </text>
  75. </view>
  76. </view>
  77. </block>
  78. </template>
  79. </scroll-view>
  80. </view>
  81. </view>
  82. <view :class="['condition-list-box' , [4,5].includes(searchType) ? '' : 'hide-element' ]">
  83. <!-- 选择范围 -->
  84. <view ref="searchTypeRefs4" :class="['distance-list', searchType === 4 ? '': 'hide-element' ]">
  85. <scroll-view :style="{'height': 260 +'px' }" class="scroll-condition" scroll-y="true"
  86. :show-scrollbar="false">
  87. <block v-for="(item , index) in distance" :key="`Distance__${index}`">
  88. <text :key="`Distance_${index}`"
  89. :class="['condition-list-item' , 'nvue-one-row' , activeDistance && activeDistance.value === item.value ? 'active-condition' : '']"
  90. @click.stop="onSelectClassify(3,item , index)">
  91. {{item.label}}
  92. </text>
  93. </block>
  94. </scroll-view>
  95. </view>
  96. <view ref="searchTypeRefs5" :class="['condition-list', searchType === 5 ? '': 'hide-element' ]">
  97. <view class="condition-list-left">
  98. <scroll-view :style="{'height': 260 +'px' }" class="scroll-condition" scroll-y="true"
  99. :show-scrollbar="false">
  100. <block v-for="(item , index) in classifyTree" :key="`classifyTree__${index}`">
  101. <text :key="`classifyTree_${index}`"
  102. :class="['condition-list-item' , 'nvue-one-row' , oneClassifyIndex === index? 'active-condition' : '']"
  103. @click.stop="onSelectClassify(1,item , index)">
  104. {{item.name}}
  105. </text>
  106. </block>
  107. </scroll-view>
  108. </view>
  109. <view class="condition-list-right">
  110. <scroll-view :style="{'height': 260 +'px' }" class="scroll-condition" scroll-y="true"
  111. :show-scrollbar="false">
  112. <template
  113. v-if="classifyTree && classifyTree[oneClassifyIndex] && classifyTree[oneClassifyIndex].children">
  114. <block v-for="(item , index) in classifyTree[oneClassifyIndex].children || []"
  115. :key="`classifyTree_two__${index}`">
  116. <text :key="`classifyTree_two_${index}`"
  117. :class="['condition-list-item' , 'nvue-one-row' , activeClassify && activeClassify.id === item.id ? 'active-condition' : '']"
  118. @click.stop="onSelectClassify(2,item , index)">
  119. {{item.name}}
  120. </text>
  121. </block>
  122. </template>
  123. </scroll-view>
  124. </view>
  125. </view>
  126. </view>
  127. </view>
  128. </view>
  129. </template>
  130. <script>
  131. import Mixin from "./Mixin.js"
  132. export default {
  133. mixins: [Mixin],
  134. // classifyList
  135. data() {
  136. return {
  137. keyWord_: '',
  138. oldValue: '',
  139. awaitTime: 0,
  140. awaitInterval: null,
  141. distance: [{
  142. label: '1公里',
  143. value: 1000
  144. }, {
  145. label: '3公里',
  146. value: 3000
  147. }, {
  148. label: '5公里',
  149. value: 5000
  150. }],
  151. }
  152. },
  153. mounted() {
  154. // setTimeout(()=> {
  155. // console.log('aaaaa = ' , 1)
  156. // this.blur()
  157. // },3000)
  158. },
  159. watch: {
  160. keyWord: {
  161. handler: function(newK) {
  162. this.keyWord_ = newK || ''
  163. },
  164. immediate: true
  165. },
  166. searchType: {
  167. handler: function(newS, oldS) {
  168. this.$nextTick(() => {
  169. setTimeout(() => {
  170. this.animationStyle(newS, oldS)
  171. const Refs2 = this.$refs.searchTypeRefs2;
  172. const Refs345_lable = this.$refs.searchTypeRefs345_lable;
  173. const Refs3 = this.$refs.searchTypeRefs3;
  174. const Refs4 = this.$refs.searchTypeRefs4;
  175. const Refs5 = this.$refs.searchTypeRefs5;
  176. //
  177. switch (newS) {
  178. case 1:
  179. this.animationStyle(Refs2, {
  180. height: 0 + 'px'
  181. }, 70)
  182. this.animationStyle(Refs3, {
  183. height: 0 + 'px'
  184. }, 70)
  185. this.animationStyle(Refs345_lable, {
  186. height: 0 + 'px'
  187. }, 70)
  188. this.animationStyle(Refs4, {
  189. height: 0 + 'px'
  190. }, 70)
  191. this.animationStyle(Refs5, {
  192. height: 0 + 'px'
  193. }, 70)
  194. break;
  195. case 2:
  196. this.animationStyle(Refs3, {
  197. height: 0 + 'px'
  198. }, 70)
  199. this.animationStyle(Refs345_lable, {
  200. height: 0 + 'px'
  201. }, 70)
  202. this.animationStyle(Refs4, {
  203. height: 0 + 'px'
  204. }, 70)
  205. this.animationStyle(Refs5, {
  206. height: 0 + 'px'
  207. }, 70)
  208. this.animationStyle(Refs2, {
  209. height: uni.upx2px(80) + 'px'
  210. }, 70, 80)
  211. break;
  212. case 3:
  213. this.animationStyle(Refs2, {
  214. height: 0 + 'px'
  215. }, 70)
  216. this.animationStyle(Refs4, {
  217. height: 0 + 'px'
  218. }, 70)
  219. this.animationStyle(Refs5, {
  220. height: 0 + 'px'
  221. }, 70)
  222. this.animationStyle(Refs345_lable, {
  223. height: uni.upx2px(92) + 'px'
  224. }, 70, 71)
  225. this.animationStyle(Refs3, {
  226. height: uni.upx2px(121) + 'px'
  227. }, 70, 141)
  228. break;
  229. case 4:
  230. this.animationStyle(Refs2, {
  231. height: 0 + 'px'
  232. }, 70)
  233. this.animationStyle(Refs3, {
  234. height: 0 + 'px'
  235. }, 70)
  236. this.animationStyle(Refs5, {
  237. height: 0 + 'px'
  238. }, 70)
  239. this.animationStyle(Refs4, {
  240. height: 260 + 'px'
  241. }, 70, 71)
  242. break;
  243. case 5:
  244. this.animationStyle(Refs2, {
  245. height: 0 + 'px'
  246. }, 70)
  247. this.animationStyle(Refs3, {
  248. height: 0 + 'px'
  249. }, 70)
  250. this.animationStyle(Refs4, {
  251. height: 0 + 'px'
  252. }, 70)
  253. this.animationStyle(Refs5, {
  254. height: 260 + 'px'
  255. }, 70, 70)
  256. break;
  257. }
  258. }, 100)
  259. })
  260. },
  261. immediate: true
  262. }
  263. },
  264. methods: {
  265. /**
  266. * el: 动画元素
  267. * styles 动画样式
  268. * duration 动画时间
  269. * delay 延迟动画
  270. */
  271. animationStyle(el, styles, duration, delay) {
  272. if (el) {
  273. const animation = weex.requireModule('animation')
  274. animation.transition(el, {
  275. styles: styles,
  276. duration: duration, //ms
  277. needLayout: true,
  278. timingFunction: 'linear',
  279. delay: delay || 0 //ms
  280. }, res => {})
  281. }
  282. },
  283. setTop(statusBarH) {
  284. // console.log('statusBarH = ', statusBarH)
  285. const searchH = uni.upx2px(30)
  286. return searchH + statusBarH + 'px'
  287. },
  288. blur() {
  289. // console.log('-------------------999-----------------')
  290. try {
  291. this.$refs.searchInputRef.blur()
  292. } catch (e) {
  293. //TODO handle the exception
  294. // console.log('------------------------------------', e)
  295. }
  296. uni.hideKeyboard()
  297. },
  298. onSearchFocus() {
  299. this.$emit('onSearchFocus')
  300. },
  301. selectHotClassify(item) {
  302. // console.log('000')
  303. this.$emit('selectHotClassify', item)
  304. },
  305. onSelectClassify(level, val, index) {
  306. this.$emit('onSelectClassify', {
  307. level: level,
  308. val: val,
  309. index: index
  310. })
  311. },
  312. selectLabel(avt, num) {
  313. const n = avt === num ? 3 : num;
  314. this.$emit('selectLabel', n)
  315. },
  316. getMapList(kw) {
  317. if (kw.detail.value === this.oldValue) return false;
  318. this.oldValue = kw.detail.value
  319. this.$emit('onSearch', kw.detail.value);
  320. // try {
  321. // clearInterval(this.awaitInterval)
  322. // } catch (e) {
  323. // //TODO handle the exception
  324. // }
  325. // if (kw.detail.value === this.oldValue) return false;
  326. // this.awaitTime = 0;
  327. // this.awaitInterval = setInterval(() => {
  328. // this.awaitTime = this.awaitTime + 100;
  329. // if (this.awaitTime >= 500) {
  330. // if (kw.detail.value) {
  331. // this.$emit('onSearch', kw.detail.value);
  332. // }
  333. // this.oldValue = kw.detail.value
  334. // clearInterval(this.awaitInterval)
  335. // }
  336. // }, 100)
  337. }
  338. }
  339. }
  340. </script>
  341. <style lang="scss" scoped>
  342. @import url("./style.scss");
  343. .iconfont_nvue {
  344. font-family: iconfont_nvue;
  345. }
  346. .search-box-bg {
  347. background: #fff !important;
  348. }
  349. .search-box {
  350. position: absolute;
  351. z-index: 2;
  352. left: 20rpx;
  353. right: 20rpx;
  354. // margin-top: 20rpx;
  355. border-radius: 20rpx;
  356. background-color: transparent;
  357. .search-frame {
  358. background-color: #fff;
  359. height: 89rpx;
  360. flex-direction: row;
  361. align-items: center;
  362. padding: 10rpx 20rpx;
  363. border-radius: 20rpx;
  364. box-shadow: 0px 10rpx 16rpx 0px rgba(153, 153, 153, 0.15);
  365. .back-icon {
  366. transform: rotate(-180deg) !important;
  367. }
  368. .search-icon {
  369. font-size: 40rpx;
  370. color: #666666;
  371. width: 40rpx;
  372. // height: 40rpx;
  373. transform: rotate(0deg);
  374. }
  375. .search-input {
  376. // background-color: skyblue;
  377. height: 60rpx;
  378. flex: 1;
  379. font-size: 28rpx;
  380. margin-left: 10rpx;
  381. }
  382. }
  383. .classify-box {
  384. width: 710rpx;
  385. height: 0;
  386. flex-direction: row;
  387. align-items: center;
  388. justify-content: space-between;
  389. padding: 0 30rpx;
  390. overflow: hidden;
  391. .classify-item {
  392. width: 106rpx;
  393. height: 100rpx;
  394. flex-direction: column;
  395. align-items: center;
  396. justify-content: space-between;
  397. .classify-icon {
  398. width: 64rpx;
  399. height: 64rpx;
  400. }
  401. .classify-text {
  402. font-size: 24rpx;
  403. font-family: PingFang SC, PingFang SC-Bold;
  404. font-weight: 700;
  405. color: #373737;
  406. }
  407. }
  408. // @keyframes identifier {
  409. // to {
  410. // height: 0;
  411. // }
  412. // from {
  413. // height: 179rpx;
  414. // }
  415. // }
  416. }
  417. .condition-box {
  418. .condition-label {
  419. height: 0;
  420. flex-direction: row;
  421. align-items: center;
  422. //
  423. // border-bottom-color: $zw-border-color;
  424. border-bottom-color: #EDEDED;
  425. border-bottom-style: solid;
  426. // border-bottom: 1rpx solid $zw-border-color;
  427. padding: 0 30rpx;
  428. .label-item {
  429. min-width: 200rpx;
  430. flex-direction: row;
  431. align-items: center;
  432. &+.label-item {
  433. margin-left: 20rpx;
  434. }
  435. .label-item-text {
  436. max-width: 400rpx;
  437. // width: 130rpx;
  438. font-size: 28rpx;
  439. line-height: 36rpx;
  440. font-family: PingFang SC, PingFang SC-Regular;
  441. font-weight: 400;
  442. text-align: center;
  443. color: #1a1a1a;
  444. padding-right: 4px;
  445. }
  446. .label-item-icon {
  447. width: 28rpx;
  448. height: 28rpx;
  449. transform: rotate(0deg);
  450. transition: transform 1s;
  451. }
  452. .active-condition-label {
  453. transform: rotate(-180deg);
  454. }
  455. }
  456. }
  457. .condition-val {
  458. height: 0;
  459. flex-direction: row;
  460. align-items: center;
  461. padding: 0 30rpx;
  462. .scroll-condition {
  463. flex-direction: row;
  464. }
  465. .auto-width-item-v {
  466. padding-right: 30rpx;
  467. .condition-item-v {
  468. height: 70rpx;
  469. background-color: #f2f2f2;
  470. line-height: 70rpx;
  471. padding: 0 30rpx;
  472. font-size: 26rpx;
  473. font-family: PingFang SC, PingFang SC-Regular;
  474. font-weight: 400;
  475. text-align: center;
  476. color: #666666;
  477. border-radius: 10rpx;
  478. border-width: 1rpx;
  479. border-style: solid;
  480. border-color: #f2f2f2;
  481. }
  482. .active-condition-val {
  483. border-color: #4fc9d5;
  484. background-color: #EDFDFD;
  485. color: #3FB9D4;
  486. }
  487. }
  488. }
  489. .condition-list-box {
  490. .distance-list {
  491. height: 0;
  492. overflow: hidden;
  493. .active-condition {
  494. background-color: #fff;
  495. color: #3DB8D2;
  496. }
  497. }
  498. .condition-list {
  499. height: 0;
  500. overflow: hidden;
  501. // padding: 0 30rpx;
  502. flex-direction: row;
  503. justify-content: space-between;
  504. align-items: stretch;
  505. .condition-list-left {
  506. width: 200rpx;
  507. background-color: #f9f9f9;
  508. .scroll-condition {
  509. background-color: #f9f9f9;
  510. }
  511. .active-condition {
  512. background-color: #fff;
  513. }
  514. }
  515. .condition-list-right {
  516. // width: 430rpx;
  517. flex: 1;
  518. background-color: #fff;
  519. .active-condition {
  520. color: #3DB8D2;
  521. }
  522. }
  523. }
  524. .condition-list-item {
  525. height: 80rpx;
  526. line-height: 80rpx;
  527. font-size: 28rpx;
  528. font-family: PingFang SC, PingFang SC-Regular;
  529. font-weight: 400;
  530. color: #666666;
  531. padding: 0 20rpx;
  532. }
  533. }
  534. }
  535. }
  536. .hot-classify {
  537. height: 80rpx;
  538. padding-top: 20rpx;
  539. .scroll-condition {
  540. flex-direction: row;
  541. .hot-item {
  542. margin-right: 20rpx;
  543. background-color: #fff;
  544. padding: 0 25rpx;
  545. height: 56rpx;
  546. border-radius: 30rpx;
  547. flex-direction: row;
  548. align-items: center;
  549. justify-content: center;
  550. .hot-item-icon {
  551. width: 30rpx;
  552. height: 30rpx;
  553. }
  554. .hot-item-text {
  555. padding-left: 8rpx;
  556. font-size: 28rpx;
  557. }
  558. }
  559. }
  560. }
  561. </style>