网页底部信息和产品列表页面开发

本节完成页面底部和全部产品页面的布局,首先考虑页面底部是在哪个组件中,因为每个页面的底部样式都是一样的,所以不能在 home.vue 中写底部样式,如果在 home.vue 组件中写底部样式则其他页面需要再写一次,因此应该在主组件 App.vue 中写底部代码,如下所示。

<template>
  <div id="app">
    <router-view />
    <!--网页底部信息-->
    <div class="footer"></div>
    <div class="foot"></div>
  </div>
</template>

代码解析如下。

把底部信息放到 App.vue 中是因为所有页面的底部信息都是一样的。没有把头部导航放在 App.vue 中是因为产品详情页面没有使用头部导航。

下面讲解全部产品页面布局。

新建全部产品页面组件,创建路由匹配规则,进入全部产品页面。

在 views 目录新建 productList/index.vue,如图 11-11 所示。

image 2025 02 11 20 19 11 978
Figure 1. 图11-11 创建产品列表页

打开 router/index.js,创建路由匹配规则,代码如下。

import Vue from 'vue';
import Router from 'vue-router';
import index from '../views/index';
import home from '../components/home.vue';
// 1. 引入 productList 组件
import alllist from '../views/productList';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'index',
      component: index,
      children: [
        {
          path: '/',
          name: 'home',
          component: home
        },
        // 2. 嵌套路由
        {
          path: '/alllist',
          name: 'alllist',
          component: alllist
        }
      ]
    }
  ]
});

为导航添加跳转链接,打开 header.vue 组件,修改导航菜单,代码如下。

<div class="menu">
  <div class="content">
    <ul>
      <li class="bg_active">
        <router-link to="/">首页</router-link>
      </li>
      <li>
        <router-link to="/alllist">全部产品</router-link>
      </li>
    </ul>
  </div>
</div>

单击 “全部产品” 链接,进入 alllist/index.vue 组件,最后布局页面即可。

产品列表静态页面布局

产品列表的静态视图代码如下。

<template>
  <div>
    <div class="content">
      <div class="index_hot">
        <div class="index_hot_menu">
          <span>综合排序</span>
          <span>价格由高到低</span>
          <span>价格由低到高</span>
          <em>
            <input type="text" /> -
            <input type="text" />
            <input type="button" value="价格筛选" />
          </em>
        </div>
        <div class="index_hot_main">
          <ul>
            <li>
              <img src="../../assets/images/p1.jpg" />
              <p>
                名字<br />描述
              </p>
            </li>
            <li>
              <img src="../../assets/images/p1.jpg" />
              <p>
                名字<br />描述
              </p>
            </li>
            <li>
              <img src="../../assets/images/p1.jpg" />
              <p>
                名字<br />描述
              </p>
            </li>
            <li>
              <img src="../../assets/images/p1.jpg" />
              <p>
                名字<br />描述
              </p>
            </li>
            <li>
              <img src="../../assets/images/p1.jpg" />
              <p>
                名字<br />描述
              </p>
            </li>
            <li>
              <img src="../../assets/images/p1.jpg" />
              <p>
                名字<br />描述
              </p>
            </li>
            <li>
              <img src="../../assets/images/p1.jpg" />
              <p>
                名字<br />描述
              </p>
            </li>
            <li>
              <img src="../../assets/images/p1.jpg" />
              <p>
                名字<br />描述
              </p>
            </li>
            <li>
              <img src="../../assets/images/p1.jpg" />
              <p>
                名字<br />描述
              </p>
            </li>
          </ul>
        </div>
      </div>
    </div>
  </div>
</template>

运行结果如图 11-12 所示。

image 2025 02 11 20 27 53 289
Figure 2. 图11-12 产品列表页效果图

渲染全部产品页面数据

11.3.1 节完成了全部产品静态页面布局,本节使用 axios 从服务器端获取真实数据渲染到页面,接口地址为 http://api.mm2018.com:8095/api/goods/allGoods?page=1&size=8&sort=''&priceGt=''&priceLte=''

请求方式:get请求。

相关参数说明如下。

  • page:当前显示页面。

  • size:每页显示数据条数。

  • sort:空为默认排序,1为正序,−1为倒序。

  • priceGt:价格筛选最小值。

  • priceLte:价格筛选最大值。

M 层获取所有产品数据,代码如下。

export default {
  data() {
    return {
      // 1. 定义 allList 空数组接收所有产品
      allList: []
    };
  },
  methods: {
    // 2. 声明方法使用 axios 通用形式调用接口
    getAll() {
      this.$axios({
        method: 'get',
        url: `http://api.mm2018.com:8095/api/goods/allGoods?page=1&size=6&sort=''&priceGt=''&priceLte=''`
      }).then(res => {
        // console.log(res.data.data)
        this.allList = res.data.data;
      }).catch(error => {
        console.error("获取商品列表失败:", error);
        // 处理错误,例如显示错误信息
      });
    }
  },
  created() {
    // 3. 在 created 生命周期函数中调用获取数据的方法
    this.getAll();
  }
};

此时获取到的所有数据都存放在 allList 属性中,视图层使用 v-for 遍历 allList 数组渲染数据,代码如下。

<div class="index_hot_main">
  <ul>
    <li v-for="(item, i) in allList" :key="item.id">
      <img :src="item.productImageUrl" />
      <p>
        {{ item.productName }}<br>{{ item.salePrice }}元
      </p>
    </li>
  </ul>
</div>

运行结果如图 11-13 所示。

image 2025 02 11 20 31 22 432
Figure 3. 图11-13 获取产品列表页数据

当前接口参数 page、size、sort、priceGt、priceLte 都是固定的,这里的参数应该设置为动态获取,代码如下。

export default {
  data() {
    return {
      allList: [],
      // 1. 参数在 data 中定义
      page: 1,
      size: 6,
      sort: null,
      priceGt: null,
      priceLte: null
    };
  },
  methods: {
    // 2. 把参数拼接到请求地址
    getAll() {
      this.$axios({
        method: 'get',
        url: `http://api.mm2018.com:8095/api/goods/allGoods?page=${this.page}&size=${this.size}&sort=${this.sort}&priceGt=${this.priceGt}&priceLte=${this.priceLte}`
      }).then(res => {
        // console.log(res.data.data)
        this.allList = res.data.data;
      }).catch(error => {
        console.error("获取商品列表失败:", error);
        // 处理错误,例如显示错误信息
      });
    }
  },
  created() {
    // 3. 在 created 生命周期函数中调用获取数据的方法
    this.getAll();
  }
};

把参数设置为动态获取,是因为排序功能和价格范围筛选功能是通过修改参数值实现的。

产品价格排序功能

本节实现产品价格排序功能。为了更清楚地显示具体单击了哪个菜单,首先实现菜单排他,单击菜单使其变色,代码如下。

CSS 代码如下。

<style scoped>
.active{color: #333;}
</style>

视图层代码如下。

<div class="index_hot_menu">
  <span :class="{ active: isActive == 0 }" @click="sortBtn(0)">综合排序</span>
  <span :class="{ active: isActive == 1 }" @click="sortBtn(1)">价格由高到低</span>
  <span :class="{ active: isActive == 2 }" @click="sortBtn(2)">价格由低到高</span>
</div>

JS 逻辑代码如下。

methods: {
  sortBtn(i) {
    this.isActive = i;
  }
}

运行代码,实现菜单排他功能,最后修改 sort 值,即可实现排序功能,代码如下。

sortBtn(i) {
  this.isactive = i; // 1. Update active button state

  if (i == 0) {
    // 2. Default sorting
    this.sort = null;
    this.getAll(); // 3. Refresh data
  }
  if (i == 1) {
    // 4. Price low to high
    this.sort = 1;
    this.getAll();
  }
  if (i == 2) {
    // 5. Price high to low
    this.sort = -1;
    this.getAll();
  }
}

产品价格范围筛选功能

实现思路:使用 v-model 双向数据绑定,获取用户输入的最小值和最大值,单击 “价格筛选” 按钮,重新调用方法获取数据即可,代码如下。

视图层代码如下。

<em>
    <input type="text" v-model="priceGt" /> -
    <input type="text" v-model="priceLte" />
    <input type="button" value="价格筛选" @click="priceBtn()" />
</em>

JS 逻辑代码如下。

<script>
export default {
  data() {
    return {
      allList: [],
      page: 1,
      size: 6,
      sort: null,
      priceGt: null,
      priceLte: null,
      isactive: 0
    };
  },
  methods: {
    //单击“价格筛选”按钮,重新获取数据
    priceBtn() {
      if (this.priceLte > this.priceGt) {
        this.getAll();
      } else {
        alert('最高价格必须大于最低价格');
      }
    },
    getAll() {
      this.$axios({
        methods: 'get',
        url: `http://api.mm2018.com:8095/api/goods/allGoods?page=${this.page}&size=${this.size}&sort=${this.sort}&priceGt=${this.priceGt}&priceLte=${this.priceLte}`
      }).then(res => {
        this.allList = res.data.data;
      }).catch(error => {
        console.error('Error fetching data:', error);
      });
    }
  },
  mounted() {
    this.getAll();
  }
};
</script>

运行结果如图 11-14 所示。

image 2025 02 11 20 52 04 982
Figure 4. 图11-14 产品价格范围筛选