├── .editorconfig.js ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── bitbug_favicon.ico ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ ├── css │ │ ├── base.css │ │ └── normalize.css │ └── img │ │ ├── cart │ │ └── tick.svg │ │ ├── common │ │ ├── arrow-left.svg │ │ ├── back.svg │ │ ├── collect.svg │ │ ├── placeholder.png │ │ └── top.png │ │ ├── detail │ │ ├── cart.png │ │ └── detail_bottom.png │ │ ├── home │ │ └── recommend_bg.jpg │ │ ├── profile │ │ ├── arrow-right.png │ │ ├── avatar.svg │ │ ├── cart.svg │ │ ├── message.svg │ │ ├── phone.svg │ │ ├── pointer.svg │ │ ├── shopping.svg │ │ └── vip.svg │ │ └── tabbar │ │ ├── category (1).png │ │ ├── category.png │ │ ├── cc-home (1).png │ │ ├── cc-home.png │ │ ├── profile (1).png │ │ ├── profile.png │ │ ├── shop-cart-1 (1).png │ │ └── shop-cart-1.png ├── common │ ├── const.js │ ├── mixin.js │ └── utils.js ├── components │ ├── common │ │ ├── gridView │ │ │ └── GridView.vue │ │ ├── navbar │ │ │ └── NavBar.vue │ │ ├── scroll │ │ │ └── Scroll.vue │ │ ├── swiper │ │ │ ├── Swiper.vue │ │ │ ├── SwiperItem.vue │ │ │ └── index.js │ │ ├── tabbar │ │ │ ├── TabBar.vue │ │ │ └── TabBarItem.vue │ │ └── toast │ │ │ ├── Toast.vue │ │ │ └── index.js │ └── content │ │ ├── MainTabbar.vue │ │ ├── backTop │ │ └── BackTop.vue │ │ ├── checkButton │ │ └── CheckButton.vue │ │ ├── goods │ │ ├── GoodsList.vue │ │ └── GoodsListItem.vue │ │ └── tabControl │ │ └── TabControl.vue ├── main.js ├── network │ ├── category.js │ ├── detail.js │ ├── home.js │ └── request.js ├── router │ └── index.js ├── store │ ├── actions.js │ ├── getters.js │ ├── index.js │ ├── mutation-types.js │ └── mutations.js └── views │ ├── Cart │ ├── Cart.vue │ └── childComps │ │ ├── CartBottomBar.vue │ │ ├── CartList.vue │ │ └── CartListItem.vue │ ├── Category │ ├── Category.vue │ └── childCopms │ │ ├── CategoryMenu.vue │ │ ├── ContentDetail.vue │ │ └── MenuDetail.vue │ ├── Home │ ├── Home.vue │ └── childComps │ │ ├── FeatureView.vue │ │ ├── HomeRecommendView.vue │ │ └── HomeSwiper.vue │ ├── Profile │ ├── Profile.vue │ └── childComps │ │ ├── ListView.vue │ │ └── UserInfo.vue │ └── detail │ ├── Detail.vue │ └── childComps │ ├── DetailBaseInfo.vue │ ├── DetailBottomBar.vue │ ├── DetailCommentInfo.vue │ ├── DetailGoodsInfo.vue │ ├── DetailNavBar.vue │ ├── DetailParamInfo.vue │ ├── DetailShopInfo.vue │ └── DetailSwiper.vue └── vue.config.js /.editorconfig.js: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # supermall 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fashionmall", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.21.1", 12 | "better-scroll": "^2.3.0", 13 | "core-js": "^3.6.5", 14 | "fastclick": "^1.0.6", 15 | "vue": "^2.6.11", 16 | "vue-lazyload": "^1.3.3", 17 | "vue-router": "^3.5.1", 18 | "vuex": "^3.6.2" 19 | }, 20 | "devDependencies": { 21 | "@vue/cli-plugin-babel": "~4.5.0", 22 | "@vue/cli-plugin-eslint": "~4.5.0", 23 | "@vue/cli-service": "~4.5.0", 24 | "babel-eslint": "^10.1.0", 25 | "eslint": "^6.7.2", 26 | "eslint-plugin-vue": "^6.2.2", 27 | "postcss-px-to-viewport": "^1.1.1", 28 | "vue-template-compiler": "^2.6.11" 29 | }, 30 | "eslintConfig": { 31 | "root": true, 32 | "env": { 33 | "node": true 34 | }, 35 | "extends": [ 36 | "plugin:vue/essential", 37 | "eslint:recommended" 38 | ], 39 | "parserOptions": { 40 | "parser": "babel-eslint" 41 | }, 42 | "rules": {} 43 | }, 44 | "browserslist": [ 45 | "> 1%", 46 | "last 2 versions", 47 | "not dead" 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | "postcss-px-to-viewport": { 5 | viewportWidth: 375, // 视窗的宽度,对应的是我们设计稿的宽度 6 | viewportHeight: 667, // 视窗的高度 (也可以不配置) 7 | unitPrecision: 5, // 指定'px'转化为视窗单位值的小数位数(很多时候无法整除) 8 | viewportUnit: 'vw', // 指定需要转换成的视窗单位,建议使用vw 9 | selectorBlackList: ['ignore'], //指定不需要转化的类,写上类名即可,ignore的用法是在组件中视图的标签下的类名后添加一个ignore 10 | minPixelValue: 1, // 小于或等于`1px`不转化未视窗单位 11 | mediaQuery: false // 允许在媒体查询中转换`px` 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /public/bitbug_favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/public/bitbug_favicon.ico -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | fashionmall 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 20 | 21 | 24 | -------------------------------------------------------------------------------- /src/assets/css/base.css: -------------------------------------------------------------------------------- 1 | @import './normalize.css'; 2 | /* :root --> 获取根元素html 3 | --color-text是定义的变量,这就是css中定义变量的方式,定义之后可在其他css属性里用此变量做值 4 | font-size: var(--font-size)通过var使用变量 5 | */ 6 | :root { 7 | --color-text: #666; 8 | --color-high-text: #ff5777; 9 | --color-tint: #ff8198; 10 | --color-background: #fff; 11 | --font-size: 14px; 12 | --line-height: 1.5 13 | } 14 | *, 15 | *::before, 16 | *::after { 17 | margin: 0; 18 | padding:0; 19 | box-sizing: border-box; 20 | } 21 | body{ 22 | font-family: 'Helvetica Neue', Helvetica, 'PingFang SC','Hiragino Sans GB','Mircrosoft YaHei',Arial, sans-serif; 23 | user-select: none; /* 禁止用户鼠标在页面上选中文字、图片等 */ 24 | background: var(--color-background); 25 | color: var(--color-text); 26 | width: 100vw; 27 | } 28 | a { 29 | color:var(--color-text); 30 | text-decoration: none; 31 | } 32 | .clear-fix::after { 33 | clear: both; 34 | content: ''; 35 | display: block; 36 | width: 0; 37 | height: 0; 38 | visibility: hidden; 39 | } 40 | .clear-fix { 41 | zoom: 1; 42 | } 43 | .left { 44 | float: left; 45 | } 46 | .right { 47 | float: right; 48 | } -------------------------------------------------------------------------------- /src/assets/css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in iOS. 9 | */ 10 | 11 | html { 12 | line-height: 1.15; /* 1 */ 13 | -webkit-text-size-adjust: 100%; /* 2 */ 14 | } 15 | 16 | /* Sections 17 | ========================================================================== */ 18 | 19 | /** 20 | * Remove the margin in all browsers. 21 | */ 22 | 23 | body { 24 | margin: 0; 25 | } 26 | 27 | /** 28 | * Render the `main` element consistently in IE. 29 | */ 30 | 31 | main { 32 | display: block; 33 | } 34 | 35 | /** 36 | * Correct the font size and margin on `h1` elements within `section` and 37 | * `article` contexts in Chrome, Firefox, and Safari. 38 | */ 39 | 40 | h1 { 41 | font-size: 2em; 42 | margin: 0.67em 0; 43 | } 44 | 45 | /* Grouping content 46 | ========================================================================== */ 47 | 48 | /** 49 | * 1. Add the correct box sizing in Firefox. 50 | * 2. Show the overflow in Edge and IE. 51 | */ 52 | 53 | hr { 54 | box-sizing: content-box; /* 1 */ 55 | height: 0; /* 1 */ 56 | overflow: visible; /* 2 */ 57 | } 58 | 59 | /** 60 | * 1. Correct the inheritance and scaling of font size in all browsers. 61 | * 2. Correct the odd `em` font sizing in all browsers. 62 | */ 63 | 64 | pre { 65 | font-family: monospace, monospace; /* 1 */ 66 | font-size: 1em; /* 2 */ 67 | } 68 | 69 | /* Text-level semantics 70 | ========================================================================== */ 71 | 72 | /** 73 | * Remove the gray background on active links in IE 10. 74 | */ 75 | 76 | a { 77 | background-color: transparent; 78 | } 79 | 80 | /** 81 | * 1. Remove the bottom border in Chrome 57- 82 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 83 | */ 84 | 85 | abbr[title] { 86 | border-bottom: none; /* 1 */ 87 | text-decoration: underline; /* 2 */ 88 | text-decoration: underline dotted; /* 2 */ 89 | } 90 | 91 | /** 92 | * Add the correct font weight in Chrome, Edge, and Safari. 93 | */ 94 | 95 | b, 96 | strong { 97 | font-weight: bolder; 98 | } 99 | 100 | /** 101 | * 1. Correct the inheritance and scaling of font size in all browsers. 102 | * 2. Correct the odd `em` font sizing in all browsers. 103 | */ 104 | 105 | code, 106 | kbd, 107 | samp { 108 | font-family: monospace, monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /** 113 | * Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /** 121 | * Prevent `sub` and `sup` elements from affecting the line height in 122 | * all browsers. 123 | */ 124 | 125 | sub, 126 | sup { 127 | font-size: 75%; 128 | line-height: 0; 129 | position: relative; 130 | vertical-align: baseline; 131 | } 132 | 133 | sub { 134 | bottom: -0.25em; 135 | } 136 | 137 | sup { 138 | top: -0.5em; 139 | } 140 | 141 | /* Embedded content 142 | ========================================================================== */ 143 | 144 | /** 145 | * Remove the border on images inside links in IE 10. 146 | */ 147 | 148 | img { 149 | border-style: none; 150 | } 151 | 152 | /* Forms 153 | ========================================================================== */ 154 | 155 | /** 156 | * 1. Change the font styles in all browsers. 157 | * 2. Remove the margin in Firefox and Safari. 158 | */ 159 | 160 | button, 161 | input, 162 | optgroup, 163 | select, 164 | textarea { 165 | font-family: inherit; /* 1 */ 166 | font-size: 100%; /* 1 */ 167 | line-height: 1.15; /* 1 */ 168 | margin: 0; /* 2 */ 169 | } 170 | 171 | /** 172 | * Show the overflow in IE. 173 | * 1. Show the overflow in Edge. 174 | */ 175 | 176 | button, 177 | input { /* 1 */ 178 | overflow: visible; 179 | } 180 | 181 | /** 182 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 183 | * 1. Remove the inheritance of text transform in Firefox. 184 | */ 185 | 186 | button, 187 | select { /* 1 */ 188 | text-transform: none; 189 | } 190 | 191 | /** 192 | * Correct the inability to style clickable types in iOS and Safari. 193 | */ 194 | 195 | button, 196 | [type="button"], 197 | [type="reset"], 198 | [type="submit"] { 199 | -webkit-appearance: button; 200 | } 201 | 202 | /** 203 | * Remove the inner border and padding in Firefox. 204 | */ 205 | 206 | button::-moz-focus-inner, 207 | [type="button"]::-moz-focus-inner, 208 | [type="reset"]::-moz-focus-inner, 209 | [type="submit"]::-moz-focus-inner { 210 | border-style: none; 211 | padding: 0; 212 | } 213 | 214 | /** 215 | * Restore the focus styles unset by the previous rule. 216 | */ 217 | 218 | button:-moz-focusring, 219 | [type="button"]:-moz-focusring, 220 | [type="reset"]:-moz-focusring, 221 | [type="submit"]:-moz-focusring { 222 | outline: 1px dotted ButtonText; 223 | } 224 | 225 | /** 226 | * Correct the padding in Firefox. 227 | */ 228 | 229 | fieldset { 230 | padding: 0.35em 0.75em 0.625em; 231 | } 232 | 233 | /** 234 | * 1. Correct the text wrapping in Edge and IE. 235 | * 2. Correct the color inheritance from `fieldset` elements in IE. 236 | * 3. Remove the padding so developers are not caught out when they zero out 237 | * `fieldset` elements in all browsers. 238 | */ 239 | 240 | legend { 241 | box-sizing: border-box; /* 1 */ 242 | color: inherit; /* 2 */ 243 | display: table; /* 1 */ 244 | max-width: 100%; /* 1 */ 245 | padding: 0; /* 3 */ 246 | white-space: normal; /* 1 */ 247 | } 248 | 249 | /** 250 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 251 | */ 252 | 253 | progress { 254 | vertical-align: baseline; 255 | } 256 | 257 | /** 258 | * Remove the default vertical scrollbar in IE 10+. 259 | */ 260 | 261 | textarea { 262 | overflow: auto; 263 | } 264 | 265 | /** 266 | * 1. Add the correct box sizing in IE 10. 267 | * 2. Remove the padding in IE 10. 268 | */ 269 | 270 | [type="checkbox"], 271 | [type="radio"] { 272 | box-sizing: border-box; /* 1 */ 273 | padding: 0; /* 2 */ 274 | } 275 | 276 | /** 277 | * Correct the cursor style of increment and decrement buttons in Chrome. 278 | */ 279 | 280 | [type="number"]::-webkit-inner-spin-button, 281 | [type="number"]::-webkit-outer-spin-button { 282 | height: auto; 283 | } 284 | 285 | /** 286 | * 1. Correct the odd appearance in Chrome and Safari. 287 | * 2. Correct the outline style in Safari. 288 | */ 289 | 290 | [type="search"] { 291 | -webkit-appearance: textfield; /* 1 */ 292 | outline-offset: -2px; /* 2 */ 293 | } 294 | 295 | /** 296 | * Remove the inner padding in Chrome and Safari on macOS. 297 | */ 298 | 299 | [type="search"]::-webkit-search-decoration { 300 | -webkit-appearance: none; 301 | } 302 | 303 | /** 304 | * 1. Correct the inability to style clickable types in iOS and Safari. 305 | * 2. Change font properties to `inherit` in Safari. 306 | */ 307 | 308 | ::-webkit-file-upload-button { 309 | -webkit-appearance: button; /* 1 */ 310 | font: inherit; /* 2 */ 311 | } 312 | 313 | /* Interactive 314 | ========================================================================== */ 315 | 316 | /* 317 | * Add the correct display in Edge, IE 10+, and Firefox. 318 | */ 319 | 320 | details { 321 | display: block; 322 | } 323 | 324 | /* 325 | * Add the correct display in all browsers. 326 | */ 327 | 328 | summary { 329 | display: list-item; 330 | } 331 | 332 | /* Misc 333 | ========================================================================== */ 334 | 335 | /** 336 | * Add the correct display in IE 10+. 337 | */ 338 | 339 | template { 340 | display: none; 341 | } 342 | 343 | /** 344 | * Add the correct display in IE 10. 345 | */ 346 | 347 | [hidden] { 348 | display: none; 349 | } -------------------------------------------------------------------------------- /src/assets/img/cart/tick.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/common/arrow-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/common/back.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/img/common/collect.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/common/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/common/placeholder.png -------------------------------------------------------------------------------- /src/assets/img/common/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/common/top.png -------------------------------------------------------------------------------- /src/assets/img/detail/cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/detail/cart.png -------------------------------------------------------------------------------- /src/assets/img/detail/detail_bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/detail/detail_bottom.png -------------------------------------------------------------------------------- /src/assets/img/home/recommend_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/home/recommend_bg.jpg -------------------------------------------------------------------------------- /src/assets/img/profile/arrow-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/profile/arrow-right.png -------------------------------------------------------------------------------- /src/assets/img/profile/avatar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/profile/cart.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/profile/message.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/profile/phone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/profile/pointer.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/profile/shopping.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/profile/vip.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/tabbar/category (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/tabbar/category (1).png -------------------------------------------------------------------------------- /src/assets/img/tabbar/category.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/tabbar/category.png -------------------------------------------------------------------------------- /src/assets/img/tabbar/cc-home (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/tabbar/cc-home (1).png -------------------------------------------------------------------------------- /src/assets/img/tabbar/cc-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/tabbar/cc-home.png -------------------------------------------------------------------------------- /src/assets/img/tabbar/profile (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/tabbar/profile (1).png -------------------------------------------------------------------------------- /src/assets/img/tabbar/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/tabbar/profile.png -------------------------------------------------------------------------------- /src/assets/img/tabbar/shop-cart-1 (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/tabbar/shop-cart-1 (1).png -------------------------------------------------------------------------------- /src/assets/img/tabbar/shop-cart-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/assets/img/tabbar/shop-cart-1.png -------------------------------------------------------------------------------- /src/common/const.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yxiaoping/vue-surpermall/704861dc6e0a6deaccf53b7c00399098a83306ce/src/common/const.js -------------------------------------------------------------------------------- /src/common/mixin.js: -------------------------------------------------------------------------------- 1 | import {debounce} from './utils' 2 | import BackTop from 'components/content/backTop/BackTop' 3 | // mixin 混入,此mounted函数将与组件内的mounted函数合并,不冲突 4 | // 混入时写的哪个函数,导入后就能实现相应函数的功能 5 | export const itemListenerMixin = { 6 | data () { 7 | return { 8 | itemImgListener: null 9 | // refresh: null 还可将防抖函数保存在data中,这样引入mixin的组件就可在任意位置使用防抖函数了 10 | } 11 | }, 12 | mounted () { 13 | const refresh = debounce(this.$refs.scroll.refresh, 100) 14 | this.itemImgListener = () => { refresh() } 15 | this.$bus.$on('itemImageLoad', this.itemImgListener) 16 | console.log('I am in mixins'); 17 | } 18 | } 19 | // 封装回到顶部按钮 20 | export const backTopMixin = { 21 | data () { 22 | return { 23 | showTop: false 24 | } 25 | }, 26 | components: { 27 | BackTop 28 | }, 29 | methods: { 30 | backTop () { 31 | this.$refs.scroll.scrollTo(0,0) 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/common/utils.js: -------------------------------------------------------------------------------- 1 | // 公共方法 2 | // 防抖操作 3 | export function debounce(func,delay=100){ 4 | let timer = null // 此处也是局部变量,但下面形成了闭包,此局部变量就不会被销毁 5 | return function(...args){ // 可让func函数传多个参数 6 | if(timer) clearTimeout(timer) // 如果上一个定时器未执行完直接取消执行,减少对服务器的请求 7 | timer = setTimeout(()=>{ 8 | func.apply(this,args) // 调用func函数,接收args作为参数 9 | },delay) 10 | } 11 | } 12 | 13 | // 时间戳转化 14 | // new Date(value * 1000).toLocaleString() // 返回值的格式为 yyyy/MM/dd 下午 hh:mm:ss 15 | export function formatDate(date, fmt) { 16 | // 1.获取年份 y+ 一个或多个y,正则表达式:匹配字符串 17 | if(/(y+)/.test(fmt)) { 18 | // RegExp.$1 即匹配到的/(y+)/字符串,将其替换为逗号后的(date.getFullYear() + '')... 19 | // (date.getFullYear() + '')是将时间加上一个空串,将数值转化为字符串 20 | // substr截取字符串,截取的个数为 4-匹配的字符串的长度,如果匹配的字符串为2019,则不截取,显示2019 21 | fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); 22 | } 23 | let o = { 24 | 'M+': date.getMonth() + 1, 25 | 'd+': date.getDate(), 26 | 'h+': date.getHours(), 27 | 'm+': date.getMinutes(), 28 | 's+': date.getSeconds() 29 | }; 30 | for (let k in o) { 31 | if (new RegExp(`(${k})`).test(fmt)) { 32 | let str = o[k] + ''; 33 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str)); 34 | } 35 | } 36 | return fmt; 37 | } 38 | // 不足两位则要补齐两位: 01:02 39 | // 如果传入的str为 04,则执行 0004.substr(2) -> 04 40 | // if str = 4 -> 004.sbustr(1) -> 04 41 | function padLeftZero (str) { 42 | return ('00' + str).substr(str.length); 43 | } -------------------------------------------------------------------------------- /src/components/common/gridView/GridView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 63 | 64 | 70 | -------------------------------------------------------------------------------- /src/components/common/navbar/NavBar.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 30 | -------------------------------------------------------------------------------- /src/components/common/scroll/Scroll.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 92 | 93 | 96 | -------------------------------------------------------------------------------- /src/components/common/swiper/Swiper.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 185 | 186 | 220 | -------------------------------------------------------------------------------- /src/components/common/swiper/SwiperItem.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 23 | -------------------------------------------------------------------------------- /src/components/common/swiper/index.js: -------------------------------------------------------------------------------- 1 | // 向外暴露轮播组件,方便后面使用 2 | import Swiper from './Swiper' 3 | import SwiperItem from './SwiperItem' 4 | export { 5 | Swiper,SwiperItem 6 | } 7 | // 以后导入就可使用 import {Swiper,SwiperItem} from ... -------------------------------------------------------------------------------- /src/components/common/tabbar/TabBar.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 25 | -------------------------------------------------------------------------------- /src/components/common/tabbar/TabBarItem.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 38 | 39 | 52 | -------------------------------------------------------------------------------- /src/components/common/toast/Toast.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 40 | 41 | 53 | -------------------------------------------------------------------------------- /src/components/common/toast/index.js: -------------------------------------------------------------------------------- 1 | import Toast from './Toast' // 将toast组件导入进来,好添加组件中的元素 2 | const obj = {} 3 | obj.install = function(Vue){ 4 | // 直接添加toast组件中的元素不行 5 | // document.body.appendChild(Toast.$el) 6 | // 1.创建组件构造器 7 | const toastConstructor = Vue.extend(Toast) 8 | // 2.用new的方式,根据组件构造器,可以创建一个组件对象 9 | const toast = new toastConstructor() 10 | // 3.将组件对象手动地挂载到某一个元素上 11 | toast.$mount(document.createElement('div')) // 将toast组件对象挂载到div上 12 | // 4.挂载完之后,toast.$el对应的就是div 13 | document.body.appendChild(toast.$el) 14 | 15 | Vue.prototype.$toast = toast // 将toast组件对象放在vue原型上,使得其他任意组件都可使用$toast方法使用toast组件对象 16 | } 17 | export default obj -------------------------------------------------------------------------------- /src/components/content/MainTabbar.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 36 | 37 | 40 | -------------------------------------------------------------------------------- /src/components/content/backTop/BackTop.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 23 | -------------------------------------------------------------------------------- /src/components/content/checkButton/CheckButton.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 21 | 33 | -------------------------------------------------------------------------------- /src/components/content/goods/GoodsList.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 26 | 27 | 34 | -------------------------------------------------------------------------------- /src/components/content/goods/GoodsListItem.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 44 | 45 | 87 | -------------------------------------------------------------------------------- /src/components/content/tabControl/TabControl.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 35 | 36 | 60 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | 6 | import FastClick from 'fastclick' 7 | import VueLazyLoad from 'vue-lazyload' 8 | 9 | import toast from 'components/common/toast' // 1.引入插件 10 | 11 | Vue.config.productionTip = false 12 | Vue.prototype.$bus = new Vue() // 将vue实例作为事件总线,监听不同组件间事件变化,使得组件间通信 13 | 14 | // 2.安装插件,就相当于调用了toast的install函数方法 15 | Vue.use(toast) 16 | Vue.use(VueLazyLoad, { 17 | loading: require('./assets/img/common/placeholder.png') 18 | }) 19 | 20 | // 解决移动端300ms延迟 21 | FastClick.attach(document.body) 22 | new Vue({ 23 | render: h => h(App), 24 | router, 25 | store 26 | }).$mount('#app') 27 | // $mount 将vue实例挂载到app上 28 | 29 | // import { createApp } from 'vue' 30 | // createApp(App).use(router).use(store).use(VueLazyLoad, { 31 | // loading: require('./assets/img/common/placeholder.png') 32 | // }).mount('#app') -------------------------------------------------------------------------------- /src/network/category.js: -------------------------------------------------------------------------------- 1 | import {request} from './request' 2 | export function getCategory(){ 3 | return request({ 4 | url: '/category' 5 | }) 6 | } 7 | export function getsubcategory(maitKey) { 8 | return request({ 9 | url:'/subcategory', 10 | params: { 11 | maitKey 12 | } 13 | }) 14 | } 15 | export function getContentDetail(miniWallkey, type){ 16 | return request({ 17 | url: '/subcategory/detail', 18 | params: { 19 | miniWallkey, 20 | type 21 | } 22 | }) 23 | } -------------------------------------------------------------------------------- /src/network/detail.js: -------------------------------------------------------------------------------- 1 | import {request} from './request' 2 | export function getDetail(iid) { 3 | return request({ 4 | url: '/detail', 5 | params: { 6 | iid 7 | } 8 | }) 9 | } 10 | export function getRecommend() { 11 | return request({ 12 | url: '/recommend' 13 | }) 14 | } 15 | export class Goods { 16 | constructor(itemInfo,columns,services) { 17 | this.title = itemInfo.title 18 | this.desc = itemInfo.desc 19 | this.newPrice = itemInfo.price 20 | this.oldPrice = itemInfo.oldPrice 21 | this.discount = itemInfo.discountDesc 22 | this.columns = columns 23 | this.services = services 24 | this.realPrice = itemInfo.lowNowPrice 25 | } 26 | } 27 | export class Shop { 28 | constructor(shopInfo) { 29 | this.logo = shopInfo.shopLogo; 30 | this.name = shopInfo.name; 31 | this.fans = shopInfo.sFans; 32 | this.sells = shopInfo.sSells; 33 | this.score = shopInfo.score; 34 | this.goodsCount = shopInfo.cGoods; 35 | } 36 | } 37 | export class GoodsParam { 38 | constructor(info,rule) { 39 | // images可能没有值,所以要判断一下 40 | this.image = info.images ? info.images[0] : ''; 41 | this.infos = info.set; 42 | this.sizes = rule.tables 43 | } 44 | } -------------------------------------------------------------------------------- /src/network/home.js: -------------------------------------------------------------------------------- 1 | import {request} from './request' 2 | export function getHomeMultidata() { 3 | return request({ 4 | url: '/home/multidata' 5 | }) 6 | } 7 | export function getHomeGoods(type, page) { 8 | return request({ 9 | url: '/home/data', 10 | params: { 11 | type, 12 | page 13 | } 14 | }) 15 | } -------------------------------------------------------------------------------- /src/network/request.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | export function request(config) { 3 | const instance = axios.create({ 4 | baseURL: 'http://152.136.185.210:7878/api/m5', 5 | timeout: 5000 6 | }) 7 | // 2.1 请求拦截 8 | instance.interceptors.request.use(config => { 9 | return config 10 | },err => { 11 | console.log(err) 12 | }) 13 | // 2.2 响应拦截 14 | instance.interceptors.response.use(res => { 15 | return res.data 16 | },err => { 17 | console.log(err) 18 | }) 19 | // 3.发送真正的网络请求 20 | return instance(config) 21 | } -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | 4 | // import { createRouter, createWebHistory } from 'vue-router' 5 | 6 | const Home = () => import('views//Home/Home') 7 | const Category = () => import('views/Category/Category') 8 | const Cart = () => import('views/Cart/Cart') 9 | const Profile = () => import('views/Profile/Profile') 10 | const Detail = () => import('views/detail/Detail') 11 | Vue.use(VueRouter) 12 | const routes = [ 13 | { 14 | path: '', 15 | redirect: '/home' 16 | }, 17 | { 18 | path: '/home', 19 | component: Home 20 | }, 21 | { 22 | path: '/category', 23 | component: Category 24 | }, 25 | { 26 | path: '/cart', 27 | component: Cart 28 | }, 29 | { 30 | path: '/profile', 31 | component: Profile 32 | }, 33 | { 34 | path: '/detail/:iid', 35 | component: Detail 36 | } 37 | ] 38 | const router = new VueRouter({ 39 | routes, 40 | mode: 'history' 41 | }) 42 | // const router = createRouter({ 43 | // history: createWebHistory(), 44 | // routes 45 | // }) 46 | export default router -------------------------------------------------------------------------------- /src/store/actions.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_COUNTER, 3 | ADD_TO_CART 4 | } from './mutation-types' 5 | export default { 6 | addCart(context,payload){ // dispatch可以返回一个promise,可用来监听事件成功与否,据此做弹窗toast效果 7 | return new Promise((resolve,reject) => { 8 | let oldProduct = context.state.cartList.find(item => item.iid === payload.iid) 9 | if(oldProduct){ 10 | // oldProduct.count += 1 这样写也可以,但是无法在devtools中监视到状态变化 11 | // 将数量加1的情况分发到一个特定的方法中 12 | context.commit(ADD_COUNTER,oldProduct) // commit 提交到store中mutations里的方法addCounter中去 13 | resolve('当前商品数量+1') 14 | reject('wrong') 15 | }else{ 16 | payload.count =1 17 | // context.state.cartList.push(payload) 18 | // 将添加商品的情况分发到另一个特定的方法中,使得mutations中的方法只对应一种改变 19 | context.commit(ADD_TO_CART,payload) 20 | resolve('添加新的商品') 21 | } 22 | }) 23 | } 24 | } -------------------------------------------------------------------------------- /src/store/getters.js: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | cartLength (state) { 4 | return state.cartList.length 5 | }, 6 | cartList (state) { 7 | return state.cartList 8 | } 9 | } -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import mutations from './mutations' 4 | import actions from './actions' 5 | import getters from './getters' 6 | // 1.安装插件 7 | Vue.use(Vuex) 8 | // 2.创建store对象 9 | const state = { 10 | cartList: [] 11 | } 12 | const store = new Vuex.Store({ 13 | state, 14 | // 封装、抽取后 15 | // cartList: [] 16 | // }, 17 | mutations, 18 | getters, 19 | /* mutations的目的是修改state的状态,方法尽量单一,devtools才能更好地查看state的变化 */ 20 | // addCart(state,payload) { // 固定的参数,state和传的额外参数payload,state. 可获取到state中的变量,再对其操作 21 | // 此处payload参数为新添加的商品,如果商品一致,不用重复增加数组元素,只增加个数就行 22 | // state.cartList.push(payload) 23 | // 1.查找原数组中是否有该商品 24 | // let oldProduct = null 25 | // for(let item of state.cartList){ // 遍历数组中的元素 26 | // if(item.iid === payload.iid){ 27 | // oldProduct = item // 将此时传入的元素暂时等于oldProduct,方便后面的比较 28 | // } 29 | // } 30 | // 2.判断oldProduct 31 | // if(oldProduct){ 32 | // oldProduct.count += 1 // oldProduct表示现目前的已有商品 33 | // }else{ 34 | // payload.count = 1 35 | // state.cartList.push(payload) 36 | // 被添加的商品元素为payload,如果payload的iid与已有商品的iid一致,则已有商品的数量加1 37 | // } 38 | // 第2种方法 39 | // let index = state.cartList.indexOf(payload) 40 | // if(index == -1) { 41 | // let oldProduct = state.cartList[index] 取到原数组中对应的元素 42 | // oldProduct.count += 1 43 | // }else{ 44 | // payload.count = 1 45 | // state.cartList.push(payload) 46 | // } 47 | // 第3种方法 48 | // let oldProduct = state.cartList.find(item => item.iid === payload.iid) 49 | // if(oldProduct){ 50 | // oldProduct.count += 1 51 | // }else{ 52 | // payload.count =1 53 | // state.cartList.push(payload) 54 | // } 55 | // } 56 | // 将各个对象封装起来,再导入 57 | // addCounter(state,payload){ 58 | // payload.count++ 59 | // }, 60 | // addToCart(state,payload){ 61 | // state.cartList.push(payload) 62 | // } 63 | // }, 64 | actions 65 | // addCart({state,commit},payload) 66 | // addCart(context,payload){ 67 | // let oldProduct = context.state.cartList.find(item => item.iid === payload.iid) 68 | // if(oldProduct){ 69 | // // oldProduct.count += 1 这样写也可以,但是无法在devtools中监视到状态变化 70 | // // 将数量加1的情况分发到一个特定的方法中 71 | // context.commit('addCounter',oldProduct) // commit 提交到store中mutations里的方法addCounter中去 72 | // }else{ 73 | // payload.count =1 74 | // // context.state.cartList.push(payload) 75 | // // 将添加商品的情况分发到另一个特定的方法中,使得mutations中的方法只对应一种改变 76 | // context.commit('addToCart',payload) 77 | // } 78 | // } 79 | // } 80 | }) 81 | // 3.挂载到Vue实例上 82 | export default store -------------------------------------------------------------------------------- /src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | // 定义为常量 2 | export const ADD_COUNTER = 'add_counter' 3 | export const ADD_TO_CART = 'add_to_cart' -------------------------------------------------------------------------------- /src/store/mutations.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_COUNTER, 3 | ADD_TO_CART 4 | } from './mutation-types' 5 | export default { 6 | [ADD_COUNTER](state,payload){ 7 | payload.count++ 8 | }, 9 | [ADD_TO_CART](state,payload){ 10 | payload.checked = true // 购物车中商品是否选中的属性 11 | state.cartList.push(payload) 12 | } 13 | } -------------------------------------------------------------------------------- /src/views/Cart/Cart.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 42 | 43 | 50 | -------------------------------------------------------------------------------- /src/views/Cart/childComps/CartBottomBar.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 70 | 71 | 103 | -------------------------------------------------------------------------------- /src/views/Cart/childComps/CartList.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 32 | 33 | 44 | -------------------------------------------------------------------------------- /src/views/Cart/childComps/CartListItem.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 38 | 39 | 99 | -------------------------------------------------------------------------------- /src/views/Category/Category.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 137 | 138 | 164 | -------------------------------------------------------------------------------- /src/views/Category/childCopms/CategoryMenu.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 37 | 38 | 68 | -------------------------------------------------------------------------------- /src/views/Category/childCopms/ContentDetail.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /src/views/Category/childCopms/MenuDetail.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 32 | 33 | 51 | -------------------------------------------------------------------------------- /src/views/Home/Home.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 188 | 189 | 230 | -------------------------------------------------------------------------------- /src/views/Home/childComps/FeatureView.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /src/views/Home/childComps/HomeRecommendView.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | 26 | 43 | -------------------------------------------------------------------------------- /src/views/Home/childComps/HomeSwiper.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 44 | 45 | 48 | -------------------------------------------------------------------------------- /src/views/Profile/Profile.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 24 | 25 | 32 | -------------------------------------------------------------------------------- /src/views/Profile/childComps/ListView.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 47 | 48 | 84 | -------------------------------------------------------------------------------- /src/views/Profile/childComps/UserInfo.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 26 | 27 | 65 | -------------------------------------------------------------------------------- /src/views/detail/Detail.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 231 | 232 | 244 | -------------------------------------------------------------------------------- /src/views/detail/childComps/DetailBaseInfo.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 37 | 38 | 94 | -------------------------------------------------------------------------------- /src/views/detail/childComps/DetailBottomBar.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 34 | 35 | 85 | -------------------------------------------------------------------------------- /src/views/detail/childComps/DetailCommentInfo.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 53 | 54 | 106 | -------------------------------------------------------------------------------- /src/views/detail/childComps/DetailGoodsInfo.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 47 | 48 | 104 | -------------------------------------------------------------------------------- /src/views/detail/childComps/DetailNavBar.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 40 | 41 | 60 | -------------------------------------------------------------------------------- /src/views/detail/childComps/DetailParamInfo.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 34 | 35 | 72 | -------------------------------------------------------------------------------- /src/views/detail/childComps/DetailShopInfo.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 59 | 60 | 163 | -------------------------------------------------------------------------------- /src/views/detail/childComps/DetailSwiper.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 33 | 34 | 40 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | configureWebpack: { 3 | resolve: { 4 | alias: { 5 | 'assets': '@/assets', 6 | 'common': '@/common', 7 | 'components': '@/components', 8 | 'network': '@/network', 9 | 'views': '@/views' 10 | } 11 | } 12 | } 13 | } --------------------------------------------------------------------------------