E商城(移动App)项目实施



一、创建项目

1.安装 vue-cli

$ npm install -g @vue/cli

2.创建项目

$ vue create e-mall
  1. 第一步:image-20230104150923798

  2. 第二步:image-20230104150957973

  3. 第三步:image-20230104140823294

  4. 第四步:image-20230104140846665

  5. 第五步:image-20230104151101281

  6. 第六步:image-20230104151129399

  7. 第七步:image-20230104151202534

  8. 项目创建成功:image-20230104151310685

二、安装使用 Vant UI

1.安装 Vant UI

$ npm i vant@latest-v2 -S

2.引入使用Vant UI

修改 main.js

import Vant from 'vant';
import 'vant/lib/index.css';
Vue.use(Vant);

三、修改 App.vue

修改 App.vue

<template>
  <div id="app">
    <router-view style="padding-bottom: 60px"/>

    <van-tabbar active-color="#42b983" route>
      <van-tabbar-item to="/" icon="home-o">首页</van-tabbar-item>
      <van-tabbar-item to="/category" icon="apps-o">分类</van-tabbar-item>
      <van-tabbar-item to="/cart" icon="shopping-cart-o">购物车</van-tabbar-item>
      <van-tabbar-item to="/mine" icon="user-o">我的</van-tabbar-item>
    </van-tabbar>
  </div>
</template>

<style lang="less">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
}

body {
  margin: 0;
}

#app .van-nav-bar__title {
  font-weight: bold;
  color: #fff;
}
</style>

四、添加首页布局

image-20230104153729520

修改 HomeView.vue

<template>
  <div class="home">
    <van-nav-bar title="E商城" border style="background-color: #42b983"/>

    <van-sticky>
      <van-search
        v-model="search"
        shape="round"
        placeholder="请输入搜索关键词"
        background="#42b983"
      />
    </van-sticky>

    <van-swipe class="my-swipe" height="200" :autoplay="3000">
      <van-swipe-item v-for="(item, index) in banner" :key="index">
        <img :src="item.url" :alt="item.content">
      </van-swipe-item>
    </van-swipe>

    <van-grid :column-num="5">
      <van-grid-item
        v-for="(item, index) in channel"
        :key="item.id"
        :icon="item.iconUrl"
        :text="item.name"
      />
      <van-grid-item
        icon="ellipsis"
        text="更多"
      />
    </van-grid>

    <div>
      <van-card
        v-for="item in filterGoodsList"
        :price="item.retailPrice.toFixed(2)"
        :origin-price="item.counterPrice.toFixed(2)"
        :desc="item.brief"
        :title="item.name"
        :thumb="item.picUrl"
        @click="toDetailPage(item.id)"
      >
        <template #tags>
          <van-tag plain type="danger" v-if="item.isHot">热销</van-tag>
          &nbsp;
          <van-tag plain type="danger" v-if="item.isNew">新品</van-tag>
        </template>
      </van-card>
    </div>
  </div>
</template>

<script>
export default {
  name: 'HomeView',
  data() {
    return {
      search: '',
      banner: [],
      channel: [],
      goodsList: [],
    }
  },
  methods: {
    toDetailPage(id) {
      this.$router.push({
        name: 'product',
        params: {
          id
        }
      })
    }
  }
}
</script>

<style>
.my-swipe img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.title {
  padding: 10px 16px 0;
  color: rgba(69, 90, 100, 0.6);
  font-size: 14px;
}
</style>

五、添加首页API

1.启动 litemall-wx-api-0.1.0-exec

$ java -jar litemall-wx-api-0.1.0-exec.jar

2.安装 axios

$ npm i axios -S

3.修改 main.js

import axios from "axios";
Vue.prototype.$axios = axios

4.完善 HomeView.vue

<template>
  <div class="home">
    <van-nav-bar title="E商城" border style="background-color: #42b983"/>

    <van-sticky>
      <van-search
        v-model="search"
        shape="round"
        placeholder="请输入搜索关键词"
        background="#42b983"
      />
    </van-sticky>

    <van-swipe class="my-swipe" height="200" :autoplay="3000">
      <van-swipe-item v-for="(item, index) in banner" :key="index">
        <img :src="item.url" :alt="item.content">
      </van-swipe-item>
    </van-swipe>

    <van-grid :column-num="5">
      <van-grid-item
        v-for="(item, index) in channel.slice(0, 9)"
        :key="item.id"
        :icon="item.iconUrl"
        :text="item.name"
      />
      <van-grid-item
        icon="ellipsis"
        text="更多"
      />
    </van-grid>

    <van-list
      v-model="loading"
      :finished="finished"
      finished-text="我是有底线的"
      @load="onLoad"
    >
      <van-card
        v-for="item in filterGoodsList"
        :price="item.retailPrice.toFixed(2)"
        :origin-price="item.counterPrice.toFixed(2)"
        :desc="item.brief"
        :title="item.name"
        :thumb="item.picUrl"
        @click="toDetailPage(item.id)"
      >
        <template #tags>
          <van-tag plain type="danger" v-if="item.isHot">热销</van-tag>
          &nbsp;
          <van-tag plain type="danger" v-if="item.isNew">新品</van-tag>
        </template>
      </van-card>
    </van-list>
<!--    <van-divider>我是有底线的</van-divider>-->
  </div>
</template>

<script>
export default {
  name: 'HomeView',
  data() {
    return {
      search: '',
      banner: [],
      channel: [],
      goodsList: [],
      loading: false,
      finished: false,
      page: 1,
      limit: 20
    }
  },
  computed: {
    filterGoodsList() {
      return this.goodsList.filter(item => item.name.includes(this.search))
    }
  },
  created() {
    this.$axios({
      url: 'http://localhost:8081/wx/home/index',
    }).then(res => {
      this.banner = res.data.data.banner
      this.channel = res.data.data.channel
      this.floorGoodsList = res.data.data.floorGoodsList
    })

    this.loading = true
    this.$axios({
      url: 'http://localhost:8081/wx/goods/list',
    }).then(res => {
      this.goodsList = res.data.data.list
      console.log(res.data.data)
    }).finally(() => {
      this.loading = false
    })
  },
  methods: {
    onLoad() {
      this.page++
      this.$axios({
        url: `http://localhost:8081/wx/goods/list?page=${this.page}&limit=${this.limit}`,
      }).then(res => {
        this.goodsList = [...this.goodsList, ...res.data.data.list]
        console.log(res.data.data)
        if (res.data.data.list.length < this.limit) {
          this.finished = true
        }
      }).finally(() => {
        this.loading = false
      })
    },
    toDetailPage(id) {
      this.$router.push({
        name: 'product',
        params: {
          id
        }
      })
    }
  }
}
</script>

<style>
.my-swipe img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.title {
  padding: 10px 16px 0;
  color: rgba(69, 90, 100, 0.6);
  font-size: 14px;
}
</style>

六、商品详情页实施

image-20230104153819918

1.views/ 文件夹创建 ProductView.vue

<template>
  <div>
    <van-nav-bar title="E商城" border style="background-color: #42b983"/>
    <van-swipe
      class="my-swipe"
      height="300"
      :autoplay="3000"
      indicator-color="#42b983"
    >
      <van-swipe-item v-for="(image, index) in productInfo.gallery" :key="index">
        <img :src="image" alt="">
      </van-swipe-item>
    </van-swipe>
    <div class="info">
      <div class="price">
        <span>价格:<b></b></span>
        <span>原价:<del></del></span>
      </div>
      <div class="name"></div>
      <div class="desc"></div>
    </div>

    <div class="detail" v-html="productInfo.detail"></div>

    <van-goods-action style="bottom: 50px">
      <van-goods-action-icon icon="chat-o" text="客服" />
      <van-goods-action-icon icon="cart-o" text="购物车" />
      <van-goods-action-icon icon="shop-o" text="店铺" />
      <van-goods-action-button type="warning" text="加入购物车" />
      <van-goods-action-button type="danger" text="立即购买" />
    </van-goods-action>
  </div>
</template>

<script>
export default {
  name: "ProductView",
  data() {
    return {
      productInfo: {},
      product: {},
    }
  },
  created() {
    const { id } = this.$route.params
    this.$axios({
      url: 'http://localhost:8081/wx/goods/detail?id='+id
    }).then(res => {
      console.log(res.data.data)
      console.log(res.data.data.info)
      this.productInfo = res.data.data.info
      this.product = res.data.data
    })
  },
  methods: {
    onClickButton() {

    }
  }
}
</script>

<style lang="less">
.my-swipe img {
  height: 100%;
  width: 100%;
  object-fit: cover;
}

.info {
  .price {
    background: #ea5b5b;
    display: flex;
    align-items: flex-end;
    color: #ffd01e;
    padding: 15px;
    font-size: 22px;

    span:last-child {
      margin-left: 10px;
      font-size: 14px;
      color: #fff;
    }
  }

  .name {
    padding: 10px 10px 0;
    font-size: 18px;
  }

  .desc {
    padding: 0 10px 10px;
    font-size: 14px;
    color: gray;
  }
}

.detail {
  p {
    margin: 0;
  }
  img {
    display: block;
    width: 100%;
  }
}
</style>

2.添加路由访问

  {
    path: '/product/:id',
    name: 'product',
    component: () => import('../views/ProductView')
  },

七、商品分类页实施

image-20230104153845620

1.views/ 文件夹创建 CategoryView.vue

<template>
  <div>
    <van-nav-bar title="E商城 | 分类" border style="background-color: #42b983"/>

    <van-tree-select
      :items="categories"
      :main-active-index="mainActiveIndex"
      @click-nav="clickNav"
      @click-item="clickItem"
    />
  </div>
</template>

<script>
export default {
  name: "CategoryView",
  data: () => ({
    mainActiveIndex: 0,
    categories: []
  }),
  created() {
    this.$axios({
      url: 'http://localhost:8081/wx/catalog/index'
    }).then(res => {
      this.categories = res.data.data.categoryList.map(item => {
        return {
          text: item.name,
          id: item.id
        }
      })
      this.categories[0].children = res.data.data.currentSubCategory.map(item => {
        return {
          text: item.name,
          id: item.id
        }
      })
    })
  },
  methods: {
    onSearch() {
      console.log(this.search)
    },
    clickNav(index) {
      if (!this.categories[index].children) {
        const id = this.categories[index].id
        this.$axios({
          url: ' http://localhost:8081/wx/catalog/current?id='+id
        }).then(res => {
          this.categories[index].children = res.data.data.currentSubCategory.map(item => {
            return {
              text: item.name,
              id: item.id,
            }
          })

          this.mainActiveIndex = index
        })
      } else {
        this.mainActiveIndex = index
      }
    },
    clickItem(data) {
      console.log(data)
    }
  }
}
</script>

<style>
.van-tree-select {
  height: 100%!important;
}
</style>

2.添加路由访问

  {
    path: '/category',
    name: 'category',
    component: () => import('../views/CategoryView')
  },