yuhao 2 年之前
父节点
当前提交
599c95314b

+ 12 - 0
.babel

@@ -0,0 +1,12 @@
1
+{
2
+    "plugins": [
3
+        [
4
+            "import",
5
+            {
6
+                "libraryName": "vant",
7
+                "libraryDirectory": "es",
8
+                "style": true
9
+            }
10
+        ]
11
+    ]
12
+}

+ 23 - 0
.gitignore

@@ -0,0 +1,23 @@
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?

+ 8 - 0
.postcssrc.js

@@ -0,0 +1,8 @@
1
+// .postcssrc.js
2
+module.exports = {
3
+    plugins: {
4
+        'postcss-px-to-viewport': {
5
+            viewportWidth: 375,
6
+        },
7
+    },
8
+};

+ 19 - 0
README.md

@@ -0,0 +1,19 @@
1
+# shangcheng
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
+### Customize configuration
19
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 5 - 0
babel.config.js

@@ -0,0 +1,5 @@
1
+module.exports = {
2
+  presets: [
3
+    '@vue/cli-plugin-babel/preset'
4
+  ]
5
+}

文件差异内容过多而无法显示
+ 11871 - 0
package-lock.json


+ 37 - 0
package.json

@@ -0,0 +1,37 @@
1
+{
2
+  "name": "shangcheng",
3
+  "version": "0.1.0",
4
+  "private": true,
5
+  "scripts": {
6
+    "serve": "vue-cli-service serve",
7
+    "build": "vue-cli-service build"
8
+  },
9
+  "dependencies": {
10
+    "axios": "^1.1.3",
11
+    "core-js": "^3.6.5",
12
+    "qrcodejs2": "0.0.2",
13
+    "swiper": "^5.4.5",
14
+    "vant": "^2.12.2",
15
+    "vue": "^2.6.11",
16
+    "vue-awesome-swiper": "^4.1.1",
17
+    "vue-router": "^3.2.0",
18
+    "vuetify": "^2.6.12",
19
+    "vuex": "^3.4.0"
20
+  },
21
+  "devDependencies": {
22
+    "@vue/cli-plugin-babel": "~4.5.19",
23
+    "@vue/cli-plugin-router": "~4.5.19",
24
+    "@vue/cli-plugin-vuex": "~4.5.19",
25
+    "@vue/cli-service": "~4.5.19",
26
+    "babel-plugin-import": "^1.13.5",
27
+    "less": "^3.0.4",
28
+    "less-loader": "^5.0.0",
29
+    "postcss-px-to-viewport": "^1.1.1",
30
+    "vue-template-compiler": "^2.6.11"
31
+  },
32
+  "browserslist": [
33
+    "> 1%",
34
+    "last 2 versions",
35
+    "not dead"
36
+  ]
37
+}

二进制
public/favicon.ico


+ 18 - 0
public/index.html

@@ -0,0 +1,18 @@
1
+<!DOCTYPE html>
2
+<html lang="">
3
+  <head>
4
+    <meta charset="utf-8">
5
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
7
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
8
+    <title><%= htmlWebpackPlugin.options.title %></title>
9
+    <!-- <script type="text/javascript" src="https://ydcommon.51yund.com/test_web_hd/vendor/vconsole.min.js"></script> -->
10
+  </head>
11
+  <body>
12
+    <noscript>
13
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
14
+    </noscript>
15
+    <div id="app"></div>
16
+    <!-- built files will be auto injected -->
17
+  </body>
18
+</html>

+ 11 - 0
src/App.vue

@@ -0,0 +1,11 @@
1
+<template>
2
+  <v-app id="app">
3
+  <router-view></router-view>
4
+  </v-app>
5
+</template>
6
+
7
+<style lang="less">
8
+#app{
9
+  background-color: #F7F8FA ;
10
+}
11
+</style>

+ 34 - 0
src/api/index.js

@@ -0,0 +1,34 @@
1
+import request from '../utils/request'
2
+
3
+// 获取banner列表
4
+export const getBanner = () => {
5
+    return request({
6
+        url: '/v2/api-h5/banner',
7
+        method: 'get',
8
+    })
9
+}
10
+
11
+// 获取商品分类列表
12
+export const getCategory = () => {
13
+    return request({
14
+        url: '/v2/api-h5/goods/category',
15
+        method: 'get',
16
+    })
17
+}
18
+
19
+// 获取商品列表
20
+export const getGoodList = (params) => {
21
+    return request({
22
+        url: '/v2/api-h5/goods/list',
23
+        method: 'get',
24
+        params
25
+    })
26
+}
27
+// 获取商品详情
28
+export const getGoodInfo = (params) => {
29
+    return request({
30
+        url: '/v2/api-h5/goods/info',
31
+        method: 'get',
32
+        params
33
+    })
34
+}

二进制
src/assets/logo.png


二进制
src/image/nature-1.jpg


二进制
src/image/nature-10.jpg


二进制
src/image/nature-2.jpg


二进制
src/image/nature-3.jpg


二进制
src/image/nature-4.jpg


二进制
src/image/nature-5.jpg


二进制
src/image/nature-6.jpg


二进制
src/image/nature-7.jpg


二进制
src/image/nature-8.jpg


二进制
src/image/nature-9.jpg


+ 18 - 0
src/main.js

@@ -0,0 +1,18 @@
1
+import Vue from 'vue'
2
+import App from './App.vue'
3
+import router from './router'
4
+import store from './store'
5
+import './plugins/vant'
6
+// 引入vuetify
7
+import vuetify from '@/plugins/vuetify' // path to vuetify export
8
+import VueAwesomeSwiper from 'vue-awesome-swiper'
9
+import 'swiper/css/swiper.css'
10
+Vue.use(VueAwesomeSwiper)
11
+Vue.config.productionTip = false
12
+
13
+new Vue({
14
+  router,
15
+  store,
16
+  vuetify,
17
+  render: h => h(App)
18
+}).$mount('#app')

+ 10 - 0
src/plugins/vant.js

@@ -0,0 +1,10 @@
1
+//文件下放入你所需用到的组件即可,这里我是用了 Button 
2
+import Vue from 'vue';
3
+import 'vant/lib/index.css';
4
+import { Swipe, SwipeItem } from 'vant';
5
+import { Tab, Tabs } from 'vant';
6
+
7
+Vue.use(Tab);
8
+Vue.use(Tabs);
9
+Vue.use(Swipe);
10
+Vue.use(SwipeItem);

+ 9 - 0
src/plugins/vuetify.js

@@ -0,0 +1,9 @@
1
+import Vue from 'vue'
2
+import Vuetify from 'vuetify'
3
+import 'vuetify/dist/vuetify.min.css'
4
+
5
+Vue.use(Vuetify)
6
+
7
+const opts = {}
8
+
9
+export default new Vuetify(opts)

+ 26 - 0
src/router/index.js

@@ -0,0 +1,26 @@
1
+import Vue from 'vue'
2
+import VueRouter from 'vue-router'
3
+import Home from '../views/home'
4
+import Swiper from '../views/swiper'
5
+Vue.use(VueRouter)
6
+
7
+const routes = [
8
+  {
9
+    path: '/',
10
+    name: 'Swiper',
11
+    component: Swiper
12
+  },
13
+  {
14
+    path: '/home',
15
+    name: 'Home',
16
+    component: Home
17
+  },
18
+]
19
+
20
+const router = new VueRouter({
21
+  mode: 'hash',
22
+  base: process.env.BASE_URL,
23
+  routes
24
+})
25
+
26
+export default router

+ 15 - 0
src/store/index.js

@@ -0,0 +1,15 @@
1
+import Vue from 'vue'
2
+import Vuex from 'vuex'
3
+
4
+Vue.use(Vuex)
5
+
6
+export default new Vuex.Store({
7
+  state: {
8
+  },
9
+  mutations: {
10
+  },
11
+  actions: {
12
+  },
13
+  modules: {
14
+  }
15
+})

+ 28 - 0
src/utils/request.js

@@ -0,0 +1,28 @@
1
+import axios from "axios";
2
+const service = axios.create({
3
+    baseURL:'https://api.ijolijoli.com/',
4
+    timeout: 5000,
5
+});
6
+
7
+// request拦截器
8
+axios.interceptors.request.use(
9
+    config => {
10
+        return config;
11
+    },
12
+    error => {
13
+        return Promise.resolve(err)
14
+    }
15
+);
16
+
17
+// 响应拦截器
18
+axios.interceptors.response.use(
19
+    res => {
20
+        console.log(res)
21
+    },
22
+    error => {
23
+        console.log(error)
24
+        return Promise.reject(error);
25
+    }
26
+);
27
+
28
+export default service;

文件差异内容过多而无法显示
+ 13 - 0
src/utils/swiper-bundle.min.css


文件差异内容过多而无法显示
+ 14 - 0
src/utils/swiper-bundle.min.js


+ 582 - 0
src/views/home/index.vue

@@ -0,0 +1,582 @@
1
+<template>
2
+  <div @touchend="moveEvent" @click="moveEvent">
3
+    <!-- 切换栏 -->
4
+    <div class="tabs">
5
+      <v-card>
6
+        <v-tabs
7
+          background-color="#FFFFFF"
8
+          center-active
9
+          color="#FA7D22"
10
+          height="120"
11
+        >
12
+          <v-tab
13
+            @click="selectTab(item)"
14
+            v-for="(item, index) in categoryList"
15
+            :key="index"
16
+            >{{ item.name }}</v-tab
17
+          >
18
+        </v-tabs>
19
+      </v-card>
20
+    </div>
21
+    <!-- 商品轮播图 -->
22
+    <div class="swiper-container">
23
+      <div class="swiper-wrapper">
24
+        <div
25
+          @click="selectGood(item)"
26
+          v-for="(item, index) in goodList"
27
+          :key="index"
28
+          class="swiper-slide"
29
+        >
30
+          <img :src="item.cover_url" alt="" />
31
+        </div>
32
+      </div>
33
+    </div>
34
+    <!-- 商品大图标题 -->
35
+    <div class="goodsTop">
36
+      <div class="img">
37
+        <img :src="goodInfo.cover_url" alt="" />
38
+      </div>
39
+      <div class="goodsTop-right">
40
+        <div class="goodsTopTitle">
41
+          {{ goodInfo.goods_name }}
42
+        </div>
43
+        <div class="price">
44
+          ¥<span>{{ goodInfo.price }}</span
45
+          >.00
46
+        </div>
47
+      </div>
48
+    </div>
49
+    <!-- 功效适用皮肤 -->
50
+    <div class="goodsExplain">
51
+      <div class="effect">
52
+        <img
53
+          src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/H5/shangcheng/%E5%8A%9F%E6%95%88%402x.png"
54
+          alt=""
55
+        />
56
+        <div
57
+          :class="{
58
+            effectRight: true,
59
+            infoOver: isOver,
60
+          }"
61
+        >
62
+          <div class="effect-right-title">功效</div>
63
+          <div class="effect-right-content">
64
+            {{ goodInfo.effect
65
+            }}{{ goodInfo.effect ? goodInfo.effect.lenght : "" }}
66
+          </div>
67
+        </div>
68
+      </div>
69
+      <div class="skin">
70
+        <img
71
+          src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/H5/shangcheng/%E9%80%82%E7%94%A8%E7%9A%AE%E8%82%A4%402x.png"
72
+          alt=""
73
+        />
74
+        <div
75
+          :class="{
76
+            skinRight: true,
77
+            infoOver: isSkinOver,
78
+          }"
79
+        >
80
+          <div class="skin-right-title">适用皮肤</div>
81
+          <div class="skin-right-content">{{ goodInfo.skin_type }}</div>
82
+        </div>
83
+      </div>
84
+    </div>
85
+    <!-- 重要成分 -->
86
+    <div class="ingredient">
87
+      <div class="QRcode">
88
+        <div id="qrcode" ref="qrcode"></div>
89
+      </div>
90
+      <div class="order">微信扫码下单</div>
91
+      <img
92
+        class="background"
93
+        src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/H5/shangcheng/%E9%87%8D%E8%A6%81%E6%88%90%E5%88%86%E8%83%8C%E6%99%AF%402x.png"
94
+        alt=""
95
+      />
96
+      <div class="ingredient-top">
97
+        <div class="icon"></div>
98
+        <div class="ingredient-title">重要成分</div>
99
+      </div>
100
+      <!-- <div class="ingredient-content">
101
+        <div class="ingredient-content-title">1.精纯珍贵二裂酵母</div>
102
+        <div class="content">嫩滑细腻 紧实肌肤</div>
103
+      </div>
104
+      <div class="ingredient-content">
105
+        <div class="ingredient-content-title">2.精纯珍贵二裂酵母</div>
106
+        <div class="content">嫩滑细腻 紧实肌肤</div>
107
+      </div> -->
108
+      <div class="ingredient-content">
109
+        <div class="content">{{ goodInfo.component }}</div>
110
+      </div>
111
+    </div>
112
+  </div>
113
+</template>
114
+
115
+<script>
116
+var Swiper = require("../../utils/swiper-bundle.min");
117
+import { getBanner, getCategory, getGoodList, getGoodInfo } from "../../api";
118
+import QRCode from "qrcodejs2";
119
+export default {
120
+  components: {
121
+    QRCode,
122
+  },
123
+  data() {
124
+    return {
125
+      timmer: null, //倒计时函数
126
+      categoryList: [], //商品分类列表
127
+      goodList: [], //商品列表
128
+      goodInfo: [], //商品详情
129
+      qrcode: "",
130
+      isOver: false,
131
+      isSkinOver: false,
132
+      goods_id: "", //商品ID
133
+    };
134
+  },
135
+  created() {
136
+    // 获取banner传过来的商品ID
137
+    this.goods_id = this.$route.query.goods_id;
138
+    // 获取商品分类列表
139
+    this.getCategory();
140
+  },
141
+  mounted() {
142
+    this.swiper();
143
+    this.init();
144
+  },
145
+  methods: {
146
+    /**
147
+      监听鼠标滑动和点击事件,重置超时时间
148
+     */
149
+    moveEvent() {
150
+      clearTimeout(this.timmer);
151
+      this.init();
152
+    },
153
+    /**
154
+      用户超时定时器 5分钟
155
+     */
156
+    init() {
157
+      this.timmer = setTimeout(() => {
158
+        // 执行事件
159
+        this.$router.replace({
160
+          path: "/",
161
+        });
162
+      }, 300000);
163
+    },
164
+    // 解析富文本
165
+    showHtml(str) {
166
+      return str
167
+        .replace(str ? /&(?!#?\w+;)/g : /&/g, "&amp;")
168
+        .replace(/&lt;/g, "<")
169
+        .replace(/&gt;/g, ">")
170
+        .replace(/&quot;/g, '"')
171
+        .replace(/&#39;/g, "'")
172
+        .replace(/&amp;nbsp;/g, "\u3000");
173
+    },
174
+    // swiper轮播图
175
+    swiper() {
176
+      let effect = 1;
177
+      let that = this;
178
+      var swiper = new Swiper(".swiper-container", {
179
+        speed: 2500,
180
+        slidesPerView: 5,
181
+        spaceBetween: 30,
182
+        centeredSlides: true,
183
+        watchSlidesProgress: true,
184
+        slideToClickedSlide: true,
185
+        preloadImages: true,
186
+        on: {
187
+          setTranslate: function () {
188
+            let slides = this.slides;
189
+            for (let i = 0; i < slides.length; i++) {
190
+              let slide = slides.eq(i);
191
+              let progress = slides[i].progress;
192
+              //slide.html(progress.toFixed(2)); 看清楚progress是怎么变化的
193
+              slide.css({ opacity: "", background: "" });
194
+              slide.transform(""); //清除样式
195
+              if (effect == 1) {
196
+                slide.transform("scale(" + (1 - Math.abs(progress) / 8) + ")");
197
+              }
198
+            }
199
+          },
200
+          setTransition: function (transition) {
201
+            for (var i = 0; i < this.slides.length; i++) {
202
+              var slide = this.slides.eq(i);
203
+              slide.transition(transition);
204
+            }
205
+          },
206
+          transitionStart() {
207
+            // 如果是第一张或者第二张就不居中
208
+            if (this.activeIndex == 0 || this.activeIndex == 1) {
209
+              this.setTranslate(0);
210
+            }
211
+            // 最后一张或者两张不动
212
+            if (
213
+              this.activeIndex == this.slides.length - 2 ||
214
+              this.activeIndex == this.slides.length - 1
215
+            ) {
216
+              let slideW = (this.width / 5).toFixed(5); //每个轮播的宽度
217
+              let keepW = slideW * (this.slides.length - 5); //需要设置的setTranslate的宽度
218
+              this.setTranslate(-keepW);
219
+            }
220
+          },
221
+
222
+          // 滑动切换商品详情
223
+          touchEnd: function (swiper, event) {
224
+            //你的事件
225
+            let id = that.goodList[swiper.activeIndex].id;
226
+            that.getGoodInfo(id);
227
+          },
228
+        },
229
+      });
230
+    },
231
+    // 二维码
232
+    qrcodeScan() {
233
+      //生成二维码
234
+      document.getElementById("qrcode").innerHTML = "";
235
+      new QRCode(document.getElementById("qrcode"), {
236
+        width: 117, // 二维码宽度
237
+        height: 117, // 二维码高度
238
+        text: this.goodInfo.qrcode_content, // 浏览器地址url
239
+        colorDark: "#000000",
240
+        colorLight: "#ffffff",
241
+        correctLevel: QRCode.CorrectLevel.H,
242
+      });
243
+    },
244
+    // 获取商品分类列表
245
+    getCategory() {
246
+      getCategory().then((res) => {
247
+        if (res.status == 200) {
248
+          this.categoryList = res.data.data.list;
249
+          this.getGoodList();
250
+        }
251
+      });
252
+    },
253
+    // 获取商品列表
254
+    getGoodList(id) {
255
+      let params = {
256
+        page: 1,
257
+        limit: 10,
258
+        category_id: id ? id : this.categoryList[0].id, //分类ID
259
+      };
260
+      getGoodList(params).then((res) => {
261
+        if (res.status == 200) {
262
+          this.goodList = res.data.data.list;
263
+          this.getGoodInfo();
264
+        }
265
+      });
266
+    },
267
+    // 获取商品详情
268
+    getGoodInfo(id) {
269
+      this.isOver = false;
270
+      this.isSkinOver = false;
271
+      getGoodInfo({
272
+        id: this.goods_id
273
+          ? this.goods_id
274
+          : id
275
+          ? id
276
+          : this.goodList[0]
277
+          ? this.goodList[0].id
278
+          : "",
279
+      }).then((res) => {
280
+        if (res.status == 200) {
281
+          if (this.goodInfo.id == res.data.data.id) {
282
+            return;
283
+          } else {
284
+            if (res.data.data.goods_name.length > 20) {
285
+              let c = res.data.data.goods_name.substring(
286
+                20,
287
+                res.data.data.goods_name.length
288
+              );
289
+              let b = res.data.data.goods_name.slice(0, 20);
290
+              let a = c.replace(c, "...");
291
+              res.data.data.goods_name = b + a;
292
+            }
293
+            if (res.data.data.price) {
294
+              let priceA = res.data.data.price.indexOf(".");
295
+              res.data.data.price = res.data.data.price.slice(0, priceA);
296
+            }
297
+            if (res.data.data.effect.length > 7) {
298
+              this.isOver = true;
299
+            }
300
+            if (res.data.data.skin_type > 7) {
301
+              this.isSkinOver = true;
302
+            }
303
+            this.goodInfo = res.data.data;
304
+            this.qrcodeScan();
305
+          }
306
+        }
307
+      });
308
+    },
309
+    // 选择商品分类
310
+    selectTab(e) {
311
+      // 重置banner传过来的商品
312
+      this.goods_id = "";
313
+      let id = e.id;
314
+      this.getGoodList(id);
315
+    },
316
+    // 选择商品
317
+    selectGood(e) {
318
+      // 重置banner传过来的商品
319
+      this.goods_id = "";
320
+      let id = e.id;
321
+      this.getGoodInfo(id);
322
+    },
323
+  },
324
+};
325
+</script>
326
+
327
+<style scoped lang='less'>
328
+@import "../../utils/swiper-bundle.min.css";
329
+// 切换栏
330
+/deep/.v-tab {
331
+  font-size: 40px;
332
+  color: #333333;
333
+  padding: 40px;
334
+}
335
+/deep/.swiper-slide.swiper-slide-visible.swiper-slide-active {
336
+  border: 2px solid #fa7d22;
337
+}
338
+/deep/.v-tabs:not(.v-tabs--vertical):not(.v-tabs--right)
339
+  > .v-slide-group--is-overflowing.v-tabs-bar--is-mobile:not(.v-slide-group--has-affixes)
340
+  .v-slide-group__prev {
341
+  display: none;
342
+  visibility: hidden;
343
+}
344
+// 商品轮播
345
+body {
346
+  color: #000;
347
+  margin: 0;
348
+  padding: 0;
349
+}
350
+.swiper-container {
351
+  width: 100%;
352
+  height: auto;
353
+  margin-left: auto;
354
+  margin-right: auto;
355
+  margin-top: 40px;
356
+}
357
+.swiper-slide {
358
+  text-align: center;
359
+  font-size: 18px;
360
+  background: #fff;
361
+  height: 240px;
362
+  border-radius: 20px;
363
+  /* Center slide text vertically */
364
+  display: -webkit-box;
365
+  display: -ms-flexbox;
366
+  display: -webkit-flex;
367
+  display: flex;
368
+  -webkit-box-pack: center;
369
+  -ms-flex-pack: center;
370
+  -webkit-justify-content: center;
371
+  justify-content: center;
372
+  -webkit-box-align: center;
373
+  -ms-flex-align: center;
374
+  -webkit-align-items: center;
375
+  align-items: center;
376
+  transition-property: all;
377
+  img {
378
+    width: 100%;
379
+    height: 100%;
380
+  }
381
+}
382
+#progressEffect {
383
+  position: absolute;
384
+  z-index: 10;
385
+  top: 20px;
386
+  left: 20px;
387
+}
388
+// 商品大图
389
+.goodsTop {
390
+  width: 980px;
391
+  height: 239px;
392
+  background-color: #fff;
393
+  border-radius: 20px;
394
+  margin-top: 160px;
395
+  margin-left: 50px;
396
+  position: relative;
397
+  .img {
398
+    width: 280px;
399
+    height: 360px;
400
+    position: absolute;
401
+    left: 0;
402
+    top: -122px;
403
+    img {
404
+      width: 100%;
405
+      height: 100%;
406
+    }
407
+  }
408
+  .goodsTop-right {
409
+    margin-left: 314px;
410
+    padding: 45px 20px 20px;
411
+    height: 100%;
412
+    position: relative;
413
+    .goodsTopTitle {
414
+      color: #333333;
415
+      font-size: 45px;
416
+      font-weight: 700;
417
+    }
418
+    .price {
419
+      position: absolute;
420
+      font-size: 39px;
421
+      color: #fa4622;
422
+      bottom: 20px;
423
+      right: 20px;
424
+      span {
425
+        font-size: 65px;
426
+      }
427
+    }
428
+  }
429
+}
430
+// 功效适用皮肤
431
+.goodsExplain {
432
+  margin-top: 30px;
433
+  display: flex;
434
+  .effect {
435
+    height: 240px;
436
+    width: 465px;
437
+    margin-left: 50px;
438
+    border-radius: 20px;
439
+    background-color: #fff;
440
+    padding: 45px 20px 45px 40px;
441
+    display: flex;
442
+    align-items: center;
443
+    img {
444
+      width: 150px;
445
+      height: 150px;
446
+    }
447
+    .effectRight {
448
+      padding: 24px 0;
449
+      height: 150px;
450
+      margin-left: 20px;
451
+      font-size: 30px;
452
+      color: #333;
453
+      .effect-right-content {
454
+        font-weight: 600;
455
+        overflow: hidden;
456
+        text-overflow: ellipsis;
457
+        display: -webkit-box;
458
+        -webkit-box-orient: vertical;
459
+        -webkit-line-clamp: 2;
460
+      }
461
+    }
462
+    .infoOver {
463
+      padding: 0;
464
+      display: flex;
465
+      flex-direction: column;
466
+      justify-content: space-between;
467
+      overflow: hidden;
468
+      text-overflow: ellipsis;
469
+      -webkit-box-orient: vertical;
470
+      -webkit-line-clamp: 2;
471
+    }
472
+  }
473
+  .skin {
474
+    height: 240px;
475
+    width: 465px;
476
+    margin-left: 50px;
477
+    border-radius: 20px;
478
+    background-color: #fff;
479
+    padding: 45px 20px 45px 40px;
480
+    display: flex;
481
+    img {
482
+      width: 150px;
483
+      height: 150px;
484
+    }
485
+    .skinRight {
486
+      padding: 24px 0;
487
+      height: 150px;
488
+      margin-left: 20px;
489
+      font-size: 30px;
490
+      color: #333;
491
+      .skin-right-content {
492
+        font-weight: 600;
493
+        overflow: hidden;
494
+        text-overflow: ellipsis;
495
+        display: -webkit-box;
496
+        -webkit-box-orient: vertical;
497
+        -webkit-line-clamp: 2;
498
+      }
499
+    }
500
+    .infoOver {
501
+      padding: 0;
502
+      display: flex;
503
+      flex-direction: column;
504
+      justify-content: space-between;
505
+      overflow: hidden;
506
+      text-overflow: ellipsis;
507
+      -webkit-box-orient: vertical;
508
+      -webkit-line-clamp: 2;
509
+    }
510
+  }
511
+}
512
+// 重要成分
513
+.ingredient {
514
+  height: 700px;
515
+  width: 980px;
516
+  background-color: #fff;
517
+  border-radius: 20px;
518
+  margin-left: 50px;
519
+  margin-top: 30px;
520
+  position: relative;
521
+  .QRcode {
522
+    position: absolute;
523
+    width: 200px;
524
+    height: 200px;
525
+    border-radius: 20px;
526
+    border: 2px solid #fa7d22;
527
+    top: 59px;
528
+    right: 54px;
529
+    display: flex;
530
+    justify-content: center;
531
+    align-items: center;
532
+    padding: 10px;
533
+  }
534
+  .order {
535
+    font-size: 26px;
536
+    color: #666666;
537
+    position: absolute;
538
+    top: 274px;
539
+    right: 76px;
540
+  }
541
+  .background {
542
+    position: absolute;
543
+    right: 0;
544
+    bottom: 0;
545
+    width: 456px;
546
+    height: 417px;
547
+  }
548
+  .ingredient-top {
549
+    display: flex;
550
+    .icon {
551
+      width: 10px;
552
+      height: 50px;
553
+      background-color: #fa7d22;
554
+      border-radius: 5px;
555
+      margin-left: 51px;
556
+      margin-top: 50px;
557
+    }
558
+    .ingredient-title {
559
+      font-size: 40px;
560
+      font-weight: 700;
561
+      color: #333333;
562
+      margin-left: 20px;
563
+      margin-top: 46px;
564
+    }
565
+  }
566
+  .ingredient-content {
567
+    width: 600px;
568
+    margin-left: 70px;
569
+    .ingredient-content-title {
570
+      margin-top: 50px;
571
+      font-size: 40px;
572
+      color: #333;
573
+    }
574
+    .content {
575
+      margin-top: 30px;
576
+      font-size: 30px;
577
+      color: #666666;
578
+      margin-left: 32px;
579
+    }
580
+  }
581
+}
582
+</style>

+ 51 - 0
src/views/swiper/index.vue

@@ -0,0 +1,51 @@
1
+<template>
2
+  <div>
3
+    <van-swipe class="my-swipe" :autoplay="10000" :show-indicators="false">
4
+      <van-swipe-item v-for="(item, index) in bannerList" :key="index"
5
+        ><img @click="goGoods(item)" :src="item.cover_url" alt=""
6
+      /></van-swipe-item>
7
+    </van-swipe>
8
+  </div>
9
+</template>
10
+<script>
11
+import { getBanner } from "../../api";
12
+export default {
13
+  data() {
14
+    return {
15
+      bannerList: [], //轮播图列表
16
+    };
17
+  },
18
+  mounted() {
19
+    this.getBanner();
20
+  },
21
+  methods: {
22
+    // 获取首页轮播
23
+    getBanner() {
24
+      getBanner().then((res) => {
25
+        if (res.status == 200) {
26
+          this.bannerList = res.data.data.list;
27
+        }
28
+      });
29
+    },
30
+    // 进入商品详情
31
+    goGoods(e) {
32
+      this.$router.push({
33
+        path: "/home",
34
+        query: {
35
+          goods_id: e.goods_id,
36
+        },
37
+      });
38
+    },
39
+  },
40
+};
41
+</script>
42
+
43
+<style scoped lang='less'>
44
+.my-swipe {
45
+  height: 1920px;
46
+  img {
47
+    width: 100%;
48
+    height: 100%;
49
+  }
50
+}
51
+</style>

+ 28 - 0
vue.config.js

@@ -0,0 +1,28 @@
1
+module.exports = {
2
+    productionSourceMap: false,// 生产环境是否要生成 sourceMap
3
+    publicPath: './',  //   部署应用包时的基本 URL
4
+    outputDir: 'dist',  //   打包时输出的文件目录
5
+    assetsDir: 'assets',  //   放置静态文件夹目录
6
+    css: {
7
+        loaderOptions: {
8
+            postcss: {
9
+                plugins: [
10
+                    require("postcss-px-to-viewport")({
11
+                        unitToConvert: "px", // 把什么单位转换成vw
12
+                        viewportWidth: 1080, // 视口宽度,设计稿宽度
13
+                        viewportHeight: 1920, // 视口高度,设计稿高度
14
+                        unitPrecision: 5, // 转换成vw单位的小数点后的保留位数
15
+                        propList: ["*"], // 属性列表,表示你要把哪些css属性的px转换成vw
16
+                        viewportUnit: "vw", // 使用的单位,目前可选单位有vw,vh。
17
+                        fontViewportUnit: "vw", // 字体使用的单位
18
+                        selectorBlackList: ['van', 'el-'], // 匹配不被转换为vw的选择器
19
+                        minPixelValue: 1,
20
+                        mediaQuery: false,
21
+                        replace: true, // 是否直接更换属性值,而不添加备用属性
22
+                        exclude: /(\/|\\)(node_modules)(\/|\\)/,
23
+                    })
24
+                ]
25
+            }
26
+        }
27
+    }
28
+}