header.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import { Sticky, Cell, Tag, Icon, Popup, Tabs, Tab, Dialog } from 'vant'
  2. import {
  3. RouterView,
  4. useRouter,
  5. useRoute,
  6. onBeforeRouteUpdate,
  7. onBeforeRouteLeave
  8. } from 'vue-router'
  9. import { defineComponent, onMounted, reactive, ref, watch } from 'vue'
  10. import mitt from 'mitt'
  11. import Search from '@/components/col-search'
  12. import { useLocalStorage } from '@vueuse/core'
  13. import styles from './index.module.less'
  14. import classNames from 'classnames'
  15. import SelectTag from './select-tag'
  16. import { getRandomKey, musicBuy } from '../music'
  17. import SelectSubject from './select-subject'
  18. export const mitter = mitt()
  19. const selectTagRef = ref()
  20. export default defineComponent({
  21. name: 'MusicSearchHeader',
  22. setup() {
  23. const searchInputRef = ref()
  24. localStorage.setItem('behaviorId', getRandomKey())
  25. const router = useRouter()
  26. const route = useRoute()
  27. const subjectIds = ref('')
  28. const keyword = ref('')
  29. const tagids = ref('')
  30. const tagVisibility = ref(false)
  31. const words = useLocalStorage<string[]>('music-search', [])
  32. const activeTab = ref('songe')
  33. onBeforeRouteUpdate(() => {
  34. if (route.path === '/music-songbook/search') {
  35. keyword.value = ''
  36. tagids.value = ''
  37. subjectIds.value = ''
  38. activeTab.value = 'songe'
  39. try {
  40. selectTagRef.value?.resetTags?.()
  41. } catch (error) {
  42. console.log(error)
  43. }
  44. }
  45. return true
  46. })
  47. watch(activeTab, val => {
  48. mitter.emit('changeTab', val)
  49. })
  50. const onSearch = val => {
  51. keyword.value = val
  52. const indexOf = words.value.indexOf(val)
  53. if (indexOf > -1) {
  54. words.value.splice(indexOf, 1)
  55. }
  56. if (val) {
  57. words.value.unshift(val)
  58. words.value.length = Math.min(words.value.length, 5)
  59. }
  60. mitter.emit('search', val)
  61. }
  62. const onComfirm = (tags, name = '') => {
  63. const data = Object.values(tags).flat().filter(Boolean).join(',')
  64. tagids.value = data
  65. mitter.emit('confirm', tags)
  66. tagVisibility.value = false
  67. }
  68. const onComfirmSubject = (item: any) => {
  69. // console.log('onSort', item)
  70. subject.name = item.name
  71. subject.id = item.id
  72. mitter.emit('confirmSubject', subject)
  73. subject.show = false
  74. }
  75. onMounted(() => {})
  76. const subject = reactive({
  77. show: false,
  78. name: '全部',
  79. id: ''
  80. });
  81. return () => {
  82. return (
  83. <div class={styles.search}>
  84. <Sticky class={styles.sticky}>
  85. <Search
  86. modelValue={keyword.value}
  87. showAction
  88. ref={searchInputRef}
  89. onSearch={onSearch}
  90. onFilter={() => (tagVisibility.value = true)}
  91. filterDot={!!tagids.value}
  92. onClick={() => {
  93. if (route.path === '/music-songbook') {
  94. router.push({
  95. path: '/music-songbook/search'
  96. })
  97. }
  98. }}
  99. v-slots={{
  100. left: () => (
  101. <div
  102. class={styles.label}
  103. onClick={() => (subject.show = true)}
  104. >
  105. {subject.name}
  106. <Icon
  107. classPrefix="iconfont"
  108. name="down"
  109. size={12}
  110. color="#333"
  111. />
  112. </div>
  113. )
  114. }}
  115. />
  116. {route.path === '/music-songbook/search' && (
  117. <Tabs
  118. color="var(--van-primary)"
  119. background="transparent"
  120. lineWidth={20}
  121. shrink
  122. v-model:active={activeTab.value}
  123. onChange={val => (activeTab.value = val)}
  124. >
  125. <Tab title="单曲" name="songe"></Tab>
  126. <Tab title="专辑" name="album"></Tab>
  127. </Tabs>
  128. )}
  129. </Sticky>
  130. {words.value.length > 0 && route.path === '/music-songbook/search' && (
  131. <div class={classNames(styles.keywords, 'van-hairline--bottom')}>
  132. <div class={styles.content}>
  133. {words.value.map(item => (
  134. <Tag
  135. round
  136. class={styles.searchKeyword}
  137. key={item}
  138. onClick={() => onSearch(item)}
  139. >
  140. {item}
  141. </Tag>
  142. ))}
  143. </div>
  144. <Icon
  145. class={styles.remove}
  146. name="delete-o"
  147. onClick={() => (words.value = [])}
  148. />
  149. </div>
  150. )}
  151. <RouterView />
  152. <Popup
  153. show={tagVisibility.value}
  154. round
  155. closeable
  156. position="bottom"
  157. style={{ height: '60%' }}
  158. teleport="body"
  159. onUpdate:show={val => (tagVisibility.value = val)}
  160. >
  161. <SelectTag
  162. ref={selectTagRef}
  163. onConfirm={onComfirm}
  164. onCancel={() => {}}
  165. />
  166. </Popup>
  167. {/* 声部弹框 */}
  168. <Popup
  169. show={subject.show}
  170. position="bottom"
  171. round
  172. closeable
  173. safe-area-inset-bottom
  174. onClose={() => (subject.show = false)}
  175. onClosed={() => (subject.show = false)}
  176. >
  177. <SelectSubject isReset onComfirm={onComfirmSubject} />
  178. </Popup>
  179. </div>
  180. )
  181. }
  182. }
  183. })