| @ -0,0 +1,9 @@ | ||||
| root = true | ||||
| 
 | ||||
| [*] | ||||
| charset = utf-8 | ||||
| indent_style = space | ||||
| indent_size = 2 | ||||
| end_of_line = lf | ||||
| insert_final_newline = true | ||||
| trim_trailing_whitespace = true | ||||
| Before Width: | Height: | Size: 4.2 KiB | 
| After Width: | Height: | Size: 2.7 KiB | 
| @ -1,28 +1,24 @@ | ||||
| <template> | ||||
|   <div id="app"> | ||||
|     <img alt="Vue logo" src="./assets/logo.png"> | ||||
|     <HelloWorld msg="Welcome to Your Vue.js App"/> | ||||
|     <keep-alive exclude="Detail"> | ||||
|       <router-view/> | ||||
|     </keep-alive> | ||||
|     <MainTabBar/> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import HelloWorld from './components/HelloWorld.vue' | ||||
| import MainTabBar from "components/content/mainTabbar/MainTabBar"; | ||||
| 
 | ||||
| 
 | ||||
| export default { | ||||
|   name: 'App', | ||||
|   components: { | ||||
|     HelloWorld | ||||
|     MainTabBar | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style> | ||||
| #app { | ||||
|   font-family: Avenir, Helvetica, Arial, sans-serif; | ||||
|   -webkit-font-smoothing: antialiased; | ||||
|   -moz-osx-font-smoothing: grayscale; | ||||
|   text-align: center; | ||||
|   color: #2c3e50; | ||||
|   margin-top: 60px; | ||||
| } | ||||
| @import "./assets/css/base.css"; | ||||
| </style> | ||||
|  | ||||
| @ -0,0 +1,341 @@ | ||||
| /*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */ | ||||
| 
 | ||||
| /* Document | ||||
|    ========================================================================== */ | ||||
| 
 | ||||
| /** | ||||
|  * 1. Correct the line height in all browsers. | ||||
|  * 2. Prevent adjustments of font size after orientation changes in iOS. | ||||
|  */ | ||||
| 
 | ||||
| html { | ||||
|   line-height: 1.15; /* 1 */ | ||||
|   -webkit-text-size-adjust: 100%; /* 2 */ | ||||
| } | ||||
| 
 | ||||
| /* Sections | ||||
|    ========================================================================== */ | ||||
| 
 | ||||
| /** | ||||
|  * Remove the margin in all browsers. | ||||
|  */ | ||||
| 
 | ||||
| body { | ||||
|   margin: 0; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Correct the font size and margin on `h1` elements within `section` and | ||||
|  * `article` contexts in Chrome, Firefox, and Safari. | ||||
|  */ | ||||
| 
 | ||||
| h1 { | ||||
|   font-size: 2em; | ||||
|   margin: 0.67em 0; | ||||
| } | ||||
| 
 | ||||
| /* Grouping content | ||||
|    ========================================================================== */ | ||||
| 
 | ||||
| /** | ||||
|  * 1. Add the correct box sizing in Firefox. | ||||
|  * 2. Show the overflow in Edge and IE. | ||||
|  */ | ||||
| 
 | ||||
| hr { | ||||
|   box-sizing: content-box; /* 1 */ | ||||
|   height: 0; /* 1 */ | ||||
|   overflow: visible; /* 2 */ | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 1. Correct the inheritance and scaling of font size in all browsers. | ||||
|  * 2. Correct the odd `em` font sizing in all browsers. | ||||
|  */ | ||||
| 
 | ||||
| pre { | ||||
|   font-family: monospace, monospace; /* 1 */ | ||||
|   font-size: 1em; /* 2 */ | ||||
| } | ||||
| 
 | ||||
| /* Text-level semantics | ||||
|    ========================================================================== */ | ||||
| 
 | ||||
| /** | ||||
|  * Remove the gray background on active links in IE 10. | ||||
|  */ | ||||
| 
 | ||||
| a { | ||||
|   background-color: transparent; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 1. Remove the bottom border in Chrome 57- | ||||
|  * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. | ||||
|  */ | ||||
| 
 | ||||
| abbr[title] { | ||||
|   border-bottom: none; /* 1 */ | ||||
|   text-decoration: underline; /* 2 */ | ||||
|   text-decoration: underline dotted; /* 2 */ | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Add the correct font weight in Chrome, Edge, and Safari. | ||||
|  */ | ||||
| 
 | ||||
| b, | ||||
| strong { | ||||
|   font-weight: bolder; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 1. Correct the inheritance and scaling of font size in all browsers. | ||||
|  * 2. Correct the odd `em` font sizing in all browsers. | ||||
|  */ | ||||
| 
 | ||||
| code, | ||||
| kbd, | ||||
| samp { | ||||
|   font-family: monospace, monospace; /* 1 */ | ||||
|   font-size: 1em; /* 2 */ | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Add the correct font size in all browsers. | ||||
|  */ | ||||
| 
 | ||||
| small { | ||||
|   font-size: 80%; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Prevent `sub` and `sup` elements from affecting the line height in | ||||
|  * all browsers. | ||||
|  */ | ||||
| 
 | ||||
| sub, | ||||
| sup { | ||||
|   font-size: 75%; | ||||
|   line-height: 0; | ||||
|   position: relative; | ||||
|   vertical-align: baseline; | ||||
| } | ||||
| 
 | ||||
| sub { | ||||
|   bottom: -0.25em; | ||||
| } | ||||
| 
 | ||||
| sup { | ||||
|   top: -0.5em; | ||||
| } | ||||
| 
 | ||||
| /* Embedded content | ||||
|    ========================================================================== */ | ||||
| 
 | ||||
| /** | ||||
|  * Remove the border on images inside links in IE 10. | ||||
|  */ | ||||
| 
 | ||||
| img { | ||||
|   border-style: none; | ||||
| } | ||||
| 
 | ||||
| /* Forms | ||||
|    ========================================================================== */ | ||||
| 
 | ||||
| /** | ||||
|  * 1. Change the font styles in all browsers. | ||||
|  * 2. Remove the margin in Firefox and Safari. | ||||
|  */ | ||||
| 
 | ||||
| button, | ||||
| input, | ||||
| optgroup, | ||||
| select, | ||||
| textarea { | ||||
|   font-family: inherit; /* 1 */ | ||||
|   font-size: 100%; /* 1 */ | ||||
|   line-height: 1.15; /* 1 */ | ||||
|   margin: 0; /* 2 */ | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Show the overflow in IE. | ||||
|  * 1. Show the overflow in Edge. | ||||
|  */ | ||||
| 
 | ||||
| button, | ||||
| input { /* 1 */ | ||||
|   overflow: visible; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Remove the inheritance of text transform in Edge, Firefox, and IE. | ||||
|  * 1. Remove the inheritance of text transform in Firefox. | ||||
|  */ | ||||
| 
 | ||||
| button, | ||||
| select { /* 1 */ | ||||
|   text-transform: none; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Correct the inability to style clickable types in iOS and Safari. | ||||
|  */ | ||||
| 
 | ||||
| button, | ||||
| [type="button"], | ||||
| [type="reset"], | ||||
| [type="submit"] { | ||||
|   -webkit-appearance: button; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Remove the inner border and padding in Firefox. | ||||
|  */ | ||||
| 
 | ||||
| button::-moz-focus-inner, | ||||
| [type="button"]::-moz-focus-inner, | ||||
| [type="reset"]::-moz-focus-inner, | ||||
| [type="submit"]::-moz-focus-inner { | ||||
|   border-style: none; | ||||
|   padding: 0; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Restore the focus styles unset by the previous rule. | ||||
|  */ | ||||
| 
 | ||||
| button:-moz-focusring, | ||||
| [type="button"]:-moz-focusring, | ||||
| [type="reset"]:-moz-focusring, | ||||
| [type="submit"]:-moz-focusring { | ||||
|   outline: 1px dotted ButtonText; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Correct the padding in Firefox. | ||||
|  */ | ||||
| 
 | ||||
| fieldset { | ||||
|   padding: 0.35em 0.75em 0.625em; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 1. Correct the text wrapping in Edge and IE. | ||||
|  * 2. Correct the color inheritance from `fieldset` elements in IE. | ||||
|  * 3. Remove the padding so developers are not caught out when they zero out | ||||
|  *    `fieldset` elements in all browsers. | ||||
|  */ | ||||
| 
 | ||||
| legend { | ||||
|   box-sizing: border-box; /* 1 */ | ||||
|   color: inherit; /* 2 */ | ||||
|   display: table; /* 1 */ | ||||
|   max-width: 100%; /* 1 */ | ||||
|   padding: 0; /* 3 */ | ||||
|   white-space: normal; /* 1 */ | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Add the correct vertical alignment in Chrome, Firefox, and Opera. | ||||
|  */ | ||||
| 
 | ||||
| progress { | ||||
|   vertical-align: baseline; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Remove the default vertical scrollbar in IE 10+. | ||||
|  */ | ||||
| 
 | ||||
| textarea { | ||||
|   overflow: auto; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 1. Add the correct box sizing in IE 10. | ||||
|  * 2. Remove the padding in IE 10. | ||||
|  */ | ||||
| 
 | ||||
| [type="checkbox"], | ||||
| [type="radio"] { | ||||
|   box-sizing: border-box; /* 1 */ | ||||
|   padding: 0; /* 2 */ | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Correct the cursor style of increment and decrement buttons in Chrome. | ||||
|  */ | ||||
| 
 | ||||
| [type="number"]::-webkit-inner-spin-button, | ||||
| [type="number"]::-webkit-outer-spin-button { | ||||
|   height: auto; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 1. Correct the odd appearance in Chrome and Safari. | ||||
|  * 2. Correct the outline style in Safari. | ||||
|  */ | ||||
| 
 | ||||
| [type="search"] { | ||||
|   -webkit-appearance: textfield; /* 1 */ | ||||
|   outline-offset: -2px; /* 2 */ | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Remove the inner padding in Chrome and Safari on macOS. | ||||
|  */ | ||||
| 
 | ||||
| [type="search"]::-webkit-search-decoration { | ||||
|   -webkit-appearance: none; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 1. Correct the inability to style clickable types in iOS and Safari. | ||||
|  * 2. Change font properties to `inherit` in Safari. | ||||
|  */ | ||||
| 
 | ||||
| ::-webkit-file-upload-button { | ||||
|   -webkit-appearance: button; /* 1 */ | ||||
|   font: inherit; /* 2 */ | ||||
| } | ||||
| 
 | ||||
| /* Interactive | ||||
|    ========================================================================== */ | ||||
| 
 | ||||
| /* | ||||
|  * Add the correct display in Edge, IE 10+, and Firefox. | ||||
|  */ | ||||
| 
 | ||||
| details { | ||||
|   display: block; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Add the correct display in all browsers. | ||||
|  */ | ||||
| 
 | ||||
| summary { | ||||
|   display: list-item; | ||||
| } | ||||
| 
 | ||||
| /* Misc | ||||
|    ========================================================================== */ | ||||
| 
 | ||||
| /** | ||||
|  * Add the correct display in IE 10+. | ||||
|  */ | ||||
| 
 | ||||
| template { | ||||
|   display: none; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Add the correct display in IE 10. | ||||
|  */ | ||||
| 
 | ||||
| [hidden] { | ||||
|   display: none; | ||||
| } | ||||
| After Width: | Height: | Size: 410 B | 
| After Width: | Height: | Size: 566 B | 
| After Width: | Height: | Size: 2.2 KiB | 
| After Width: | Height: | Size: 5.0 KiB | 
| After Width: | Height: | Size: 2.6 KiB | 
| After Width: | Height: | Size: 8.1 KiB | 
| After Width: | Height: | Size: 57 KiB | 
| After Width: | Height: | Size: 881 B | 
| After Width: | Height: | Size: 881 B | 
| After Width: | Height: | Size: 902 B | 
| After Width: | Height: | Size: 902 B | 
| After Width: | Height: | Size: 937 B | 
| After Width: | Height: | Size: 937 B | 
| After Width: | Height: | Size: 924 B | 
| After Width: | Height: | Size: 924 B | 
| Before Width: | Height: | Size: 6.7 KiB | 
| @ -0,0 +1,38 @@ | ||||
| import {debounce} from "@/common/utils"; | ||||
| 
 | ||||
| export const itemListenerMixin={ | ||||
|   data(){ | ||||
|     return{ | ||||
|       itemImgListener:null, | ||||
|     } | ||||
|   }, | ||||
| 
 | ||||
|   mounted(){ | ||||
|     const refresh = debounce(this.$refs.scroll.refresh,500) | ||||
| 
 | ||||
|     this.itemImgListener=()=>{ | ||||
|       refresh() | ||||
|     } | ||||
| 
 | ||||
|     this.$bus.$on('itemImgLoad',this.itemImgListener) | ||||
| 
 | ||||
|   } | ||||
| } | ||||
| export const backTopMixin={ | ||||
|   data(){ | ||||
|     return{ | ||||
|       isShowBackTop:false, | ||||
|       tabOffsetTop:0, | ||||
|       isTabFixed:false, | ||||
|     } | ||||
|   }, | ||||
|   methods:{ | ||||
|     backClick(){ | ||||
|       this.$refs.scroll.scrollTo(0,0) | ||||
|     }, | ||||
|     contentScoll(position){ | ||||
|       this.isShowBackTop=(-position.y)>1000 | ||||
|       this.isTabFixed=(-position.y)>this.tabOffsetTop | ||||
|     }, | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,37 @@ | ||||
| export function debounce(func,delay){ | ||||
|   let timer=null | ||||
|   //...args多个参数 delay是延迟执行 但timer已经赋值 再次传入timer清空
 | ||||
|   return function (...args){ | ||||
|     if(timer) clearTimeout(timer) | ||||
| 
 | ||||
|     timer=setTimeout(()=>{ | ||||
|       func.apply(this,args) | ||||
|     },delay) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export function formatDate(date, fmt) { | ||||
|   if (/(y+)/.test(fmt)) { | ||||
|     fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); | ||||
|   } | ||||
|   let o = { | ||||
|     'M+': date.getMonth() + 1, | ||||
|     'd+': date.getDate(), | ||||
|     'h+': date.getHours(), | ||||
|     'm+': date.getMinutes(), | ||||
|     's+': date.getSeconds() | ||||
|   }; | ||||
|   for (let k in o) { | ||||
|     if (new RegExp(`(${k})`).test(fmt)) { | ||||
|       let str = o[k] + ''; | ||||
|       fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str)); | ||||
|     } | ||||
|   } | ||||
|   return fmt; | ||||
| } | ||||
| 
 | ||||
| function padLeftZero (str) { | ||||
|   return ('00' + str).substr(str.length); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -1,57 +0,0 @@ | ||||
| <template> | ||||
|   <div class="hello"> | ||||
|     <h1>{{ msg }}</h1> | ||||
|     <p> | ||||
|       For a guide and recipes on how to configure / customize this project,<br> | ||||
|       check out the | ||||
|       <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>. | ||||
|     </p> | ||||
|     <h3>Installed CLI Plugins</h3> | ||||
|     <ul> | ||||
|       <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li> | ||||
|     </ul> | ||||
|     <h3>Essential Links</h3> | ||||
|     <ul> | ||||
|       <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li> | ||||
|       <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li> | ||||
|       <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li> | ||||
|       <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li> | ||||
|       <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li> | ||||
|     </ul> | ||||
|     <h3>Ecosystem</h3> | ||||
|     <ul> | ||||
|       <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li> | ||||
|       <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li> | ||||
|       <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li> | ||||
|       <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li> | ||||
|       <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li> | ||||
|     </ul> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
|   name: 'HelloWorld', | ||||
|   props: { | ||||
|     msg: String | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <!-- Add "scoped" attribute to limit CSS to this component only --> | ||||
| <style scoped> | ||||
| h3 { | ||||
|   margin: 40px 0 0; | ||||
| } | ||||
| ul { | ||||
|   list-style-type: none; | ||||
|   padding: 0; | ||||
| } | ||||
| li { | ||||
|   display: inline-block; | ||||
|   margin: 0 10px; | ||||
| } | ||||
| a { | ||||
|   color: #42b983; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,65 @@ | ||||
| <template> | ||||
|   <div class="wrapper" ref="wrapper"> | ||||
|     <div class="content"> | ||||
|       <slot></slot> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import BScroll from 'better-scroll' | ||||
| export default { | ||||
|   name: "Scroll", | ||||
|   props:{ | ||||
|     probeType:{ | ||||
|       type:Number, | ||||
|       default:0 | ||||
|     }, | ||||
|     pullUpLoad:{ | ||||
|       type:Boolean, | ||||
|       default: false | ||||
|     } | ||||
|   }, | ||||
|   data(){ | ||||
|     return{ | ||||
|       scroll:null | ||||
|     } | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.scroll=new BScroll(this.$refs.wrapper,{ | ||||
|       click:true, | ||||
|       probeType:this.probeType, | ||||
|       pullUpLoad: this.pullUpLoad | ||||
|     }) | ||||
|     this.scroll.on('scroll',(position)=>{ | ||||
|       this.$emit('scroll',position) | ||||
|     }) | ||||
| 
 | ||||
|     this.scroll.on('pullingUp',()=>{ | ||||
|       this.$emit('pullingUp') | ||||
|     }) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     this.scroll.scrollTo(0,0) | ||||
|   }, | ||||
|   methods:{ | ||||
|     scrollTo(x,y,time=3000){ | ||||
|       this.scroll && this.scroll.scrollTo(x,y,time) | ||||
|     }, | ||||
|     finishPullUp(){ | ||||
|       this.scroll && this.scroll.finishPullUp() | ||||
|     }, | ||||
|     refresh(){ | ||||
|       this.scroll && this.scroll.refresh() | ||||
|     }, | ||||
|     getScrolly(){ | ||||
|       return this.scroll ? this.scroll.y : 0 | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| 
 | ||||
| </style> | ||||
| @ -0,0 +1,29 @@ | ||||
| <template> | ||||
| <div class="nav-bar"> | ||||
|   <div class="left"><slot name="left"></slot></div> | ||||
|   <div class="center"><slot name="center"></slot></div> | ||||
|   <div class="right"><slot name="right"></slot></div> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
| name: "NavBar" | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| .nav-bar{ | ||||
|   display: flex; | ||||
|   line-height: 44px; | ||||
|   height: 44px; | ||||
|   text-align: center; | ||||
|   box-shadow: 0 1px 1px rgba(100,100,100,.1); | ||||
| } | ||||
| .left,.right{ | ||||
|   width:60px; | ||||
| } | ||||
| .center{ | ||||
|   flex:1; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,371 @@ | ||||
| <template> | ||||
|     <div id="hy-swiper"> | ||||
|       <div class="swiper" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd"> | ||||
|         <slot></slot> | ||||
|       </div> | ||||
|       <slot name="indicator"> | ||||
|       </slot> | ||||
|       <div class="indicator"> | ||||
|         <slot name="indicator" v-if="showIndicator && slideCount>1"> | ||||
|           <div v-for="(item, index) in slideCount" class="indi-item" :class="{active: index === currentIndex-1}" :key="index"></div> | ||||
|         </slot> | ||||
|       </div> | ||||
|     </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| 	export default { | ||||
| 		name: "Swiper", | ||||
|     props: { | ||||
|       interval: { | ||||
| 		    type: Number, | ||||
|         default: 3000 | ||||
|       }, | ||||
|       animDuration: { | ||||
| 		    type: Number, | ||||
|         default: 300 | ||||
|       }, | ||||
|       moveRatio: { | ||||
|         type: Number, | ||||
|         default: 0.25 | ||||
|       }, | ||||
|       showIndicator: { | ||||
|         type: Boolean, | ||||
|         default: true | ||||
|       } | ||||
|     }, | ||||
|     data: function () { | ||||
| 		  return { | ||||
|         slideCount: 0, // 元素个数 | ||||
|         totalWidth: 0, // swiper的宽度 | ||||
|         swiperStyle: {}, // swiper样式 | ||||
|         currentIndex: 1, // 当前的index | ||||
|         scrolling: false, // 是否正在滚动 | ||||
|       } | ||||
|     }, | ||||
|     mounted: function () { | ||||
|       // 1.操作DOM, 在前后添加Slide | ||||
|       setTimeout(() => { | ||||
|         this.handleDom(); | ||||
|         // 2.开启定时器 | ||||
|         this.startTimer(); | ||||
|       }, 500) | ||||
|     }, | ||||
|     methods: { | ||||
| 		  /** | ||||
|        * 定时器操作 | ||||
|        */ | ||||
|       startTimer: function () { | ||||
| 		    this.playTimer = window.setInterval(() => { | ||||
| 		      this.currentIndex++; | ||||
| 		      this.scrollContent(-this.currentIndex * this.totalWidth); | ||||
|         }, this.interval) | ||||
|       }, | ||||
|       stopTimer: function () { | ||||
|         window.clearInterval(this.playTimer); | ||||
|       }, | ||||
| 
 | ||||
|       /** | ||||
|        * 滚动到正确的位置 | ||||
|        */ | ||||
|       scrollContent: function (currentPosition) { | ||||
|         // 0.设置正在滚动 | ||||
|         this.scrolling = true; | ||||
| 
 | ||||
|         // 1.开始滚动动画 | ||||
|         this.swiperStyle.transition ='transform '+ this.animDuration + 'ms'; | ||||
|         this.setTransform(currentPosition); | ||||
| 
 | ||||
|         // 2.判断滚动到的位置 | ||||
|         this.checkPosition(); | ||||
| 
 | ||||
|         // 4.滚动完成 | ||||
|         this.scrolling = false | ||||
|       }, | ||||
| 
 | ||||
|       /** | ||||
|        * 校验正确的位置 | ||||
|        */ | ||||
|       checkPosition: function () { | ||||
|         window.setTimeout(() => { | ||||
|           // 1.校验正确的位置 | ||||
|           this.swiperStyle.transition = '0ms'; | ||||
|           if (this.currentIndex >= this.slideCount + 1) { | ||||
|             this.currentIndex = 1; | ||||
|             this.setTransform(-this.currentIndex * this.totalWidth); | ||||
|           } else if (this.currentIndex <= 0) { | ||||
|             this.currentIndex = this.slideCount; | ||||
|             this.setTransform(-this.currentIndex * this.totalWidth); | ||||
|           } | ||||
| 
 | ||||
|           // 2.结束移动后的回调 | ||||
|           this.$emit('transitionEnd', this.currentIndex-1); | ||||
|         }, this.animDuration) | ||||
|       }, | ||||
| 
 | ||||
|       /** | ||||
|        * 设置滚动的位置 | ||||
|        */ | ||||
|       setTransform: function (position) { | ||||
|         this.swiperStyle.transform = `translate3d(${position}px, 0, 0)`; | ||||
|         this.swiperStyle['-webkit-transform'] = `translate3d(${position}px), 0, 0`; | ||||
|         this.swiperStyle['-ms-transform'] = `translate3d(${position}px), 0, 0`; | ||||
|       }, | ||||
| 
 | ||||
|       /** | ||||
|        * 操作DOM, 在DOM前后添加Slide | ||||
|        */ | ||||
| 		  handleDom: function () { | ||||
|         // 1.获取要操作的元素 | ||||
|         let swiperEl = document.querySelector('.swiper'); | ||||
|         let slidesEls = swiperEl.getElementsByClassName('slide'); | ||||
|         // 2.保存个数 | ||||
|         this.slideCount = slidesEls.length; | ||||
| 
 | ||||
|         // 3.如果大于1个, 那么在前后分别添加一个slide | ||||
|         if (this.slideCount > 1) { | ||||
|           let cloneFirst = slidesEls[0].cloneNode(true); | ||||
|           let cloneLast = slidesEls[this.slideCount - 1].cloneNode(true); | ||||
|           swiperEl.insertBefore(cloneLast, slidesEls[0]); | ||||
|           swiperEl.appendChild(cloneFirst); | ||||
|           this.totalWidth = swiperEl.offsetWidth; | ||||
|           this.swiperStyle = swiperEl.style; | ||||
|         } | ||||
| 
 | ||||
|         // 4.让swiper元素, 显示第一个(目前是显示前面添加的最后一个元素) | ||||
|         this.setTransform(-this.totalWidth); | ||||
|       }, | ||||
| 
 | ||||
|       /** | ||||
|        * 拖动事件的处理 | ||||
|        */ | ||||
|       touchStart: function (e) { | ||||
|         // 1.如果正在滚动, 不可以拖动 | ||||
|         if (this.scrolling) return; | ||||
| 
 | ||||
|         // 2.停止定时器 | ||||
|         this.stopTimer(); | ||||
| 
 | ||||
|         // 3.保存开始滚动的位置 | ||||
|         this.startX = e.touches[0].pageX; | ||||
|       }, | ||||
| 
 | ||||
|       touchMove: function (e) { | ||||
|         // 1.计算出用户拖动的距离 | ||||
|         this.currentX = e.touches[0].pageX; | ||||
|         this.distance = this.currentX - this.startX; | ||||
|         let currentPosition = -this.currentIndex * this.totalWidth; | ||||
|         let moveDistance = this.distance + currentPosition; | ||||
| 
 | ||||
|         // 2.设置当前的位置 | ||||
|         this.setTransform(moveDistance); | ||||
|       }, | ||||
| 
 | ||||
|       touchEnd: function (e) { | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         // 1.获取移动的距离 | ||||
|         let currentMove = Math.abs(this.distance); | ||||
| 
 | ||||
|         // 2.判断最终的距离 | ||||
|         if (this.distance === 0) { | ||||
|           return | ||||
|         } else if (this.distance > 0 && currentMove > this.totalWidth * this.moveRatio) { // 右边移动超过0.5 | ||||
|           this.currentIndex-- | ||||
|         } else if (this.distance < 0 && currentMove > this.totalWidth * this.moveRatio) { // 向左移动超过0.5 | ||||
|           this.currentIndex++ | ||||
|         } | ||||
| 
 | ||||
|         // 3.移动到正确的位置 | ||||
|         this.scrollContent(-this.currentIndex * this.totalWidth); | ||||
| 
 | ||||
|         // 4.移动完成后重新开启定时器 | ||||
|         this.startTimer(); | ||||
|       }, | ||||
| 
 | ||||
|       /** | ||||
|        * 控制上一个, 下一个 | ||||
|        */ | ||||
|       previous: function () { | ||||
|         this.changeItem(-1); | ||||
|       }, | ||||
| 
 | ||||
|       next: function () { | ||||
|         this.changeItem(1); | ||||
|       }, | ||||
| 
 | ||||
|       changeItem: function (num) { | ||||
|         // 1.移除定时器 | ||||
|         this.stopTimer(); | ||||
| 
 | ||||
|         // 2.修改index和位置 | ||||
|         this.currentIndex += num; | ||||
|         this.scrollContent(-this.currentIndex * this.totalWidth); | ||||
| 
 | ||||
|         // 3.添加定时器 | ||||
|         this.startTimer(); | ||||
|       } | ||||
|     } | ||||
| 	} | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
|   #hy-swiper { | ||||
|     overflow: hidden; | ||||
|     position: relative; | ||||
|   } | ||||
| 
 | ||||
|   .swiper { | ||||
|     display: flex; | ||||
|   } | ||||
| 
 | ||||
|   .indicator { | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     position: absolute; | ||||
|     width: 100%; | ||||
|     bottom: 8px; | ||||
|   } | ||||
| 
 | ||||
|   .indi-item { | ||||
|     box-sizing: border-box; | ||||
|     width: 8px; | ||||
|     height: 8px; | ||||
|     border-radius: 4px; | ||||
|     background-color: #fff; | ||||
|     line-height: 8px; | ||||
|     text-align: center; | ||||
|     font-size: 12px; | ||||
|     margin: 0 5px; | ||||
|   } | ||||
| 
 | ||||
|   .indi-item.active { | ||||
|     background-color: rgba(212,62,46,1.0); | ||||
|   } | ||||
| </style> | ||||
| @ -0,0 +1,22 @@ | ||||
| <template> | ||||
|     <div class="slide"> | ||||
|       <slot></slot> | ||||
|     </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| 	export default { | ||||
| 		name: "Slide" | ||||
| 	} | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
|   .slide { | ||||
|     width: 100%; | ||||
|     flex-shrink: 0; | ||||
|   } | ||||
| 
 | ||||
|   .slide img { | ||||
|     width: 100%; | ||||
|   } | ||||
| </style> | ||||
| @ -0,0 +1,6 @@ | ||||
| import Swiper from './Swiper' | ||||
| import SwiperItem from './SwiperItem' | ||||
| 
 | ||||
| export { | ||||
|   Swiper, SwiperItem | ||||
| } | ||||
| @ -0,0 +1,24 @@ | ||||
| <template> | ||||
|   <div id="tab-bar"> | ||||
|    <slot></slot> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
|   name: "TabBar" | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| #tab-bar{ | ||||
|   display: flex; | ||||
|   background-color: #f6f6f6; | ||||
| 
 | ||||
|   position: fixed; | ||||
|   left: 0; | ||||
|   right: 0; | ||||
|   bottom:0; | ||||
|   box-shadow: 0 -3px 1px rgba(100,100,100,.1); | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,53 @@ | ||||
| <template> | ||||
|   <div class="tab-bar-item" @click="itemClick"> | ||||
|     <div  v-if="!isActive"><slot name="item-icon"></slot></div> | ||||
|     <div v-else><slot name="item-icon-active"></slot></div> | ||||
|     <div :style="activeStyle"><slot name="item-text"></slot></div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
|   name: "TabBarItem", | ||||
|   props:{ | ||||
|     path:String, | ||||
|     activeColor:{ | ||||
|       type:String, | ||||
|       default:'red' | ||||
|     } | ||||
|   }, | ||||
|   data(){ | ||||
|     return{ | ||||
|       // isActive:true | ||||
|     } | ||||
|   }, | ||||
|   computed:{ | ||||
|     isActive(){ | ||||
|       return this.$route.path.indexOf(this.path)!==-1 | ||||
|     }, | ||||
|     activeStyle(){ | ||||
|       return this.isActive ? {color:this.activeColor} : {} | ||||
|     } | ||||
|   }, | ||||
|   methods:{ | ||||
|     itemClick(){ | ||||
|       this.$router.replace(this.path) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| .tab-bar-item{ | ||||
|   flex:1; | ||||
|   text-align: center; | ||||
|   height: 49px; | ||||
| } | ||||
| .tab-bar-item img{ | ||||
|   width:24px; | ||||
|   height:24px; | ||||
|   margin-top: 3px; | ||||
|   vertical-align: middle; | ||||
|   margin-bottom: 2px; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,23 @@ | ||||
| <template> | ||||
| <div class="back-Top" > | ||||
|   <img src="@/assets/img/common/top.png" alt=""> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
|   name: "backTop", | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| .back-Top{ | ||||
|   position: fixed; | ||||
|   right: 8px; | ||||
|   bottom: 55px; | ||||
| } | ||||
| .back-Top img{ | ||||
|   width: 48px; | ||||
|   height: 48px; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,32 @@ | ||||
| <template> | ||||
| <div class="goods"> | ||||
|   <GoodsListItem v-for="(item, index) in goods" :key="index" :goodsItem="item"/> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import GoodsListItem from "@/components/content/goods/GoodsListItem"; | ||||
| 
 | ||||
| export default { | ||||
| name: "GoodsList", | ||||
|   components:{ | ||||
|   GoodsListItem | ||||
|   }, | ||||
|   props:{ | ||||
|   goods:{ | ||||
|     type:Array, | ||||
|     default(){ | ||||
|       return [] | ||||
|     } | ||||
|   } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| .goods{ | ||||
|   display: flex; | ||||
|   flex-wrap: wrap; | ||||
|   justify-content: space-around; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,85 @@ | ||||
| <template> | ||||
|   <div class="goods-items" @click="itemClick"> | ||||
|       <img :src="showImage"  alt="" @load="imageLoad"> | ||||
|       <div class="goods-info"> | ||||
|         <p>{{goodsItem.title}}</p> | ||||
|         <span class="price">{{goodsItem.price}}</span> | ||||
|         <span class="collect">{{goodsItem.cfav}}</span> | ||||
|       </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
| name: "GoodsListItem", | ||||
|   props:{ | ||||
|     goodsItem:{ | ||||
|       type:Object, | ||||
|       default(){ | ||||
|         return {} | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods:{ | ||||
|   imageLoad(){ | ||||
|     this.$bus.$emit('itemImageLoad') | ||||
|   }, | ||||
|     itemClick(){ | ||||
|       this.$router.push('/detail/'+this.goodsItem.iid) | ||||
|     } | ||||
|   }, | ||||
|   computed:{ | ||||
|   showImage(){ | ||||
|     return this.goodsItem.image || this.goodsItem.show.img | ||||
|   } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| .goods-items { | ||||
|   padding-bottom: 40px; | ||||
|   position: relative; | ||||
| 
 | ||||
|   width:48%; | ||||
| } | ||||
| .goods-items img { | ||||
|   width: 100%; | ||||
| } | ||||
| 
 | ||||
| .goods-info { | ||||
|   font-size: 12px; | ||||
|   position: absolute; | ||||
|   bottom: 5px; | ||||
|   left: 0; | ||||
|   right: 0; | ||||
|   overflow: hidden; | ||||
|   text-align: center; | ||||
| } | ||||
| 
 | ||||
| .goods-info p { | ||||
|   overflow: hidden; | ||||
|   text-overflow: ellipsis; | ||||
|   white-space: nowrap; | ||||
|   margin-bottom: 3px; | ||||
| } | ||||
| 
 | ||||
| .goods-info .price { | ||||
|   color: var(--color-high-text); | ||||
|   margin-right: 20px; | ||||
| } | ||||
| 
 | ||||
| .goods-info .collect { | ||||
|   position: relative; | ||||
| } | ||||
| 
 | ||||
| .goods-info .collect::before { | ||||
|   content: ''; | ||||
|   position: absolute; | ||||
|   left: -15px; | ||||
|   top: 0; | ||||
|   width: 14px; | ||||
|   height: 14px; | ||||
|   background: url("~assets/img/common/collect.svg") 0 0/14px 14px; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,42 @@ | ||||
| <template> | ||||
|   <tab-bar> | ||||
|     <tab-bar-item path="/home" activeColor="red"> | ||||
|       <img slot="item-icon"    src="~assets/img/tabbar/home.svg" alt=""> | ||||
|       <img slot="item-icon-active"    src="~assets/img/tabbar/home_active.svg" alt=""> | ||||
|       <div slot="item-text">首页</div> | ||||
|     </tab-bar-item> | ||||
|     <tab-bar-item path="/category" activeColor="red"> | ||||
|       <img slot="item-icon"    src="~assets/img/tabbar/category.svg" alt=""> | ||||
|       <img slot="item-icon-active"    src="~assets/img/tabbar/category_active.svg" alt=""> | ||||
|       <div slot="item-text">分类</div> | ||||
|     </tab-bar-item> | ||||
|     <tab-bar-item path="/cart" activeColor="red"> | ||||
|       <img slot="item-icon"    src="~assets/img/tabbar/cart.svg" alt=""> | ||||
|       <img slot="item-icon-active"    src="~assets/img/tabbar/cart_active.svg" alt=""> | ||||
|       <div slot="item-text">购物车</div> | ||||
|     </tab-bar-item> | ||||
|     <tab-bar-item path="/profile" activeColor="red"> | ||||
|       <img slot="item-icon"    src="~assets/img/tabbar/profile.svg" alt=""> | ||||
|       <img slot="item-icon-active"    src="~assets/img/tabbar/profile_active.svg" alt=""> | ||||
|       <div slot="item-text">我的</div> | ||||
|     </tab-bar-item> | ||||
|   </tab-bar> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import TabBar from "@/components/common/tabbar/TabBar"; | ||||
| import TabBarItem from "@/components/common/tabbar/TabBarItem"; | ||||
| 
 | ||||
| export default { | ||||
| 
 | ||||
| name: "MainTabBar", | ||||
|   components:{ | ||||
|     TabBar, | ||||
|     TabBarItem | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| 
 | ||||
| </style> | ||||
| @ -0,0 +1,55 @@ | ||||
| <template> | ||||
| <div class="tab-control"> | ||||
|   <div v-for="(item,index) in titles" | ||||
|        class="tab-control-item" :class="{active:index===currentIndex}" @click="itemclick(index)"> | ||||
|     <span>{{item}}</span> | ||||
|   </div> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
|   name: "TabControl", | ||||
|   props:{ | ||||
|     titles:{ | ||||
|       type:Array, | ||||
|       default(){ | ||||
|         return [] | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   data(){ | ||||
|     return{ | ||||
|       currentIndex:0 | ||||
|     } | ||||
|   }, | ||||
|   methods:{ | ||||
|     itemclick(index){ | ||||
|       this.currentIndex=index; | ||||
|       this.$emit('tabClick',index); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| .tab-control{ | ||||
|   display: flex; | ||||
|   text-align: center; | ||||
|   font-size: 15px; | ||||
|   height: 40px; | ||||
|   line-height: 40px; | ||||
|   background-color: #fff; | ||||
|   z-index: 9; | ||||
| } | ||||
| .tab-control-item{ | ||||
|   flex:1; | ||||
| } | ||||
| .tab-control-item span{ | ||||
|   padding: 5px; | ||||
| } | ||||
| 
 | ||||
| .active span{ | ||||
|   border-bottom: 3px solid var(--color-tint); | ||||
| } | ||||
| </style> | ||||
| @ -1,8 +1,11 @@ | ||||
| import Vue from 'vue' | ||||
| import App from './App.vue' | ||||
| import router from './router' | ||||
| 
 | ||||
| Vue.config.productionTip = false | ||||
| Vue.prototype.$bus = new Vue() | ||||
| 
 | ||||
| new Vue({ | ||||
|   render: h => h(App), | ||||
|   router, | ||||
| }).$mount('#app') | ||||
|  | ||||
| @ -0,0 +1,50 @@ | ||||
| import {request} from "@/network/request"; | ||||
| 
 | ||||
| export function getDetail(iid){ | ||||
|   return request({ | ||||
|     url:'/detail', | ||||
|     params:{ | ||||
|       iid | ||||
|     } | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| export function getRecommend(){ | ||||
|   return request({ | ||||
|     url:'/recommend' | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| export class Goods{ | ||||
|   constructor(itemInfo, columns, services) { | ||||
|     this.title = itemInfo.title; | ||||
|     this.desc = itemInfo.desc; | ||||
|     this.newPrice = itemInfo.price; | ||||
|     this.oldPrice = itemInfo.oldPrice; | ||||
|     this.discount = itemInfo.discountDesc; | ||||
|     this.columns = columns; | ||||
|     this.services = services; | ||||
|     this.nowPrice = itemInfo.highNowPrice; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class Shop { | ||||
|   constructor(shopInfo) { | ||||
|     this.logo = shopInfo.shopLogo; | ||||
|     this.name = shopInfo.name; | ||||
|     this.fans = shopInfo.cFans; | ||||
|     this.sells = shopInfo.cSells; | ||||
|     this.score = shopInfo.score; | ||||
|     this.goodsCount = shopInfo.cGoods | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class GoodsParam { | ||||
|   constructor(info, rule) { | ||||
|     // 注: images可能没有值(某些商品有值, 某些没有值)
 | ||||
|     this.image = info.images ? info.images[0] : ''; | ||||
|     this.infos = info.set; | ||||
|     this.sizes = rule.tables; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @ -0,0 +1,18 @@ | ||||
| import {request} from "@/network/request"; | ||||
| 
 | ||||
| export function getHomeMutidata(){ | ||||
|   return request({ | ||||
|     url:'/home/multidata' | ||||
|   }) | ||||
| } | ||||
| export function getHomeGoods(type,page){ | ||||
|   return request({ | ||||
|     url:'/home/data', | ||||
|     params:{ | ||||
|       type, | ||||
|       page | ||||
|     } | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -0,0 +1,26 @@ | ||||
| import axios from 'axios' | ||||
| 
 | ||||
| export function request(config){ | ||||
|   const  instance =axios.create({ | ||||
|     baseURL:'http://152.136.185.210:8000/api/w6', | ||||
|     timeout:5000 | ||||
|   }) | ||||
| 
 | ||||
|   // //拦截
 | ||||
|   // instance.interceptors.request.use(config=>{
 | ||||
|   //     console.log(config);
 | ||||
|   //     return config
 | ||||
|   //   },
 | ||||
|   //   err=>{
 | ||||
|   //     // console.log(err)
 | ||||
|   //   })
 | ||||
|   //
 | ||||
|   // instance.interceptors.request.use(res=>{
 | ||||
|   //   return res.get
 | ||||
|   // },err=>{
 | ||||
|   //   console.log(err);
 | ||||
|   // })
 | ||||
| 
 | ||||
|   return instance(config) | ||||
| } | ||||
| 
 | ||||
| @ -0,0 +1,41 @@ | ||||
| import Vue from 'vue' | ||||
| import Router from 'vue-router' | ||||
| 
 | ||||
| const Home=()=>import('../views/home/Home') | ||||
| const Category=()=>import('../views/category/Category') | ||||
| const Cart=()=>import('../views/cart/Cart') | ||||
| const Profile=()=>import('../views/profile/Profile') | ||||
| const Detail=()=>import('../views/detail/Detail') | ||||
| Vue.use(Router) | ||||
| 
 | ||||
| const routes=[ | ||||
|   { | ||||
|     path:'', | ||||
|     redirect:'/home' | ||||
|   }, | ||||
|   { | ||||
|     path:'/home', | ||||
|     component:Home | ||||
|   }, | ||||
|   { | ||||
|     path:'/category', | ||||
|     component:Category | ||||
|   }, | ||||
|   { | ||||
|     path:'/cart', | ||||
|     component:Cart | ||||
|   }, | ||||
|   { | ||||
|     path: '/profile', | ||||
|     component: Profile | ||||
|   }, | ||||
|   { | ||||
|     path: '/detail/:iid', | ||||
|     component: Detail | ||||
|   } | ||||
| ] | ||||
| const router =new Router({ | ||||
|   routes, | ||||
|   mode:'history' | ||||
| }) | ||||
| export default router | ||||
| @ -0,0 +1,15 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <h2>购物车</h2> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
| name: "Home" | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| 
 | ||||
| </style> | ||||
| @ -0,0 +1,152 @@ | ||||
| <template> | ||||
|   <div class="wrapper" ref="aaaa"> | ||||
|     <ul > | ||||
|       <button @click="btnClick">按钮</button> | ||||
|       <li>分类列表1</li> | ||||
|       <li>分类列表2</li> | ||||
|       <li>分类列表3</li> | ||||
|       <li>分类列表4</li> | ||||
|       <li>分类列表5</li> | ||||
|       <li>分类列表6</li> | ||||
|       <li>分类列表7</li> | ||||
|       <li>分类列表8</li> | ||||
|       <li>分类列表9</li> | ||||
|       <li>分类列表10</li> | ||||
|       <li>分类列表11</li> | ||||
|       <li>分类列表12</li> | ||||
|       <li>分类列表13</li> | ||||
|       <li>分类列表14</li> | ||||
|       <li>分类列表15</li> | ||||
|       <li>分类列表16</li> | ||||
|       <li>分类列表17</li> | ||||
|       <li>分类列表18</li> | ||||
|       <li>分类列表19</li> | ||||
|       <li>分类列表20</li> | ||||
|       <li>分类列表21</li> | ||||
|       <li>分类列表22</li> | ||||
|       <li>分类列表23</li> | ||||
|       <li>分类列表24</li> | ||||
|       <li>分类列表25</li> | ||||
|       <li>分类列表26</li> | ||||
|       <li>分类列表27</li> | ||||
|       <li>分类列表28</li> | ||||
|       <li>分类列表29</li> | ||||
|       <li>分类列表30</li> | ||||
|       <li>分类列表31</li> | ||||
|       <li>分类列表32</li> | ||||
|       <li>分类列表33</li> | ||||
|       <li>分类列表34</li> | ||||
|       <li>分类列表35</li> | ||||
|       <li>分类列表36</li> | ||||
|       <li>分类列表37</li> | ||||
|       <li>分类列表38</li> | ||||
|       <li>分类列表39</li> | ||||
|       <li>分类列表40</li> | ||||
|       <li>分类列表41</li> | ||||
|       <li>分类列表42</li> | ||||
|       <li>分类列表43</li> | ||||
|       <li>分类列表44</li> | ||||
|       <li>分类列表45</li> | ||||
|       <li>分类列表46</li> | ||||
|       <li>分类列表47</li> | ||||
|       <li>分类列表48</li> | ||||
|       <li>分类列表49</li> | ||||
|       <li>分类列表50</li> | ||||
|       <li>分类列表51</li> | ||||
|       <li>分类列表52</li> | ||||
|       <li>分类列表53</li> | ||||
|       <li>分类列表54</li> | ||||
|       <li>分类列表55</li> | ||||
|       <li>分类列表56</li> | ||||
|       <li>分类列表57</li> | ||||
|       <li>分类列表58</li> | ||||
|       <li>分类列表59</li> | ||||
|       <li>分类列表60</li> | ||||
|       <li>分类列表61</li> | ||||
|       <li>分类列表62</li> | ||||
|       <li>分类列表63</li> | ||||
|       <li>分类列表64</li> | ||||
|       <li>分类列表65</li> | ||||
|       <li>分类列表66</li> | ||||
|       <li>分类列表67</li> | ||||
|       <li>分类列表68</li> | ||||
|       <li>分类列表69</li> | ||||
|       <li>分类列表70</li> | ||||
|       <li>分类列表71</li> | ||||
|       <li>分类列表72</li> | ||||
|       <li>分类列表73</li> | ||||
|       <li>分类列表74</li> | ||||
|       <li>分类列表75</li> | ||||
|       <li>分类列表76</li> | ||||
|       <li>分类列表77</li> | ||||
|       <li>分类列表78</li> | ||||
|       <li>分类列表79</li> | ||||
|       <li>分类列表80</li> | ||||
|       <li>分类列表81</li> | ||||
|       <li>分类列表82</li> | ||||
|       <li>分类列表83</li> | ||||
|       <li>分类列表84</li> | ||||
|       <li>分类列表85</li> | ||||
|       <li>分类列表86</li> | ||||
|       <li>分类列表87</li> | ||||
|       <li>分类列表88</li> | ||||
|       <li>分类列表89</li> | ||||
|       <li>分类列表90</li> | ||||
|       <li>分类列表91</li> | ||||
|       <li>分类列表92</li> | ||||
|       <li>分类列表93</li> | ||||
|       <li>分类列表94</li> | ||||
|       <li>分类列表95</li> | ||||
|       <li>分类列表96</li> | ||||
|       <li>分类列表97</li> | ||||
|       <li>分类列表98</li> | ||||
|       <li>分类列表99</li> | ||||
|       <li>分类列表100</li> | ||||
|     </ul> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
|  import BScroll from 'better-scroll' | ||||
| 
 | ||||
| export default { | ||||
|   name: "Category", | ||||
|   data(){ | ||||
|     return { | ||||
|       scroll:null | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.scroll=new BScroll(document.querySelector('.wrapper'),{ | ||||
|       probeType:3, | ||||
|       pullUpLoad:true, | ||||
|     }) | ||||
| 
 | ||||
|     this.scroll.on('scroll',(position)=>{ | ||||
|       // console.log(position); | ||||
|     }) | ||||
| 
 | ||||
|     this.scroll.on('pullingUp',()=>{ | ||||
|       console.log('上拉加载更多'); | ||||
|     }) | ||||
|   }, | ||||
|   methods:{ | ||||
|     btnClick(){ | ||||
|       console.log('ctnClick'); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| .wrapper{ | ||||
|   height: 150px; | ||||
|   background-color: red; | ||||
| 
 | ||||
|   /*overflow: hidden;*/ | ||||
|   overflow-y:scroll; | ||||
| } | ||||
| 
 | ||||
| </style> | ||||
| @ -0,0 +1,168 @@ | ||||
| <template> | ||||
|   <div id="detail" > | ||||
|       <DetailNewBar class="detail-nav" @titleClick="titleClick" ref="nav"/> | ||||
|       <scroll class="content" | ||||
|               ref="scroll" | ||||
|               @scroll="totalScroll" | ||||
|               :probe-type="3" > | ||||
|       <DetailSwiper :top-images="topImages"/> | ||||
|       <DetailBaseInfo :goods="goods"/> | ||||
|       <DetailShopInfo :shop="shop" /> | ||||
|       <DetailGoodsInfo :detail-info="detailInfo" @detailImageload="detailImageload"/> | ||||
|       <DetailParamInfo ref="params" :param-info="paramInfo"/> | ||||
|       <DetailCommentInfo ref="comment" :comment-info="commentInfo"/> | ||||
|       <GoodsList ref="recommend" :goods="recommends"></GoodsList> | ||||
|     </scroll> | ||||
|     <back-top @click.native="backClick" v-show="isShowBackTop"/> | ||||
|     <detail-bottom-bar @addToCart="addToCart"/> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import DetailNewBar from "@/views/detail/childComps/DetailNewBar"; | ||||
| import DetailSwiper from "@/views/detail/childComps/DetailSwiper"; | ||||
| import DetailBaseInfo from "@/views/detail/childComps/DetailBaseInfo"; | ||||
| import DetailShopInfo from "@/views/detail/childComps/DetailShopInfo"; | ||||
| import DetailGoodsInfo from "@/views/detail/childComps/DetailGoodsInfo"; | ||||
| import DetailParamInfo from "@/views/detail/childComps/DetailParamInfo"; | ||||
| import DetailCommentInfo from "@/views/detail/childComps/DetailCommentInfo"; | ||||
| import DetailBottomBar from "@/views/detail/childComps/DetailBottomBar"; | ||||
| 
 | ||||
| import backTop from "@/components/content/backTop/backTop"; | ||||
| import GoodsList from "@/components/content/goods/GoodsList"; | ||||
| import scroll from "@/components/common/Scroll/Scroll"; | ||||
| 
 | ||||
| import {itemListenerMixin,backTopMixin} from "@/common/mixin"; | ||||
| import {debounce} from "@/common/utils"; | ||||
| 
 | ||||
| import {getDetail, Goods, Shop, GoodsParam, getRecommend} from "@/network/detail"; | ||||
| 
 | ||||
| 
 | ||||
| export default { | ||||
|   name: "Detail", | ||||
|   components: { | ||||
|     DetailNewBar, | ||||
|     DetailSwiper, | ||||
|     DetailBaseInfo, | ||||
|     DetailShopInfo, | ||||
|     DetailGoodsInfo, | ||||
|     DetailParamInfo, | ||||
|     DetailCommentInfo, | ||||
|     DetailBottomBar, | ||||
| 
 | ||||
|     backTop, | ||||
|     GoodsList, | ||||
|     scroll, | ||||
| 
 | ||||
|   }, | ||||
|   mixins: [itemListenerMixin,backTopMixin], | ||||
|   data() { | ||||
|     return { | ||||
|       iid: null, | ||||
|       topImages: [], | ||||
|       goods: {}, | ||||
|       shop: {}, | ||||
|       detailInfo: {}, | ||||
|       paramInfo: {}, | ||||
|       commentInfo: {}, | ||||
|       recommends: [], | ||||
|       themeTopYs: [], | ||||
|       getThemeTopY: null, | ||||
|       currentIndex:0, | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     //home主页传入iid | ||||
|     this.iid = this.$route.params.iid | ||||
|     //数据的展示 | ||||
|     getDetail(this.iid).then(res => { | ||||
|       const data = res.data.result | ||||
|       //轮播图的切换 | ||||
|       this.topImages = data.itemInfo.topImages | ||||
|       //商品介绍 | ||||
|       this.goods = new Goods(data.itemInfo, data.columns, data.shopInfo.services) | ||||
|       //店铺名的展示 | ||||
|       this.shop = new Shop(data.shopInfo) | ||||
|       //穿着展示 | ||||
|       this.detailInfo = data.detailInfo | ||||
|       //商品推荐的展示 | ||||
|       this.paramInfo = new GoodsParam(data.itemParams.info, data.itemParams.rule) | ||||
| 
 | ||||
|       if (data.rate.list) { | ||||
|         this.commentInfo = data.rate.list[0]; | ||||
|       } | ||||
|       //导航栏点击切换 | ||||
|       this.getThemeTopY = debounce(() => { | ||||
|         this.themeTopYs = [] | ||||
|         this.themeTopYs.push(0); | ||||
|         this.themeTopYs.push(this.$refs.params.$el.offsetTop) | ||||
|         this.themeTopYs.push(this.$refs.comment.$el.offsetTop) | ||||
|         this.themeTopYs.push(this.$refs.recommend.$el.offsetTop) | ||||
|         this.themeTopYs.push(Number.MAX_VALUE) | ||||
|       }, 500) | ||||
| 
 | ||||
|     }) | ||||
|     //获取评论的数据 | ||||
|     getRecommend().then(res => { | ||||
|       this.recommends = res.data.data.list | ||||
|     }) | ||||
|   }, | ||||
|   mounted() { | ||||
|   }, | ||||
|   destroyed() { | ||||
|     //无keep-live时activated无法使用 | ||||
|     this.$bus.$off('itemImgLoad', this.itemImgListener) | ||||
|   }, | ||||
|   methods: { | ||||
|     //上拉图片加载 | ||||
|     detailImageload() { | ||||
|       this.itemImgListener() | ||||
|       this.getThemeTopY() | ||||
|     }, | ||||
|     //导航栏点击切换 | ||||
|     titleClick(index) { | ||||
|       this.$refs.scroll.scrollTo(0, -this.themeTopYs[index], 1000); | ||||
|     }, | ||||
|     //位置移动时导航栏跟着移动 | ||||
|     positionScroll(position) { | ||||
|       const positionY = -position.y | ||||
|       let length = this.themeTopYs.length | ||||
|       for (let i = 0; i < length-1; i++) { | ||||
|         if(this.currentIndex!==i&&(positionY>=this.themeTopYs[i]&&positionY<this.themeTopYs[i+1])) | ||||
|         { | ||||
|           this .currentIndex=i; | ||||
|           this.$refs.nav.currentIndex=this.currentIndex | ||||
| 
 | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     //mixin混入回退顶部的按钮 | ||||
|     totalScroll(position){ | ||||
|       this.positionScroll(position) | ||||
|       this.contentScoll(position) | ||||
|     }, | ||||
|     //加入购物车 | ||||
|     addToCart(){ | ||||
|       console.log('----'); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| #detail{ | ||||
|   position: relative; | ||||
|   z-index: 9; | ||||
|   background-color: #ffffff; | ||||
|   height: 100vh; | ||||
| } | ||||
| .detail-nav{ | ||||
|   position: relative; | ||||
|   z-index: 9; | ||||
|   background-color: #ffffff; | ||||
| } | ||||
| .content{ | ||||
|   height: calc(100% - 96px); | ||||
|   position: relative; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,103 @@ | ||||
| <template> | ||||
|   <div v-if="Object.keys(goods).length !== 0" class="base-info"> | ||||
|     <div class="info-title">{{goods.title}}</div> | ||||
|     <div class="info-price"> | ||||
|       <span class="n-price">{{goods.newPrice}}</span> | ||||
|       <span class="o-price">{{goods.oldPrice}}</span> | ||||
|       <span class="discount">{{goods.discount}}</span> | ||||
|     </div> | ||||
|     <div class="info-other"> | ||||
|       <span>{{goods.columns[0]}}</span> | ||||
|       <span>{{goods.columns[1]}}</span> | ||||
|       <span>{{goods.services[goods.services.length-1].name}}</span> | ||||
|     </div> | ||||
|     <div class="info-service"> | ||||
|       <span class="info-service-item" v-for="index in goods.services.length-1" :key="index"> | ||||
|         <img :src="goods.services[index-1].icon"> | ||||
|         <span>{{goods.services[index-1].name}}</span> | ||||
|       </span> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| 	export default { | ||||
| 		name: "DetailBaseInfo", | ||||
|     props: { | ||||
| 		  goods: { | ||||
| 		    type: Object, | ||||
|         default(){ | ||||
| 		      return [] | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 	} | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
|   .base-info { | ||||
|     margin-top: 15px; | ||||
|     padding: 0 8px; | ||||
|     color: #999; | ||||
|     border-bottom: 5px solid #f2f5f8; | ||||
|   } | ||||
| 
 | ||||
|   .info-title { | ||||
|     color: #222 | ||||
|   } | ||||
| 
 | ||||
|   .info-price { | ||||
|     margin-top: 10px; | ||||
|   } | ||||
| 
 | ||||
|   .info-price .n-price { | ||||
|     font-size: 24px; | ||||
|     color: var(--color-high-text); | ||||
|   } | ||||
| 
 | ||||
|   .info-price .o-price { | ||||
|     font-size: 13px; | ||||
|     margin-left: 5px; | ||||
|     text-decoration: line-through; | ||||
|   } | ||||
| 
 | ||||
|   .info-price .discount { | ||||
|     font-size: 12px; | ||||
|     padding: 2px 5px; | ||||
|     color: #fff; | ||||
|     background-color: var(--color-high-text); | ||||
|     border-radius: 8px; | ||||
|     margin-left: 5px; | ||||
| 
 | ||||
|     /*让元素上浮一些: 使用相对定位即可*/ | ||||
|     position: relative; | ||||
|     top: -8px; | ||||
|   } | ||||
| 
 | ||||
|   .info-other { | ||||
|     margin-top: 15px; | ||||
|     line-height: 30px; | ||||
|     display: flex; | ||||
|     font-size: 13px; | ||||
|     border-bottom: 1px solid rgba(100,100,100,.1); | ||||
|     justify-content: space-between; | ||||
|   } | ||||
| 
 | ||||
|   .info-service { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     line-height: 60px; | ||||
|   } | ||||
| 
 | ||||
|   .info-service-item img { | ||||
|     width: 10px; | ||||
|     height: 10px; | ||||
|     position: relative; | ||||
|     top: 2px; | ||||
|   } | ||||
| 
 | ||||
|   .info-service-item span { | ||||
|     font-size: 13px; | ||||
|     color: #333; | ||||
|   } | ||||
| </style> | ||||
| @ -0,0 +1,91 @@ | ||||
| <template> | ||||
|   <div class="bottom-bar"> | ||||
|     <div class="bar-item bar-left"> | ||||
|       <div> | ||||
|         <i class="icon service"></i> | ||||
|         <span class="text">客服</span> | ||||
|       </div> | ||||
|       <div> | ||||
|         <i class="icon shop"></i> | ||||
|         <span class="text">店铺</span> | ||||
|       </div> | ||||
|       <div> | ||||
|         <i class="icon select"></i> | ||||
|         <span class="text">收藏</span> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="bar-item bar-right"> | ||||
|       <div class="cart" @click="addToCart">加入购物车</div> | ||||
|       <div class="buy">购买</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| 	export default { | ||||
| 		name: "DetailBottomBar", | ||||
|     methods: { | ||||
|       addToCart() { | ||||
|         this.$emit('addToCart') | ||||
|       } | ||||
|     } | ||||
| 	} | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
|   .bottom-bar { | ||||
|     height: 58px; | ||||
|     position: fixed; | ||||
|     background-color: #fff; | ||||
|     left: 0; | ||||
|     right: 0; | ||||
|     bottom: 0; | ||||
| 
 | ||||
|     display: flex; | ||||
|     text-align: center; | ||||
|   } | ||||
| 
 | ||||
|   .bar-item { | ||||
|     flex: 1; | ||||
|     display: flex; | ||||
|   } | ||||
| 
 | ||||
|   .bar-item>div { | ||||
|     flex: 1; | ||||
|   } | ||||
| 
 | ||||
|   .bar-left .text { | ||||
|     font-size: 13px; | ||||
|   } | ||||
| 
 | ||||
|   .bar-left .icon { | ||||
|     display: block; | ||||
|     width: 22px; | ||||
|     height: 22px; | ||||
|     margin: 10px auto 3px; | ||||
|     background: url("~assets/img/detail/detail_bottom.png") 0 0/100%; | ||||
|   } | ||||
| 
 | ||||
|   .bar-left .service { | ||||
|     background-position:0 -54px; | ||||
|   } | ||||
| 
 | ||||
|   .bar-left .shop { | ||||
|     background-position:0 -98px; | ||||
|   } | ||||
| 
 | ||||
|   .bar-right { | ||||
|     font-size: 15px; | ||||
|     color: #fff; | ||||
|     line-height: 58px; | ||||
|   } | ||||
| 
 | ||||
|   .bar-right .cart { | ||||
|     background-color: #ffe817; | ||||
|     color: #333; | ||||
|   } | ||||
| 
 | ||||
|   .bar-right .buy { | ||||
|     background-color: #f69; | ||||
|   } | ||||
| </style> | ||||
| @ -0,0 +1,118 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <div v-if="Object.keys(commentInfo).length !== 0" class="comment-info"> | ||||
|       <div class="info-header"> | ||||
|         <div class="header-title">用户评价</div> | ||||
|         <div class="header-more"> | ||||
|           更多 | ||||
|           <i class="arrow-right"></i> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="info-user"> | ||||
|         <img :src="commentInfo.user.avatar" alt=""> | ||||
|         <span>{{commentInfo.user.uname}}</span> | ||||
|       </div> | ||||
|       <div class="info-detail"> | ||||
|         <p>{{commentInfo.content}}</p> | ||||
|         <div class="info-other"> | ||||
|           <span class="date">{{commentInfo.created | showDate}}</span> | ||||
|           <span>{{commentInfo.style}}</span> | ||||
|         </div> | ||||
|         <div class="info-imgs"> | ||||
|           <img :src="item" v-for="(item, index) in commentInfo.images"> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
|   import {formatDate} from "@/common/utils"; | ||||
| 
 | ||||
|   export default { | ||||
| 		name: "DetailCommentInfo", | ||||
|     props: { | ||||
| 		  commentInfo: { | ||||
| 		    type: Object, | ||||
|       } | ||||
|     }, | ||||
|     filters: { | ||||
| 		  showDate: function (value) { | ||||
|         let date = new Date(value*1000); | ||||
|         return formatDate(date, 'yyyy-MM-dd') | ||||
|       } | ||||
|     } | ||||
| 	} | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
|   .comment-info { | ||||
|     padding: 5px 12px; | ||||
|     color: #333; | ||||
|     border-bottom: 5px solid #f2f5f8; | ||||
|   } | ||||
| 
 | ||||
|   .info-header { | ||||
|     height: 50px; | ||||
|     line-height: 50px; | ||||
|     border-bottom: 1px solid rgba(0,0,0,.1); | ||||
|   } | ||||
| 
 | ||||
|   .header-title { | ||||
|     float: left; | ||||
|     font-size: 15px; | ||||
|   } | ||||
| 
 | ||||
|   .header-more { | ||||
|     float: right; | ||||
|     margin-right: 10px; | ||||
|     font-size: 13px; | ||||
|   } | ||||
| 
 | ||||
|   .info-user { | ||||
|     padding: 10px 0 5px; | ||||
|   } | ||||
| 
 | ||||
|   .info-user img { | ||||
|     width: 42px; | ||||
|     height: 42px; | ||||
|     border-radius: 50%; | ||||
|   } | ||||
| 
 | ||||
|   .info-user span { | ||||
|     position: relative; | ||||
|     font-size: 15px; | ||||
|     top: -15px; | ||||
|     margin-left: 10px; | ||||
|   } | ||||
| 
 | ||||
|   .info-detail { | ||||
|     padding: 0 5px 15px; | ||||
|   } | ||||
| 
 | ||||
|   .info-detail p { | ||||
|     font-size: 14px; | ||||
|     color: #777; | ||||
|     line-height: 1.5; | ||||
|   } | ||||
| 
 | ||||
|   .info-detail .info-other { | ||||
|     font-size: 12px; | ||||
|     color: #999; | ||||
|     margin-top: 10px; | ||||
|   } | ||||
| 
 | ||||
|   .info-other .date { | ||||
|     margin-right: 8px; | ||||
|   } | ||||
| 
 | ||||
|   .info-imgs { | ||||
|     margin-top: 10px; | ||||
|   } | ||||
| 
 | ||||
|   .info-imgs img { | ||||
|     width: 70px; | ||||
|     height: 70px; | ||||
|     margin-right: 5px; | ||||
|   } | ||||
| </style> | ||||
| @ -0,0 +1,90 @@ | ||||
| <template> | ||||
|   <div v-if="Object.keys(detailInfo).length !== 0" class="goods-info" > | ||||
|     <div class="info-desc clear-fix"> | ||||
|       <div class="start"> | ||||
|       </div> | ||||
|       <div class="desc">{{detailInfo.desc}}</div> | ||||
|       <div class="end"></div> | ||||
|     </div> | ||||
|     <div class="info-key">{{detailInfo.detailImage[0].key}}</div> | ||||
|     <div class="info-list"> | ||||
|       <img v-for="(item, index) in detailInfo.detailImage[0].list" :key="index" :src="item" alt="" @load="imgLoad"> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| 	export default { | ||||
| 		name: "DetailGoodsInfo", | ||||
|     props: { | ||||
|       detailInfo: { | ||||
|         type: Object | ||||
|       } | ||||
|     }, | ||||
|     data(){ | ||||
| 		  return{ | ||||
| 		    rounter:0, | ||||
|         imagesLength:0, | ||||
|       } | ||||
|     }, | ||||
|     methods: { | ||||
|       imgLoad() { | ||||
|         this.$emit('detailImageload') | ||||
|       } | ||||
|     } | ||||
| 	} | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
|   .goods-info { | ||||
|     padding: 20px 0; | ||||
|     border-bottom: 5px solid #f2f5f8; | ||||
|   } | ||||
| 
 | ||||
|   .info-desc { | ||||
|     padding: 0 15px; | ||||
|   } | ||||
| 
 | ||||
|   .info-desc .start, .info-desc .end { | ||||
|     width: 90px; | ||||
|     height: 1px; | ||||
|     background-color: #a3a3a5; | ||||
|     position: relative; | ||||
|   } | ||||
| 
 | ||||
|   .info-desc .start { | ||||
|     float: left; | ||||
|   } | ||||
| 
 | ||||
|   .info-desc .end { | ||||
|     float: right; | ||||
|   } | ||||
| 
 | ||||
|   .info-desc .start::before, .info-desc .end::after { | ||||
|     content: ''; | ||||
|     position: absolute; | ||||
|     width: 5px; | ||||
|     height: 5px; | ||||
|     background-color: #333; | ||||
|     bottom: 0; | ||||
|   } | ||||
| 
 | ||||
|   .info-desc .end::after { | ||||
|     right: 0; | ||||
|   } | ||||
| 
 | ||||
|   .info-desc .desc { | ||||
|     padding: 15px 0; | ||||
|     font-size: 14px; | ||||
|   } | ||||
| 
 | ||||
|   .info-key { | ||||
|     margin: 10px 0 10px 15px; | ||||
|     color: #333; | ||||
|     font-size: 15px; | ||||
|   } | ||||
| 
 | ||||
|   .info-list img { | ||||
|     width: 100%; | ||||
|   } | ||||
| </style> | ||||
| @ -0,0 +1,56 @@ | ||||
| <template> | ||||
|   <nav-bar> | ||||
|     <div slot="left" class="back" @click="backClick"> | ||||
|       <img src="~assets/img/common/back.svg" alt=""> | ||||
|     </div> | ||||
|     <div slot="center" class="title"> | ||||
|       <div v-for="(item,index) in titles" | ||||
|            class="title-item" | ||||
|            :class="{active:index===currentIndex}" @click="titleClick(index)"> | ||||
|         {{item}} | ||||
|       </div> | ||||
|     </div> | ||||
|   </nav-bar> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import NavBar from "@/components/common/navbar/NavBar"; | ||||
| 
 | ||||
| export default { | ||||
|   name: "DetailNewBar", | ||||
|   components: { | ||||
|     NavBar | ||||
|   }, | ||||
|   data(){ | ||||
|     return{ | ||||
|       titles:['商品','参数','评论','推荐'], | ||||
|       currentIndex:0, | ||||
|     } | ||||
|   }, | ||||
|   methods:{ | ||||
|     titleClick(index){ | ||||
|       this.currentIndex=index; | ||||
|       this.$emit('titleClick',index) | ||||
|     }, | ||||
|     backClick(){ | ||||
|       this.$router.back() | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| .title{ | ||||
|   display: flex; | ||||
|   font-size: 13px; | ||||
| } | ||||
| .title-item{ | ||||
|   flex:1; | ||||
| } | ||||
| .active{ | ||||
|   color: var(--color-high-text); | ||||
| } | ||||
| .back img{ | ||||
|   margin-top: 12px; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,68 @@ | ||||
| <template> | ||||
|   <div class="param-info" v-if="Object.keys(paramInfo).length !== 0"> | ||||
|     <table v-for="(table, index) in paramInfo.sizes" | ||||
|            class="info-size" :key="index"> | ||||
|       <tr v-for="(tr, indey) in table" :key="indey"> | ||||
|         <td v-for="(td, indez) in tr" :key="indez">{{td}}</td> | ||||
|       </tr> | ||||
|     </table> | ||||
|     <table class="info-param"> | ||||
|       <tr v-for="(info, index) in paramInfo.infos"> | ||||
|         <td class="info-param-key">{{info.key}}</td> | ||||
|         <td class="param-value">{{info.value}}</td> | ||||
|       </tr> | ||||
|     </table> | ||||
|     <div class="info-img" v-if="paramInfo.image.length !== 0"> | ||||
|       <img :src="paramInfo.image" alt=""> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| 	export default { | ||||
| 		name: "DetailParamInfo", | ||||
|     props: { | ||||
| 		  paramInfo: { | ||||
| 		    type: Object | ||||
|       } | ||||
|     } | ||||
| 	} | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
|   .param-info { | ||||
|     padding: 20px 15px; | ||||
|     font-size: 14px; | ||||
|     border-bottom: 5px solid #f2f5f8; | ||||
|   } | ||||
| 
 | ||||
|   .param-info table { | ||||
|     width: 100%; | ||||
|     border-collapse: collapse; | ||||
|   } | ||||
| 
 | ||||
|   .param-info table tr { | ||||
|     height: 42px; | ||||
|   } | ||||
| 
 | ||||
|   .param-info table tr td { | ||||
|     border-bottom: 1px solid rgba(100,100,100,.1); | ||||
|   } | ||||
| 
 | ||||
|   .info-param-key { | ||||
|     /*当value的数据量比较大的时候, 会挤到key,所以给一个固定的宽度*/ | ||||
|     width: 95px; | ||||
|   } | ||||
| 
 | ||||
|   .info-param { | ||||
|     border-top: 1px solid rgba(0,0,0,.1); | ||||
|   } | ||||
| 
 | ||||
|   .param-value { | ||||
|     color: #eb4868 | ||||
|   } | ||||
| 
 | ||||
|   .info-img img { | ||||
|     width: 100%; | ||||
|   } | ||||
| </style> | ||||
| @ -0,0 +1,157 @@ | ||||
| <template> | ||||
|   <div class="shop-info"> | ||||
|     <div class="shop-top"> | ||||
|       <img :src="shop.logo"> | ||||
|       <span class="title">{{shop.name}}</span> | ||||
|     </div> | ||||
|     <div class="shop-middle"> | ||||
|       <div class="shop-middle-item shop-middle-left"> | ||||
|         <div class="info-sells"> | ||||
|           <div class="sells-count"> | ||||
|             {{shop.sells | sellCountFilter}} | ||||
|           </div> | ||||
|           <div class="sells-text">总销量</div> | ||||
|         </div> | ||||
|         <div class="info-goods"> | ||||
|           <div class="goods-count"> | ||||
|             {{shop.goodsCount}} | ||||
|           </div> | ||||
|           <div class="goods-text">全部宝贝</div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="shop-middle-item shop-middle-right"> | ||||
|         <table> | ||||
|           <tr v-for="(item, index) in shop.score" :key="index"> | ||||
|             <td>{{item.name}}</td> | ||||
|             <td class="score" :class="{'score-better': item.isBetter}">{{item.score}}</td> | ||||
|             <td class="better" :class="{'better-more': item.isBetter}"><span>{{item.isBetter ? '高':'低'}}</span></td> | ||||
|           </tr> | ||||
|         </table> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="shop-bottom"> | ||||
|       <div class="enter-shop">进店逛逛</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| 	export default { | ||||
| 		name: "DetailShopInfo", | ||||
|     props: { | ||||
| 		  shop: { | ||||
| 		    type: Object, | ||||
|         default(){ | ||||
| 		      return [] | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     filters: { | ||||
|       sellCountFilter: function (value) { | ||||
|         if (value < 10000) return value; | ||||
|         return (value/10000).toFixed(1) + '万' | ||||
|       } | ||||
|     } | ||||
| 	} | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
|   .shop-info { | ||||
|     padding: 25px 8px; | ||||
|     border-bottom: 5px solid #f2f5f8; | ||||
|   } | ||||
| 
 | ||||
|   .shop-top { | ||||
|     line-height: 45px; | ||||
|     /* 让元素垂直中心对齐 */ | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|   } | ||||
| 
 | ||||
|   .shop-top img { | ||||
|     width: 45px; | ||||
|     height: 45px; | ||||
|     border-radius: 50%; | ||||
|     border: 1px solid rgba(0,0,0,.1); | ||||
|   } | ||||
| 
 | ||||
|   .shop-top .title { | ||||
|     margin-left: 10px; | ||||
|     vertical-align: center; | ||||
|   } | ||||
| 
 | ||||
|   .shop-middle { | ||||
|     margin-top: 15px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|   } | ||||
| 
 | ||||
|   .shop-middle-item { | ||||
|     flex: 1; | ||||
|   } | ||||
| 
 | ||||
|   .shop-middle-left { | ||||
|     display: flex; | ||||
|     justify-content: space-evenly; | ||||
|     color: #333; | ||||
|     text-align: center; | ||||
|     border-right: 1px solid rgba(0,0,0,.1); | ||||
|   } | ||||
| 
 | ||||
|   .sells-count, .goods-count { | ||||
|     font-size: 18px; | ||||
|   } | ||||
| 
 | ||||
|   .sells-text, .goods-text { | ||||
|     margin-top: 10px; | ||||
|     font-size: 12px; | ||||
|   } | ||||
| 
 | ||||
|   .shop-middle-right { | ||||
|     font-size: 13px; | ||||
|     color: #333; | ||||
|   } | ||||
| 
 | ||||
|   .shop-middle-right table { | ||||
|     width: 120px; | ||||
|     margin-left: 30px; | ||||
|   } | ||||
| 
 | ||||
|   .shop-middle-right table td { | ||||
|     padding: 5px 0; | ||||
|   } | ||||
| 
 | ||||
|   .shop-middle-right .score { | ||||
|     color: #5ea732; | ||||
|   } | ||||
| 
 | ||||
|   .shop-middle-right .score-better { | ||||
|     color: #f13e3a; | ||||
|   } | ||||
| 
 | ||||
|   .shop-middle-right .better span { | ||||
|     background-color: #5ea732; | ||||
|     color: #fff; | ||||
|     text-align: center; | ||||
|   } | ||||
| 
 | ||||
|   .shop-middle-right .better-more span { | ||||
|     background-color: #f13e3a; | ||||
|   } | ||||
| 
 | ||||
|   .shop-bottom { | ||||
|     text-align: center; | ||||
|     margin-top: 10px; | ||||
|   } | ||||
| 
 | ||||
|   .enter-shop { | ||||
|     display: inline-block; | ||||
|     font-size: 14px; | ||||
|     background-color: #f2f5f8; | ||||
|     width: 150px; | ||||
|     height: 30px; | ||||
|     text-align: center; | ||||
|     line-height: 30px; | ||||
|     border-radius: 10px; | ||||
|   } | ||||
| </style> | ||||
| @ -0,0 +1,35 @@ | ||||
| <template> | ||||
|     <swiper class="swiper-item"> | ||||
|       <swiper-item  v-for="(item,index) in topImages"> | ||||
|         <img :src="item"  :key="index" alt=""> | ||||
|       </swiper-item> | ||||
|     </swiper> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import {Swiper,SwiperItem} from '@/components/common/swiper' | ||||
| 
 | ||||
| 
 | ||||
| export default { | ||||
| name: "DetailSwiper", | ||||
|   props:{ | ||||
|   topImages:{ | ||||
|     type:Array, | ||||
|     default(){ | ||||
|       return [] | ||||
|     } | ||||
|   } | ||||
|   }, | ||||
|   components:{ | ||||
|   SwiperItem, | ||||
|     Swiper, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| .swiper-item{ | ||||
|   height: 200px; | ||||
|   overflow: hidden; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,42 @@ | ||||
| <template> | ||||
|   <div class="recommends"> | ||||
|     <div v-for="item in recommends" class="recommends-item"> | ||||
|       <a :href="item.link"> | ||||
|         <img :src="item.image" alt=""> | ||||
|         <div>{{item.title}}</div> | ||||
|       </a> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
|   name: "HomeRecommendView", | ||||
|   props:{ | ||||
|     recommends:{ | ||||
|       type:Array, | ||||
|       default() { | ||||
|         return []; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| .recommends{ | ||||
|   display: flex; | ||||
|   width: 100%; | ||||
|   text-align: center; | ||||
|   font-size: 12px; | ||||
|   padding: 10px 0 20px; | ||||
|   border-bottom: 8px solid #eee; | ||||
| } | ||||
| .recommends-item{ | ||||
|   flex:1; | ||||
| } | ||||
| .recommends-item img{ | ||||
|   width: 65px; | ||||
|   height: 65px; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,45 @@ | ||||
| <template> | ||||
|   <swiper> | ||||
|     <swiperItem v-for="item in banners"> | ||||
|       <a :href="item.link" > | ||||
|         <img :src="item.image" alt="" @load="imageLoad"> | ||||
|       </a> | ||||
|     </swiperItem> | ||||
|   </swiper> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import {Swiper, SwiperItem} from "@/components/common/swiper/index" | ||||
| export default { | ||||
|   name: "HomeSwiper", | ||||
|   components:{ | ||||
|     Swiper, | ||||
|     SwiperItem | ||||
|   }, | ||||
|   props:{ | ||||
|     banners:{ | ||||
|       type:Array, | ||||
|       default(){ | ||||
|         return[] | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   data(){ | ||||
|     return { | ||||
|       isLoad:false | ||||
|     } | ||||
|   }, | ||||
|   methods:{ | ||||
|     imageLoad(){ | ||||
|       if(!this.isLoad) { | ||||
|         this.$emit('swiperImageLoad') | ||||
|         this.isLoad=true | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| 
 | ||||
| </style> | ||||
| @ -0,0 +1,20 @@ | ||||
| <template> | ||||
|   <div class="feature"> | ||||
|     <a href="https://act.mogujie.com/zzlx67"> | ||||
|       <img src="@/assets/img/home/recommend_bg.jpg" alt=""> | ||||
|     </a> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
|   name: "HomefeatureView" | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| .feature img{ | ||||
|   width: 100%; | ||||
| } | ||||
| 
 | ||||
| </style> | ||||
| @ -0,0 +1,15 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <h2>我的</h2> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
|   name: "Profile" | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| 
 | ||||
| </style> | ||||
| @ -0,0 +1,13 @@ | ||||
| module.exports={ | ||||
|     configureWebpack:{ | ||||
|         resolve:{ | ||||
|             alias:{ | ||||
|                 'assets':'@/assets', | ||||
|                 'common':'@/common', | ||||
|                 'components':'@/components', | ||||
|                 'network':'@/network', | ||||
|                 'views':'@/views', | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||