list copy 2.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. <template>
  2. <div
  3. class="bar-list"
  4. v-if="show && !(metadata.navigationTrees && metadata.navigationTrees.length == 1 && scenes.length == 1 && metadata.navigationTrees[rootTabIndex].length == 1)"
  5. :class="{ barshow: isShowScenesList }"
  6. >
  7. <div class="top-con">
  8. <div class="swiper-container swiper1" :style="`width:calc(100% - 20px)`" id="swScenes" v-if="currentScenesList.length > 0">
  9. <ul class="swiper-wrapper">
  10. <li
  11. @click="tabCurrentScene(item)"
  12. class="swiper-slide"
  13. :class="{
  14. active: currentScene.sceneCode == item.sceneCode,
  15. // loopspan:
  16. // item.name.length > spanlength &&
  17. // currentScene.id == item.id,
  18. }"
  19. :style="{ backgroundImage: `url(${item.icon})` }"
  20. v-for="(item, i) in currentScenesList"
  21. :key="i"
  22. >
  23. <i class="iconfont" :class="item.type == '4dkk' ? 'icon-editor_3d' : 'icon-editor_panoramic'"></i>
  24. <div class="marquee">
  25. <marquee-text :repeat="1" :duration="Math.ceil(item.name.length / 10) * 5" :key="item.id" v-if="item.name.length > spanlength && currentScene.id == item.id">
  26. {{ item.name }}
  27. </marquee-text>
  28. <span v-else>
  29. {{ item.name }}
  30. </span>
  31. </div>
  32. </li>
  33. </ul>
  34. </div>
  35. <div class="swiper-container swiper2" id="swSecondary" :style="`width:${clamp(secondaryW, 0, 1150)}px`" v-if="metadata.navigationTrees[rootTabIndex]?.children.length > 1">
  36. <!-- {{ clamp(secondaryW, 0, 1150) }} -->
  37. <ul class="swiper-wrapper">
  38. <li
  39. class="swiper-slide"
  40. @click="tabSecondary(item, i)"
  41. :class="{
  42. active: currentSecondary.id == item.id,
  43. // loopspan:
  44. // fixTitle(item.name).length > spanlength &&
  45. // currentSecondary.id == item.id,
  46. }"
  47. v-for="(item, i) in metadata.navigationTrees[rootTabIndex]?.children"
  48. :key="i"
  49. >
  50. <!-- {{ Math.ceil(fixTitle(item.name).length / 10) }} -->
  51. <marquee-text :duration="Math.ceil(fixTitle(item.name).length / 10) * 5" :key="item.id" :repeat="1" v-if="fixTitle(item.name).length > spanlength && currentSecondary.id == item.id">
  52. {{ fixTitle(item.name) }}
  53. </marquee-text>
  54. <span v-else>
  55. {{ fixTitle(item.name) }}
  56. </span>
  57. <!-- <span v-if="currentSecondary.id == item.id">{{
  58. fixTitle(item.name)
  59. }}</span>
  60. <span v-else>{{
  61. fixTitle(item.name).length > spanlength
  62. ? fixTitle(item.name).slice(0, spanlength)
  63. : fixTitle(item.name)
  64. }}</span> -->
  65. </li>
  66. </ul>
  67. </div>
  68. </div>
  69. <div class="swiper-container" id="swcatalogRoot" :style="`width:${catalogRootW > innerW ? '100%' : catalogRootW + 'px'}`" v-if="metadata.navigationTrees.length">
  70. <ul class="swiper-wrapper" v-if="metadata.navigationTrees.length > 1">
  71. <li
  72. class="swiper-slide"
  73. :class="{
  74. active: currentCatalogRoot.id == item.id,
  75. // loopspan:
  76. // fixTitle(item.name).length > spanlength &&
  77. // currentCatalogRoot.id == item.id,
  78. }"
  79. @click="tabRoot(item)"
  80. v-for="(item, i) in metadata.navigationTrees"
  81. :key="i"
  82. >
  83. <!-- <span v-if="currentCatalogRoot.id == item.id">{{
  84. fixTitle(item.name)
  85. }}</span>
  86. <span v-else>{{
  87. fixTitle(item.name).length > spanlength
  88. ? fixTitle(item.name).slice(0, spanlength)
  89. : fixTitle(item.name)
  90. }}</span> -->
  91. <marquee-text :duration="Math.ceil(fixTitle(item.name).length / 10) * 5" :key="item.id" :repeat="1" v-if="fixTitle(item.name).length > spanlength && currentCatalogRoot.id == item.id">
  92. {{ fixTitle(item.name) }}
  93. </marquee-text>
  94. <span v-else>
  95. {{ fixTitle(item.name) }}
  96. </span>
  97. </li>
  98. </ul>
  99. </div>
  100. </div>
  101. </template>
  102. <script setup>
  103. import { ref, watch, computed, onMounted, nextTick, unref, watchEffect } from "vue";
  104. import { useStore } from "vuex";
  105. import { useApp } from "@/app";
  106. import MarqueeText from "vue-marquee-text-component";
  107. import { useI18n, getLocale } from "@/i18n";
  108. const { t } = useI18n({ useScope: "global" });
  109. const store = useStore();
  110. const spanlength = ref(5);
  111. const metadata = computed(() => store.getters["scene/metadata"]);
  112. const scenes = computed(() => store.getters["scene/list"]);
  113. const currentScene = computed(() => store.getters["scene/currentScene"]);
  114. const currentSecondId = computed(() => store.getters["scene/currentSecondId"]);
  115. const currentRootId = computed(() => store.getters["scene/currentRootId"]);
  116. const clamp = computed(() => (num, min, max) => Math.min(Math.max(num, min), max));
  117. const currentCatalogRoot = computed(() => store.getters["scene/currentCatalogRoot"]);
  118. const currentSecondary = computed(() => store.getters["scene/currentSecondary"]);
  119. const secondaryList = computed(() => store.getters["scene/secondaryList"]);
  120. const isShowScenesList = computed(() => store.getters["functions/isShowScenesList"]);
  121. const currentScenesList = computed(() => store.getters["scene/currentScenesList"]);
  122. const show = ref(false);
  123. const swidth = ref({
  124. swcatalogRoot: 104,
  125. swSecondary: 84,
  126. swScenes: 72,
  127. });
  128. const rootTabIndex = computed(() => {
  129. console.error(currentRootId.value);
  130. return metadata.value && metadata.value?.navigationTrees ? metadata.value?.navigationTrees.findIndex((item) => item.id == currentRootId.value) : 0;
  131. });
  132. const secondTabIndex = computed(() => {
  133. return metadata.value && metadata.value?.navigationTrees ? metadata.value.navigationTrees[rootTabIndex.value]?.children.findIndex((item) => item.id == currentSecondId.value) : 0;
  134. });
  135. const scenesListW = computed(() => currentScenesList.value.length * (swidth.value["swScenes"] + 10) - 10);
  136. const secondaryW = computed(() => metadata.value.navigationTrees[secondTabIndex.value].length * (swidth.value["swSecondary"] + 10) - 10);
  137. const catalogRootW = computed(() => metadata.value.navigationTrees.length * (swidth.value["swcatalogRoot"] + 10) - 10);
  138. const innerW = computed(() => 1150);
  139. const tabCurrentScene = (data) => {
  140. console.log("tabCurrentScene", data.id, currentScene.value.id);
  141. if (data.id !== currentScene.value.id) {
  142. store.commit("scene/setCurrentScene", data);
  143. setTimeout(() => {
  144. scenesSwiperFocus();
  145. }, 300);
  146. } else {
  147. console.log("重复点击当前导航");
  148. // window.alert("alert-test-->重复点击当前导航");
  149. }
  150. };
  151. const tabSecondary = (data, index) => {
  152. store.commit("scene/setCurrentSecondary", data);
  153. };
  154. const tabRoot = (data) => {
  155. store.commit("scene/setCurrentCatalogRoot", data);
  156. };
  157. const fixTitle = (name) => {
  158. if (name == "默认二级分组") {
  159. name = t("navigation.default_group_two");
  160. } else if (name == "一级分组") {
  161. name = t("navigation.group_one");
  162. } else {
  163. name = name;
  164. }
  165. return name;
  166. };
  167. const swiperOptions = {
  168. slidesPerView: "auto",
  169. centeredSlides: true,
  170. spaceBetween: 10,
  171. centerInsufficientSlides: true,
  172. centeredSlidesBounds: true,
  173. freeMode: {
  174. enabled: true,
  175. sticky: false,
  176. momentumBounce: false,
  177. // momentumVelocityRatio: 0.5,
  178. },
  179. };
  180. // const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
  181. const initMainSwiper = () => {
  182. nextTick(() => {
  183. if (window.mainNatSwiper) {
  184. // window.mainNatSwiper = null;
  185. window.mainNatSwiper.update();
  186. window.sencordNatSwiper.slideReset();
  187. }
  188. window.mainNatSwiper = new Swiper("#swcatalogRoot", swiperOptions);
  189. });
  190. };
  191. const initsencordNatSwiper = () => {
  192. nextTick(() => {
  193. console.warn("initsencordNatSwiper");
  194. if (window.sencordNatSwiper) {
  195. window.sencordNatSwiper.update();
  196. window.sencordNatSwiper.slideReset();
  197. }
  198. window.sencordNatSwiper = new Swiper("#swSecondary", swiperOptions);
  199. });
  200. };
  201. const initScenesSwiper = () => {
  202. // console.warn("initScenesSwiper");
  203. nextTick(() => {
  204. if (window.scenesNatSwiper) {
  205. try {
  206. window.scenesNatSwiper.slides.length > 0 && window.scenesNatSwiper.update();
  207. window.scenesNatSwiper.slideReset();
  208. } catch (error) {}
  209. // window.scenesNatSwiper = null;
  210. } else {
  211. window.scenesNatSwiper = new Swiper("#swScenes", {
  212. ...swiperOptions,
  213. });
  214. }
  215. scenesSwiperFocus();
  216. });
  217. };
  218. const scenesSwiperFocus = () => {
  219. const sceneIndex = Array.from(currentScenesList.value).findIndex((item) => item.id === currentScene.value.id);
  220. if (window.scenesNatSwiper && window.scenesNatSwiper.slides.length > 0) {
  221. const index = sceneIndex < 0 ? 0 : sceneIndex;
  222. const fIndex = index < 5 ? 0 : index;
  223. console.warn("scenesSwiperFocus", fIndex);
  224. window.scenesNatSwiper.slideTo(fIndex);
  225. }
  226. };
  227. const sencordNatSwiperFocus = () => {
  228. nextTick(() => {
  229. const current = Array.from(secondaryList.value).findIndex((item) => item.id === currentSecondary.value.id);
  230. if (window.sencordNatSwiper) {
  231. const index = current < 0 ? 0 : current;
  232. console.error("sencordNatSwiperFocus", index);
  233. // window.sencordNatSwiper.slideTo(current);
  234. window.sencordNatSwiper.slideTo(current);
  235. }
  236. });
  237. };
  238. onMounted(() => {
  239. useApp().then(async (app) => {
  240. show.value = true;
  241. console.error("app", show.value);
  242. });
  243. watchEffect(() => {
  244. if (metadata.value.navigationTrees && unref(metadata.value.navigationTrees).length > 0) {
  245. initMainSwiper();
  246. }
  247. });
  248. watch(secondTabIndex.value, () => {
  249. if (unref(metadata.value.navigationTrees[rootTabIndex.value].children).length > 1) {
  250. initsencordNatSwiper();
  251. sencordNatSwiperFocus();
  252. } else {
  253. if (window.sencordNatSwiper) {
  254. console.warn("destroy-sencordNatSwiper");
  255. window.sencordNatSwiper.update();
  256. window.sencordNatSwiper.slideReset();
  257. }
  258. }
  259. });
  260. watch(currentScenesList, () => {
  261. initScenesSwiper();
  262. });
  263. watch(currentCatalogRoot, (val) => {
  264. if (Array.from(unref(val).children).includes(currentScene.value.category)) {
  265. //当前场景在一类的children
  266. const activeSecond = Array.from(unref(secondaryList)).find((i) => i.id === currentScene.value.category);
  267. // console.log("activeSecond", activeSecond);
  268. store.commit("scene/setCurrentSecondary", activeSecond);
  269. if (window.sencordNatSwiper) {
  270. window.sencordNatSwiper.update();
  271. }
  272. }
  273. });
  274. });
  275. </script>
  276. <style lang="scss" scoped>
  277. $width: 1150px;
  278. .bar-list {
  279. position: absolute;
  280. bottom: 68px;
  281. left: 50%;
  282. transform: translateX(-50%);
  283. text-align: center;
  284. max-width: $width;
  285. overflow: hidden;
  286. max-height: 0;
  287. transition: 0.3s all ease;
  288. z-index: 9;
  289. .swiper-container {
  290. width: 100%;
  291. position: relative;
  292. margin: 0 auto;
  293. > ul {
  294. > li {
  295. white-space: nowrap;
  296. > span,
  297. > div > span {
  298. cursor: pointer;
  299. display: inline-block;
  300. color: rgba(255, 255, 255, 0.6);
  301. }
  302. &.loopspan {
  303. > span,
  304. > div > span {
  305. animation: 10s wordsLoop linear infinite normal;
  306. }
  307. }
  308. &.active {
  309. > span,
  310. > div > span {
  311. color: rgba(255, 255, 255, 1);
  312. }
  313. }
  314. }
  315. }
  316. }
  317. .top-con {
  318. margin: 0 auto 10px;
  319. padding: 10px 0;
  320. background: linear-gradient(268deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.4) 25%, rgba(0, 0, 0, 0.4) 75%, rgba(0, 0, 0, 0) 100%);
  321. }
  322. #swcatalogRoot {
  323. > ul {
  324. > li {
  325. width: 104px;
  326. background: rgba(0, 0, 0, 0.5);
  327. border-radius: 4px;
  328. padding: 4px 10px;
  329. border: 1px solid rgba(255, 255, 255, 0.5);
  330. box-sizing: border-box;
  331. overflow: hidden;
  332. > span {
  333. width: 100%;
  334. word-break: keep-all;
  335. }
  336. &.active {
  337. border: 1px solid rgba(255, 255, 255, 1);
  338. }
  339. }
  340. }
  341. }
  342. #swSecondary {
  343. margin: 20px auto 10px;
  344. > ul {
  345. > li {
  346. width: 84px;
  347. box-sizing: border-box;
  348. overflow: hidden;
  349. padding-bottom: 6px;
  350. > span {
  351. width: 100%;
  352. word-break: keep-all;
  353. }
  354. &.active {
  355. position: relative;
  356. &::before {
  357. content: "";
  358. display: inline-block;
  359. position: absolute;
  360. bottom: 0;
  361. width: 20px;
  362. height: 2px;
  363. z-index: 9999;
  364. left: 50%;
  365. transform: translateX(-50%);
  366. background: var(--colors-primary-base);
  367. }
  368. }
  369. }
  370. }
  371. }
  372. #swScenes {
  373. > ul {
  374. > li {
  375. cursor: pointer;
  376. width: 72px;
  377. height: 72px;
  378. border-radius: 6px;
  379. border: 1px solid #ffffff;
  380. background-size: cover;
  381. position: relative;
  382. overflow: hidden;
  383. .iconfont {
  384. position: absolute;
  385. left: 4px;
  386. top: 4px;
  387. z-index: 99;
  388. &::after {
  389. background: rgba(0, 0, 0, 0.3);
  390. content: "";
  391. width: 14px;
  392. height: 14px;
  393. display: inline-block;
  394. position: absolute;
  395. top: 50%;
  396. left: 50%;
  397. transform: translate(-50%, -50%);
  398. z-index: -1;
  399. filter: blur(4px);
  400. }
  401. }
  402. > div {
  403. position: absolute;
  404. bottom: 0;
  405. left: 0;
  406. height: 20px;
  407. background: rgba(0, 0, 0, 0.5);
  408. width: 100%;
  409. overflow: hidden;
  410. > span,
  411. div {
  412. // width: 100%;
  413. line-height: 20px;
  414. word-break: keep-all;
  415. white-space: normal;
  416. }
  417. }
  418. &.active {
  419. border: 1px solid var(--colors-primary-base);
  420. > div {
  421. > span {
  422. }
  423. }
  424. }
  425. }
  426. }
  427. }
  428. }
  429. .barshow {
  430. max-height: 190px;
  431. }
  432. @keyframes wordsLoop {
  433. 0% {
  434. transform: translateX(100%);
  435. -webkit-transform: translateX(100%);
  436. }
  437. 100% {
  438. transform: translateX(-180%);
  439. -webkit-transform: translateX(-180%);
  440. }
  441. }
  442. .marquee {
  443. .marquee-text-wrap {
  444. height: 20px;
  445. line-height: 20px;
  446. }
  447. }
  448. </style>
  449. <style>
  450. .marquee-text-text {
  451. padding: 0 5px;
  452. }
  453. </style>