Prechádzať zdrojové kódy

添加了首页商品详情

Administrator 2 rokov pred
rodič
commit
4d0e6e640b

+ 0 - 3
.vscode/extensions.json

@@ -1,3 +0,0 @@
-{
-  "recommendations": ["Vue.volar"]
-}

+ 3 - 1
README.md

@@ -9,4 +9,6 @@
 1. 更新npm `npm install -g npm@10.2.2`
 2. 创建vite项目 `npm create vite@latest`
 3. 安装路由 `npm install vue-router@4`
-4. 安装sass `npm install -D sass`
+4. 安装sass `npm install -D sass`
+5. 安装@type/node `npm i --save-dev @types/node`
+

+ 16 - 0
package-lock.json

@@ -12,6 +12,7 @@
         "vue-router": "^4.3.0"
       },
       "devDependencies": {
+        "@types/node": "^20.12.5",
         "@vitejs/plugin-vue": "^5.0.4",
         "sass": "^1.72.0",
         "typescript": "^5.2.2",
@@ -578,6 +579,15 @@
       "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
       "dev": true
     },
+    "node_modules/@types/node": {
+      "version": "20.12.5",
+      "resolved": "https://registry.npmmirror.com/@types/node/-/node-20.12.5.tgz",
+      "integrity": "sha512-BD+BjQ9LS/D8ST9p5uqBxghlN+S42iuNxjsUGjeZobe/ciXzk2qb1B6IXc6AnRLS+yFJRpN2IPEHMzwspfDJNw==",
+      "dev": true,
+      "dependencies": {
+        "undici-types": "~5.26.4"
+      }
+    },
     "node_modules/@vitejs/plugin-vue": {
       "version": "5.0.4",
       "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz",
@@ -1431,6 +1441,12 @@
         "node": ">=14.17"
       }
     },
+    "node_modules/undici-types": {
+      "version": "5.26.5",
+      "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz",
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+      "dev": true
+    },
     "node_modules/vite": {
       "version": "5.2.2",
       "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.2.tgz",

+ 2 - 1
package.json

@@ -13,10 +13,11 @@
     "vue-router": "^4.3.0"
   },
   "devDependencies": {
+    "@types/node": "^20.12.5",
     "@vitejs/plugin-vue": "^5.0.4",
     "sass": "^1.72.0",
     "typescript": "^5.2.2",
     "vite": "^5.2.0",
     "vue-tsc": "^2.0.6"
   }
-}
+}

BIN
src/assets/goodsInfo.jpg


+ 123 - 0
src/components/GoodsInfoComponent.vue

@@ -0,0 +1,123 @@
+<template>
+  <div class="goods-info">
+    <!--      //获取图片-->
+    <div class="goods-img"><img :src="getImage(props.goodsInfo.img)" alt=""></div>
+    <div class="goods-name">
+      <span>{{ props.goodsInfo.name }}</span>
+    </div>
+    <div class="goods-price">{{ props.goodsInfo.price }}</div>
+    <div v-if="props.goodsInfo.originalPrice!==props.goodsInfo.price">
+      <div class="goods--original-price">{{ props.goodsInfo.originalPrice }}</div>
+      <div class="goods-discount-percentage">{{ props.goodsInfo.discountPercentage }}</div>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import {GoodsInfo} from "../entity/Entity.ts";
+
+const props = defineProps({
+  goodsInfo: {
+    type: GoodsInfo,
+    default: () => null
+  }
+})
+
+function getImage(url: string) {
+  return new URL(`${url}`, import.meta.url).href;
+}
+
+
+</script>
+<style scoped>
+.goods-info {
+  display: block;
+  max-width: 170px;
+  margin-bottom: 30px;
+
+  &:hover {
+    cursor: pointer;
+  }
+
+  .goods-img {
+    padding: 0;
+    margin: 0 0 12px 0;
+    overflow: hidden;
+    display: flex;
+
+    img {
+      height: 228px;
+      width: 170px;
+
+      &:hover {
+        z-index: 0;
+      }
+    }
+
+    &:hover::after {
+      opacity: 1;
+      box-shadow: rgba(100, 100, 100, 0.3) 0 0 8px 3px;
+    }
+
+    &::after {
+      content: "";
+      position: absolute;
+      width: 170px;
+      height: 228px;
+      box-sizing: border-box;
+      background: rgba(229, 229, 229, 0.2);
+      animation: 0.2s ease 0s 1 normal none running enlarge;
+      opacity: 0;
+      transition: all 0.3s ease 0s;
+    }
+  }
+
+  .goods-name {
+    height: 38px;
+    font-size: 12px;
+    /*最大行数两行*/
+    text-overflow: ellipsis;
+    overflow: hidden;
+    -webkit-line-clamp: 2;
+  }
+
+  .goods-price {
+    font-size: 16px;
+    margin: 5px 0;
+    font-weight: bold;
+
+    &::before {
+      content: "¥";
+    }
+  }
+
+  .goods--original-price {
+    display: inline-block;
+    text-decoration: line-through;
+    font-size: 12px;
+    margin: 0;
+    padding: 0;
+
+    &::before {
+      content: "¥";
+    }
+  }
+
+  .goods-discount-percentage {
+    display: inline-block;
+    font-size: 12px;
+    margin: 0 0 0 10px;
+    padding: 0 5px;
+    color: white;
+    background: rgb(223, 30, 28);
+
+    &::before {
+      content: "-";
+    }
+
+    &::after {
+      content: "%";
+    }
+  }
+
+}
+</style>

+ 124 - 0
src/components/GoodsTypeComponent.vue

@@ -0,0 +1,124 @@
+<template>
+  <div class="card" v-if="props.goodsType">
+    <div class="card-header">
+      <div class="card-title">
+        <span>{{ props.goodsType.title }}</span>
+      </div>
+      <div class="cart-other">
+        <a href="{{ props.goodsType.otherAll }}">发现全部</a>
+      </div>
+    </div>
+    <div class="card-des">
+      <span>
+      {{ props.goodsType.promotionalSlogans }}
+      </span>
+    </div>
+    <div class="card-list">
+      <template v-for="(item,index) in props.goodsType.goodsList">
+        <GoodsInfoComponent v-show="isShow||index<12" :goodsInfo="item"/>
+      </template>
+      <div class="card-show" v-if="props.goodsType.goodsList.length>12">
+        <a @click="show()">{{ isShow ? "收起" : "查看更多" }}</a>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import {GoodsType} from "../entity/Entity.ts"
+import GoodsInfoComponent from "./GoodsInfoComponent.vue";
+import {ref} from "vue";
+
+let isShow = ref(false)
+
+function show() {
+  isShow.value = !isShow.value
+}
+
+//获取父级组件传入的数据内容
+const props = defineProps({
+  goodsType: {
+    type: GoodsType,
+    default: () => null
+  }
+})
+
+</script>
+<style scoped lang="scss">
+.card {
+  width: 1180px;
+  margin: auto;
+  padding: 0;
+  //border: 1px solid #ccc;
+  text-align: left;
+
+  .card-header {
+    margin: 20px 0 0 5px;
+    display: flex;
+    line-height: 32px;
+
+    .card-title {
+      text-align: left;
+      display: inline-block;
+      padding: 0;
+      width: auto;
+      margin: 0;
+      font-weight: bold;
+      font-size: 24px;
+    }
+
+    .cart-other {
+      /*//向右对其*/
+      flex: 1;
+      margin: 0;
+      width: auto;
+
+      text-align: right;
+      vertical-align: middle;
+      align-items: center;
+      font-size: 12px;
+
+      a {
+        padding: 5px 15px;
+        color: white;
+        background: #1475fa;
+      }
+    }
+
+  }
+
+  .card-des {
+    margin: 8px 0 0 5px;
+    color: #666666;
+    font-size: 14px;
+  }
+
+  .card-list {
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+    padding: 5px 0 0 0;
+    margin-top: 15px;
+    overflow: hidden;
+    //overflow-y: auto;
+    div {
+      margin-right: 30px;
+      display: inline-block;
+    }
+
+    div:nth-child(6n) {
+      margin-right: 0;
+    }
+
+    div:nth-child(6n+1) {
+      margin-left: 5px;
+    }
+  }
+  .card-show{
+    text-align: center;
+    width: 100%;
+    cursor: pointer;
+  }
+}
+
+
+</style>

+ 44 - 0
src/entity/Entity.ts

@@ -0,0 +1,44 @@
+export class GoodsType {
+    //排序
+    sort: number
+    //标题
+    title: string
+    //发现全部
+    otherAll: string
+    //宣传标语
+    promotionalSlogans: string
+    //商品列表
+    goodsList: Array<GoodsInfo>
+
+    constructor(sort: number, title: string, otherAll: string, promotionalSlogans: string, goodsList: Array<GoodsInfo>) {
+        this.sort = sort;
+        this.title = title;
+        this.otherAll = otherAll;
+        this.promotionalSlogans = promotionalSlogans;
+        this.goodsList = goodsList;
+    }
+}
+
+export class GoodsInfo {
+    id: number
+    //图片url
+    img: string
+    //商品名字
+    name: string
+    //价格
+    price: number
+    //原价
+    originalPrice: number
+    //折扣
+    discountPercentage: number
+
+
+    constructor(id: number, img: string, name: string, price: number, originalPrice: number) {
+        this.id = id;
+        this.img = img;
+        this.name = name;
+        this.price = price;
+        this.originalPrice = originalPrice;
+        this.discountPercentage = Math.floor(price / originalPrice * 100);
+    }
+}

+ 3 - 3
src/page/GiftPackDiscounts.vue

@@ -1,6 +1,6 @@
 <template>
-  <div class="gift-pack" style="margin-bottom: 100px">
-    <div class="gift-pack-title">特惠礼包</div>
+  <div class="gift-pack">
+    <h2 class="gift-pack-title">特惠礼包</h2>
     <div class="gift-pack-content">
       <template v-for="index in 3">
         <div class="content-item">
@@ -31,7 +31,7 @@
   width: 1170px;
   text-align: left;
   font-size: 12px;
-  margin: 30px auto 20px auto ;
+  margin: 30px auto 50px auto ;
   line-height: 18px;
   .gift-pack-title {
     font-size: 24px;

+ 34 - 7
src/page/index.vue

@@ -32,9 +32,15 @@
     </div>
     <!--    内容体-->
     <div class="main-content">
-
+      <!--      首页广告内容-->
       <HomeConnect/>
-      <GiftPackDiscounts/>
+      <!--      首页优惠礼包信息-->
+<!--      <GiftPackDiscounts/>-->
+      <hr width="1170" style="margin-bottom: 40px">
+      <template v-for="item in goodsListArray">
+        <GoodsTypeComponent :goods-type="item"/>
+        <GoodsTypeComponent :goods-type="item"/>
+      </template>
 
     </div>
     <!--    底部内容-->
@@ -67,12 +73,10 @@
               {{ loginType[selectLoginType].name }}
             </form>
           </div>
-
-
         </div>
       </div>
     </div>
-    <!--  悬浮层  -->
+    <!--      悬浮层  -->
     <!--    <div class="home-suspension">-->
     <!--      <div class="right-handler"></div>-->
     <!--      <div class="bottom-advertisement">-->
@@ -81,12 +85,14 @@
     <!--        </div>-->
     <!--      </div>-->
     <!--    </div>-->
-
   </div>
 </template>
 <script setup lang="ts">
 import HomeConnect from "./HomeConnent.vue";
-import GiftPackDiscounts from "./GiftPackDiscounts.vue";
+
+import GoodsTypeComponent from "../components/GoodsTypeComponent.vue";
+
+import {GoodsInfo, GoodsType} from "../entity/Entity.ts";
 import {ref} from 'vue'
 
 let showLogin = ref(false)
@@ -99,6 +105,8 @@ class LoginType {
     this.type = type;
     this.name = name;
   }
+
+  //临时的数据信息
 }
 
 let loginType = ref([new LoginType('Phone', '手机号'), new LoginType('Email', '邮箱')])
@@ -109,6 +117,25 @@ function login() {
   showLogin.value = !showLogin.value;
 }
 
+let goodsListArray = ref([
+      new GoodsType(0, "标题内容", "/router", "买了吃亏,买了上当", [
+        new GoodsInfo(0, "../assets/goodsInfo.jpg", "商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品商品0", 3.14, 98.0),
+        new GoodsInfo(1, "../assets/goodsInfo.jpg", "商品1", 98, 98.0),
+        new GoodsInfo(2, "../assets/goodsInfo.jpg", "商品2", 98, 98.0),
+        new GoodsInfo(3, "../assets/goodsInfo.jpg", "商品3", 98, 98.0),
+        new GoodsInfo(4, "../assets/goodsInfo.jpg", "商品4", 98, 98.0),
+        new GoodsInfo(5, "../assets/goodsInfo.jpg", "商品5", 98, 98.0),
+        new GoodsInfo(6, "../assets/goodsInfo.jpg", "商品6", 3.14, 98.0),
+        new GoodsInfo(7, "../assets/goodsInfo.jpg", "商品7", 3.14, 98.0),
+        new GoodsInfo(8, "../assets/goodsInfo.jpg", "商品8", 3.14, 98.0),
+        new GoodsInfo(9, "../assets/goodsInfo.jpg", "商品9", 3.14, 98.0),
+        new GoodsInfo(10, "../assets/goodsInfo.jpg", "商品10", 3.14, 98.0),
+        new GoodsInfo(11, "../assets/goodsInfo.jpg", "商品11", 3.14, 98.0),
+        new GoodsInfo(12, "../assets/goodsInfo.jpg", "商品12", 3.14, 98.0),
+        // new GoodsInfo(13, "../assets/goodsInfo.jpg", "商品13", 3.14, 98.0),
+      ])
+    ]
+)
 
 // login-form-select
 </script>

+ 0 - 1
text.txt

@@ -1 +0,0 @@
-添加测试