金诚优选前端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

457 lines
12 KiB

4 years ago
4 years ago
  1. <template>
  2. <view class="centent">
  3. <lf-nav :title="['分类','品牌'][current]" bgColor="#fff" :search="current == 0" @changeHeight="e => nav_height = e"></lf-nav>
  4. <view class="tabs">
  5. <view class="lf-tab"
  6. :style="{width: 100 / tabs.length +'%'}"
  7. :class="{'tab-active': current == index}"
  8. v-for="(item, index) in tabs" :key="index"
  9. @click="current = index">{{ item.name }}
  10. </view>
  11. </view>
  12. <!-- 分类 -->
  13. <view class="page" v-if="current == 0">
  14. <scroll-view class="left_view p_r" scroll-y :style="{ height: autoHeight }">
  15. <block v-for="(item, index) in dataArr" :key="index">
  16. <view :class="[left_selectIndex == index ? 'left_item_s' : '', 'left_item']" :id="'left_' + index" @click="leftTap({ item, index })">{{ item.name }}</view>
  17. </block>
  18. <view class="seletItem" :style="{ top: left_selectIndex * 60 - 19 + 'px' }"></view>
  19. </scroll-view>
  20. <scroll-view @scroll="rightScroll" class="right_view" scroll-y :style="{ height: autoHeight }" :scroll-into-view="'left_' + right_selectIndex" scroll-with-animation>
  21. <block v-for="(item, index) in dataArr" :key="index">
  22. <view :ref="'left_' + index" class="right_item " :id="'left_' + index">
  23. <text class="right_item_title ">{{ item.name }}</text>
  24. <view class="right_item_view">
  25. <view class="item" v-for="(item, index) in item.subArr" :key="index" @click="rightTap(item)">
  26. <image :src="item.img" :style="{ width: '100%', height: subItemW + 'px', background: '#999999' }"></image>
  27. <text class="lf-font-24">{{ item.name }}</text>
  28. </view>
  29. </view>
  30. </view>
  31. </block>
  32. <view class="" :style="{ height: autoScrollHeight }"><!-- 站位 --></view>
  33. </scroll-view>
  34. </view>
  35. <!-- 品牌 -->
  36. <view class="brand" v-else-if="current == 1" :style="{height: autoHeight}">
  37. <!-- 筛选 -->
  38. <view class="lf-filter-box">
  39. <view class="lf-filter" :class="{'lf-filter-after': filter_active == ''}">
  40. <view :class="{'filter-active': filter_active == 'floor'}" @click="filter_active = 'floor'">楼层</view>
  41. <view :class="{'filter-active': filter_active == 'class'}" @click="filter_active = 'class'">分类</view>
  42. </view>
  43. <view class="filter-modal-mask" :style="{height: otherHeight}" v-if="filter_active != ''" @click="filter_active = ''">
  44. <view class="filter-modal">
  45. <view class="filter-item" v-for="(item, index) in 6" :key="index">{{ '哈哈'+ item }}</view>
  46. </view>
  47. </view>
  48. </view>
  49. <!-- 内容 -->
  50. <scroll-view class="brand-scroll" :scroll-into-view="scrollAnchorId" :scroll-y="true" :style="{height: otherHeight}">
  51. <view class="lf-flex brand-item"
  52. :id="'anchor-'+ index"
  53. @click="$url('/pages/shop/shopdetail')"
  54. v-for="(item, index) in point_list" :key="index">
  55. <image class="img" src="https://picsum.photos/200"></image>
  56. <view class="info">
  57. <view class="lf-font-36 lf-font-bold lf-color-black">luckin coffee 瑞幸咖啡 {{ item }}</view>
  58. <view class="lf-font-24 lf-color-gray">餐饮·美食18件在售</view>
  59. <view class="lf-font-24">
  60. <text class="lf-iconfont icon--1 lf-font-24"></text>
  61. <text class="lf-color-gray lf-m-l-10">L2</text>
  62. </view>
  63. </view>
  64. </view>
  65. </scroll-view>
  66. <!-- 锚点定位 -->
  67. <view class="fixed-point" @touchmove="pointTouchmove">
  68. <view class="point-item" @click="pointClick" :id="'point-'+index" :style="{height: 100 / 26 +'%'}" v-for="(item, index) in point_list" :key="index">{{ item }}</view>
  69. </view>
  70. </view>
  71. <lf-tabbar></lf-tabbar>
  72. </view>
  73. </template>
  74. <script>
  75. import lfNav from '@/components/lf-nav/lf-nav.vue';
  76. import lfTabbar from '@/components/lf-tabbar/lf-tabbar.vue';
  77. import testdata from './testdata.js';
  78. let app = getApp();
  79. export default {
  80. data() {
  81. return {
  82. scrollH: 0,
  83. subItemW: 0,
  84. left_selectIndex: 0,
  85. right_selectIndex: 0,
  86. ttscrollH: 0, //总高度
  87. placeholderH: 0, //占位高度
  88. heighArr: [],
  89. dataArr: testdata,
  90. current: 1,
  91. nav_height: 0,
  92. tabs: [{
  93. name: '分类'
  94. },{
  95. name: '品牌'
  96. }],
  97. filter_active: '',
  98. point_list: [],
  99. scrollAnchorId: ''
  100. };
  101. },
  102. computed: {
  103. autoHeight(){
  104. return `calc(${this.scrollH}px - ${this.nav_height}px - 90rpx - 120rpx)`;
  105. },
  106. otherHeight(){
  107. // 屏幕可用总高度 - 导航条高度 - tabs高度 - tabbar高度 - 筛选高度
  108. return `calc(${this.scrollH}px - ${this.nav_height}px - 90rpx - 120rpx - 105rpx)`;
  109. },
  110. autoScrollHeight(){
  111. return `calc(${this.scrollH}px - ${this.nav_height}px - 90rpx - 120rpx - 300rpx)`;
  112. }
  113. },
  114. components: {
  115. lfNav,
  116. lfTabbar
  117. },
  118. onLoad(options) {
  119. // https://ext.dcloud.net.cn/plugin?id=5031
  120. if(this.$isRight(options)){
  121. this.current = options.current || 1;
  122. this.left_selectIndex = options.type || 0;
  123. this.right_selectIndex = options.type || 0;
  124. }
  125. let info = uni.getSystemInfoSync();
  126. let self = this;
  127. self.scrollH = info.screenHeight;
  128. self.subItemW = parseInt((info.screenWidth * (2 / 3) - 15 * 2 - 24) / 3);
  129. setTimeout(function() {
  130. self.computerH();
  131. }, 100);
  132. this.createAtoZ();
  133. },
  134. methods: {
  135. // 生成A-Z的大写字母
  136. createAtoZ(){
  137. let point_list = [];
  138. for(var i=0; i<26; i++){
  139. point_list.push(String.fromCharCode(65+i));
  140. }
  141. this.point_list = point_list;
  142. },
  143. pointTouchmove(event){
  144. console.log(event);
  145. },
  146. pointClick(event){
  147. let index = (event.target.id).replace('point-', '');
  148. let letter = this.point_list[index];
  149. this.scrollAnchorId = '';
  150. this.$msg(letter);
  151. this.$nextTick(() => {
  152. this.scrollAnchorId = 'anchor-'+ index;
  153. })
  154. },
  155. leftTap: function(e) {
  156. this.left_selectIndex = e.index;
  157. this.right_selectIndex = e.index;
  158. },
  159. // 右边点击
  160. rightTap: function() {
  161. this.$msg('敬请期待')
  162. },
  163. rightScroll: function(e) {
  164. let scrollH = e.detail.scrollTop + 30;
  165. let cc = this.ttscrollH - this.scrollH;
  166. let a = 0;
  167. let findInx = this.heighArr.findIndex(function(itemH, i) {
  168. a = a + itemH;
  169. return a > scrollH;
  170. });
  171. // if (scrollH >= cc) {
  172. // return;
  173. // }
  174. this.left_selectIndex = findInx;
  175. },
  176. // 计算高度
  177. computerH: function() {
  178. this.ttscrollH = 0;
  179. for (let item of this.dataArr) {
  180. let title_lineH = 49; //rpx
  181. let subNum = item.subArr.length;
  182. let subImgH = this.subItemW; //rpx
  183. let subTitleH = 40; //rpx
  184. let rowSpecH = 8; //rpx
  185. let rowN = subNum % 3;
  186. let rowSpecNum = parseInt(subNum / 3) + parseInt(rowN > 0 ? 1 : 0);
  187. let totalRpx = title_lineH + (subImgH + subTitleH) * rowSpecNum + rowSpecH * (rowSpecNum - 1);
  188. this.heighArr.push(totalRpx);
  189. this.ttscrollH = this.ttscrollH + totalRpx;
  190. }
  191. // this.placeholderH = this.scrollH - this.heighArr[this.heighArr.length - 1];
  192. //以下方法也可以
  193. // let self=this
  194. // var selectorQuery = uni.createSelectorQuery()
  195. // selectorQuery.selectAll('.right_item').boundingClientRect(data => {
  196. // self.heighArr = data.map(item => {
  197. // return {
  198. // top: Math.round(item.top),
  199. // height: Math.round(item.height)
  200. // }
  201. // })
  202. // }).exec()
  203. // console.log('ttscrollH',this.$refs.left_0)
  204. }
  205. }
  206. }
  207. </script>
  208. <style lang="scss" scoped>
  209. .page {
  210. display: grid;
  211. grid-template-columns: 1fr 2fr;
  212. grid-template-rows: auto;
  213. position: absolute;
  214. left: 0rpx;
  215. right: 0rpx;
  216. overflow: hidden;
  217. box-sizing: border-box;
  218. }
  219. .left_view {
  220. background-color: #f4f8f8;
  221. position: relative;
  222. box-sizing: border-box;
  223. // 蒙版
  224. .seletItem {
  225. height: 98px;
  226. position: absolute;
  227. top: 0rpx;
  228. left: 0rpx;
  229. z-index: 10;
  230. right: 0rpx;
  231. // background-color: rgba(255, 255, 255, 0.3);
  232. transition: top 0.2s linear;
  233. display: flex;
  234. align-items: center;
  235. box-sizing: border-box;
  236. &::before {
  237. content: '';
  238. width: 6rpx;
  239. height: 60%;
  240. background-color: #15716E;
  241. left: 0rpx;
  242. }
  243. }
  244. .left_item {
  245. display: flex;
  246. justify-content: center;
  247. align-items: center;
  248. height: 60px;
  249. margin-bottom: 0rpx;
  250. position: relative;
  251. font-size: 28rpx;
  252. box-sizing: border-box;
  253. color: #555555;
  254. }
  255. .left_item_s {
  256. background-color: #ffffff;
  257. color: #15716E;
  258. font-weight: bold;
  259. position: relative;
  260. box-sizing: border-box;
  261. }
  262. }
  263. .right_view {
  264. background-color: #ffffff;
  265. padding: 0rpx 12px;
  266. box-sizing: border-box;
  267. .right_item {
  268. .right_item_title {
  269. display: block;
  270. box-sizing: border-box;
  271. line-height: 49px;
  272. font-size: 28rpx;
  273. font-weight: bold;
  274. color: #15716E;
  275. }
  276. .right_item_view {
  277. display: grid;
  278. grid-template-columns: repeat(3, 1fr);
  279. grid-template-rows: auto;
  280. grid-gap: 8px 15px;
  281. box-sizing: border-box;
  282. .item {
  283. display: flex;
  284. flex-flow: column nowrap;
  285. align-items: center;
  286. box-sizing: border-box;
  287. text {
  288. color: #333;
  289. line-height: 40px;
  290. }
  291. }
  292. }
  293. }
  294. }
  295. .tabs{
  296. width: 750rpx;
  297. height: 90rpx;
  298. display: flex;
  299. justify-content: space-between;
  300. border-bottom: 1rpx solid #e5e5e5;
  301. background-color: #FFFFFF;
  302. .lf-tab{
  303. // width: 50%;
  304. display: flex;
  305. align-items: center;
  306. justify-content: center;
  307. font-size: 28rpx;
  308. color: #777777;
  309. position: relative;
  310. &.tab-active{
  311. color: #15716E;
  312. }
  313. &.tab-active::after{
  314. content: '';
  315. position: absolute;
  316. bottom: 0;
  317. left: 50%;
  318. width: 80rpx;
  319. height: 10rpx;
  320. background-color: #15716E;
  321. border-radius: 10rpx 10rpx 0 0;
  322. margin-left: -40rpx;
  323. }
  324. }
  325. }
  326. .lf-filter-box{
  327. height: 105rpx;
  328. width: 750rpx;
  329. background-color: #F4F8F8;
  330. display: flex;
  331. justify-content: center;
  332. align-items: center;
  333. position: relative;
  334. .lf-filter{
  335. width: 300rpx;
  336. height: 65rpx;
  337. border-radius: 33rpx;
  338. border: 1rpx solid #15716E;
  339. color: #15716E;
  340. font-size: 24rpx;
  341. display: flex;
  342. align-items: center;
  343. justify-content: space-between;
  344. position: relative;
  345. overflow: hidden;
  346. &.lf-filter-after::after{
  347. content: '';
  348. position: absolute;
  349. top: 12rpx;
  350. left: calc(50% - 1rpx);
  351. width: 2rpx;
  352. height: 40rpx;
  353. background-color: #15716E;
  354. }
  355. &>view{
  356. height: 100%;
  357. width: 50%;
  358. display: flex;
  359. justify-content: space-around;
  360. align-items: center;
  361. }
  362. .filter-active{
  363. background-color: #15716E;
  364. color: #FFFFFF;
  365. }
  366. }
  367. .filter-modal-mask{
  368. position: absolute;
  369. top: 105rpx;
  370. left: 0;
  371. width: 100%;
  372. background-color: rgba(0,0,0,0.5);
  373. .filter-modal{
  374. width: 750rpx;
  375. height: max-content;
  376. padding: 60rpx 32rpx;
  377. box-sizing: border-box;
  378. background-color: #FFFFFF;
  379. display: flex;
  380. flex-wrap: wrap;
  381. position: relative;
  382. z-index: 1;
  383. .filter-item{
  384. width: 215rpx;
  385. height: 65rpx;
  386. border-radius: 10rpx;
  387. border: 1rpx solid #555555;
  388. display: flex;
  389. justify-content: center;
  390. align-items: center;
  391. font-size: 28rpx;
  392. color: #555555;
  393. margin-right: 21rpx;
  394. &:nth-child(3n){
  395. margin-right: 0rpx;
  396. }
  397. &:nth-child(n+4){
  398. margin-top: 21rpx;
  399. }
  400. }
  401. }
  402. }
  403. }
  404. .brand-scroll{
  405. padding: 0rpx 32rpx;
  406. box-sizing: border-box;
  407. width: 750rpx;
  408. .brand-item{
  409. margin-bottom: 60rpx;
  410. &:nth-child(1n){
  411. margin-top: 30rpx;
  412. }
  413. }
  414. .img{
  415. width: 150rpx;
  416. height: 150rpx;
  417. border-radius: 4rpx;
  418. margin-right: 20rpx;
  419. }
  420. .info{
  421. width: 514rpx;
  422. height: 150rpx;
  423. display: flex;
  424. flex-direction: column;
  425. justify-content: space-between;
  426. }
  427. }
  428. .brand{
  429. position: relative;
  430. }
  431. .fixed-point{
  432. position: fixed;
  433. right: 0;
  434. top: 18vh;
  435. height: 70vh;
  436. width: 57rpx;
  437. background-color: rgba(0,0,0,0.3);
  438. border-radius: 30rpx 0rpx 0rpx 30rpx;
  439. padding: 14rpx 0rpx;
  440. z-index: 2;
  441. .point-item{
  442. font-size: 24rpx;
  443. color: #FFFFFF;
  444. text-align: center;
  445. }
  446. }
  447. </style>