JDHeader.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. <template>
  2. <div class="jd-header" :class="headerClass">
  3. <!-- 顶部窄条 -->
  4. <div class="header-top">
  5. <div class="flex-between top-inner" :class="{ 'w': headerClass == 'header-indexEnterprise' }">
  6. <div class="loc-wrap">
  7. <svg
  8. width="12"
  9. height="12"
  10. viewBox="0 0 24 24"
  11. fill="none"
  12. stroke="currentColor"
  13. stroke-width="2"
  14. style="vertical-align: -2px; margin-right: 2px"
  15. >
  16. <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>
  17. <circle cx="12" cy="10" r="3"></circle>
  18. </svg>
  19. 湖北
  20. </div>
  21. <ul class="top-nav-links flex">
  22. <li @click="onPath('/order/orderManage')">我的订单</li>
  23. <li class="spacer"></li>
  24. <li @click="onPath('/enterprise/companyInfo')">我的工作台</li>
  25. <li class="spacer"></li>
  26. <li @click="onPath('/enterprise/companyInfo')">企业会员</li>
  27. <li class="spacer"></li>
  28. <li class="red" :style="{ color: config.themeColor }">企业采购</li>
  29. <li class="spacer"></li>
  30. <li>客户服务</li>
  31. <li class="spacer"></li>
  32. <li class="hotline">咨询热线 {{ servicePhone }}</li>
  33. </ul>
  34. </div>
  35. </div>
  36. <!-- 中间搜索行 -->
  37. <div :class="['header-mid-wrap', { 'is-fixed': isFixed }]">
  38. <div class="header-mid flex" :class="{ 'w': headerClass == 'header-indexEnterprise' }">
  39. <div class="logo-box">
  40. <div class="logo-text" :style="{ color: config.themeColor }" @click="onPath('/indexEnterprise')">{{ config.mainTitle }}</div>
  41. <p class="logo-desc">{{ config.subTitle }}</p>
  42. </div>
  43. <div class="search-box-wrap flex-1">
  44. <div class="search-bar flex" :style="{ borderColor: config.themeColor }">
  45. <div class="input-group flex-1 flex">
  46. <input v-model="input" type="text" />
  47. <div class="carousel-bos" v-if="placeholderList.length > 0 && input.length === 0">
  48. <el-carousel height="34px" direction="vertical" autoplay loop :interval="4000">
  49. <el-carousel-item v-for="item in placeholderList" :key="item">
  50. <div class="carousel-word">{{ item }}</div>
  51. </el-carousel-item>
  52. </el-carousel>
  53. </div>
  54. </div>
  55. <button class="search-btn" :style="{ backgroundColor: config.themeColor }" @click="onPath('/search?type=1&input=' + input)">搜 索</button>
  56. </div>
  57. <div class="hot-links">
  58. <span @click="onPath(item.link)" v-for="(item, index) in config.hotWordList" :key="index">{{ item.name }}</span>
  59. </div>
  60. </div>
  61. <div class="header-actions">
  62. <div :style="{ borderColor: config.themeColor, color: config.themeColor }" class="btn-keeper" @click="onPath(config.rightBtnLink)">
  63. <img v-if="config.rightBtnIcon" :src="config.rightBtnIcon" alt="" />{{ config.rightBtnText }}
  64. </div>
  65. </div>
  66. </div>
  67. </div>
  68. <!-- 占位符,防止吸顶时页面跳动 -->
  69. <div class="header-placeholder" v-show="isFixed"></div>
  70. </div>
  71. </template>
  72. <script setup lang="ts">
  73. import { currentSearchConfig } from '@/api/home/index-enterprise';
  74. import { getPlatformConfigList } from '@/api/breg/index';
  75. import { onPath } from '@/utils/siteConfig';
  76. import '@/views/home/jdcomponents/jd-repro.css';
  77. const input = ref<any>('');
  78. const servicePhone = ref<any>('');
  79. const placeholderList = ref<any>([]);
  80. const config = ref<any>({
  81. hotWordList: []
  82. });
  83. currentSearchConfig({}).then((res) => {
  84. if (res.code == 200) {
  85. config.value = res.data;
  86. document.documentElement.style.setProperty('--hover-jd1', res.data.themeColor || '#E7000B');
  87. if (res.data.placeholderText) {
  88. placeholderList.value = res.data.placeholderText.split(',');
  89. }
  90. }
  91. });
  92. getPlatformConfigList({ configKey: 'servicePhone' }).then((res) => {
  93. if (res.code == 200) {
  94. if (res.rows && res.rows.length > 0) {
  95. servicePhone.value = res.rows[0].value;
  96. }
  97. }
  98. });
  99. const isFixed = ref(false);
  100. const handleScroll = () => {
  101. isFixed.value = window.scrollY > 120;
  102. };
  103. onMounted(() => {
  104. window.addEventListener('scroll', handleScroll);
  105. });
  106. onUnmounted(() => {
  107. window.removeEventListener('scroll', handleScroll);
  108. });
  109. // 根据路由路径返回不同的 class
  110. const route = useRoute();
  111. const headerClass = computed(() => {
  112. const path = route.path;
  113. if (path === '/indexEnterprise') {
  114. return 'header-indexEnterprise';
  115. } else if (path === '/item') {
  116. return 'header-item';
  117. } else {
  118. return 'header-default';
  119. }
  120. });
  121. </script>
  122. <style lang="scss" scoped>
  123. .jd-header {
  124. background: #fff;
  125. }
  126. .header-top {
  127. height: 32px;
  128. background: #e3e4e5;
  129. border-bottom: 1px solid #e3e4e5;
  130. font-size: 12px;
  131. color: #999;
  132. line-height: 32px;
  133. }
  134. .top-nav-links li {
  135. padding: 0 10px;
  136. cursor: pointer;
  137. transition: color 0.2s;
  138. }
  139. .top-nav-links li:hover {
  140. color: var(--hover-jd1);
  141. }
  142. .top-nav-links .spacer {
  143. width: 1px;
  144. height: 10px;
  145. background: #ccc;
  146. margin-top: 11px;
  147. padding: 0;
  148. }
  149. .top-nav-links .red {
  150. color: #e1251b;
  151. font-weight: bold;
  152. }
  153. /* 吸顶包裹层 */
  154. .header-mid-wrap {
  155. background: #fff;
  156. transition: all 0.2s;
  157. }
  158. .header-mid-wrap.is-fixed {
  159. position: fixed;
  160. top: 0;
  161. left: 0;
  162. right: 0;
  163. z-index: 999;
  164. box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
  165. animation: slideDown 0.3s ease-out;
  166. }
  167. @keyframes slideDown {
  168. from {
  169. transform: translateY(-100%);
  170. }
  171. to {
  172. transform: translateY(0);
  173. }
  174. }
  175. .header-placeholder {
  176. height: 100px;
  177. } /* header-mid 的总高度估算 */
  178. .header-mid {
  179. padding: 25px 0 15px;
  180. display: flex;
  181. align-items: center;
  182. justify-content: flex-start;
  183. transition: padding 0.2s;
  184. }
  185. .is-fixed .header-mid {
  186. padding: 25px 0;
  187. } /* 增加吸顶时的高度,总高度 90px */
  188. .logo-box {
  189. width: auto;
  190. text-align: center;
  191. margin-right: 30px;
  192. flex-shrink: 0;
  193. }
  194. .logo-text {
  195. font-size: 32px;
  196. font-weight: 900;
  197. color: #e1251b;
  198. letter-spacing: 1px;
  199. font-family: 'Microsoft YaHei', sans-serif;
  200. line-height: 1.2;
  201. }
  202. .logo-desc {
  203. font-size: 12px;
  204. color: #999;
  205. margin-top: 5px;
  206. letter-spacing: 2px;
  207. }
  208. .is-fixed .logo-desc {
  209. display: none;
  210. } /* 吸顶时隐藏副标题 */
  211. .is-fixed .logo-text {
  212. font-size: 26px;
  213. } /* 吸顶时稍微缩小Logo */
  214. .search-box-wrap {
  215. margin: 0;
  216. flex: 1;
  217. max-width: none;
  218. display: flex;
  219. flex-direction: column;
  220. }
  221. .search-bar {
  222. height: 42px;
  223. border: 2px solid #e1251b;
  224. border-radius: 8px;
  225. background: #fff;
  226. padding: 2px;
  227. box-sizing: border-box;
  228. }
  229. .input-group {
  230. padding: 0 15px;
  231. align-items: center;
  232. height: 100%;
  233. position: relative;
  234. .carousel-bos {
  235. position: absolute;
  236. top: 0;
  237. left: 0;
  238. height: 34px;
  239. width: 100%;
  240. z-index: 1;
  241. pointer-events: none;
  242. .carousel-word {
  243. line-height: 34px;
  244. color: #999;
  245. padding-left: 15px;
  246. }
  247. }
  248. }
  249. .input-group input {
  250. width: 100%;
  251. height: 100%;
  252. border: none;
  253. outline: none;
  254. font-size: 14px;
  255. color: #333;
  256. }
  257. .input-group input::placeholder {
  258. color: #999;
  259. }
  260. .search-btn {
  261. width: 84px;
  262. height: 100%;
  263. background: #e1251b;
  264. color: #fff;
  265. border: none;
  266. font-size: 16px;
  267. font-weight: bold;
  268. border-radius: 6px;
  269. cursor: pointer;
  270. transition: background 0.2s;
  271. letter-spacing: 2px;
  272. }
  273. .search-btn:hover {
  274. background: #c81623;
  275. }
  276. .hot-links {
  277. font-size: 12px;
  278. color: #999;
  279. margin-top: 8px;
  280. padding-left: 5px;
  281. }
  282. .hot-links span {
  283. margin-right: 15px;
  284. cursor: pointer;
  285. }
  286. .hot-links span:hover {
  287. color: var(--hover-jd1);
  288. }
  289. .is-fixed .hot-links {
  290. display: none;
  291. } /* 吸顶时隐藏热搜词 */
  292. .header-actions {
  293. margin-left: 30px;
  294. flex-shrink: 0;
  295. img {
  296. height: 16px;
  297. width: 16px;
  298. margin-right: 4px;
  299. }
  300. }
  301. .btn-keeper {
  302. height: 40px;
  303. line-height: 38px;
  304. padding: 0 24px;
  305. border: 1px solid #ffcdd2;
  306. border-radius: 8px;
  307. color: #e1251b;
  308. font-size: 14px;
  309. font-weight: bold;
  310. background: #fff;
  311. cursor: pointer;
  312. transition: all 0.2s;
  313. box-sizing: border-box;
  314. display: flex;
  315. align-items: center;
  316. }
  317. .btn-keeper:hover {
  318. background: #f2f2f2;
  319. }
  320. .header-default {
  321. .top-inner,
  322. .header-mid {
  323. min-width: 1200px;
  324. max-width: 1500px;
  325. margin: 0 auto;
  326. }
  327. }
  328. .header-item {
  329. .top-inner,
  330. .header-mid {
  331. margin: 0 auto;
  332. width: 1200px;
  333. @media (min-width: 1600px) {
  334. width: 1600px;
  335. }
  336. }
  337. }
  338. </style>