Vue3电商项目实战-商品详情模块7【21-商品详情-评价组件-头部渲染、22-商品详情-评价组件-实现列表】

news2024/11/26 19:53:14

文章目录

    • 21-商品详情-评价组件-头部渲染
    • 22-商品详情-评价组件-实现列表


21-商品详情-评价组件-头部渲染

在这里插入图片描述

目的:根据后台返回的评价信息渲染评价头部内容。

yapi 平台可提供模拟接口,当后台接口未开发完毕或者没有数据的情况下,可以支持前端的开发。

大致步骤:

  • 完成静态布局
  • 定义API接口
  • 获取数据,处理完毕,提供给模版
  • 渲染模版

落的代码:

  • 布局 src/views/goods/components/goods-comment.vue
<template>
  <div class="goods-comment">
    <div class="head">
      <div class="data">
        <p><span>100</span><span>人购买</span></p>
        <p><span>99.99%</span><span>好评率</span></p>
      </div>
      <div class="tags">
        <div class="dt">大家都在说:</div>
        <div class="dd">
          <a href="javascript:;" class="active">全部评价(1000)</a>
          <a href="javascript:;">好吃(1000)</a>
          <a href="javascript:;">便宜(1000)</a>
          <a href="javascript:;">很好(1000)</a>
          <a href="javascript:;">再来一次(1000)</a>
          <a href="javascript:;">快递棒(1000)</a>
        </div>
      </div>
    </div>
    <div class="sort">
      <span>排序:</span>
      <a href="javascript:;" class="active">默认</a>
      <a href="javascript:;">最新</a>
      <a href="javascript:;">最热</a>
    </div>
    <div class="list"></div>
  </div>
</template>
<script>
export default {
  name: 'GoodsComment'
}
</script>
<style scoped lang="less">
.goods-comment {
  .head {
    display: flex;
    padding: 30px 0;
    .data {
      width: 340px;
      display: flex;
      padding: 20px;
      p {
        flex: 1;
        text-align: center;
        span {
          display: block;
          &:first-child {
            font-size: 32px;
            color: @priceColor;
          }
          &:last-child {
            color: #999;
          }
        }
      }
    }
    .tags {
      flex: 1;
      display: flex;
      border-left: 1px solid #f5f5f5;
      .dt {
        font-weight: bold;
        width: 100px;
        text-align: right;
        line-height: 42px;
      }
      .dd {
        flex: 1;
        display: flex;
        flex-wrap: wrap;
        > a {
          width: 132px;
          height: 42px;
          margin-left: 20px;
          margin-bottom: 20px;
          border-radius: 4px;
          border: 1px solid #e4e4e4;
          background: #f5f5f5;
          color: #999;
          text-align: center;
          line-height: 40px;
          &:hover {
            border-color: @xtxColor;
            background: lighten(@xtxColor,50%);
            color: @xtxColor;
          }
          &.active {
            border-color: @xtxColor;
            background: @xtxColor;
            color: #fff;
          }
        }
      }
    }
  }
  .sort {
    height: 60px;
    line-height: 60px;
    border-top: 1px solid #f5f5f5;
    border-bottom: 1px solid #f5f5f5;
    margin: 0 20px;
    color: #666;
    > span {
      margin-left: 20px;
    }
    > a {
      margin-left: 30px;
      &.active,&:hover {
        color: @xtxColor;
      }
    }
  }
}
</style>
  • 接口 src/api/goods.js
/**
 * 获取商品的评价统计信息
 * @param {String} id - 商品ID
 */
export const findCommentInfoByGoods = (id) => {
  return request(`/goods/${id}/evaluate`)
}
// https://mock.boxuegu.com/mock/1175/goods/${id}/evaluate
  • 获取数据,处理数据 src/views/goods/components/goods-comment.vue
import { findCommentInfoByGoods } from '@/api/goods'
import { ref } from 'vue'
const getCommentInfo = (props) => {
  const commentInfo = ref(null)
  findCommentInfoByGoods(props.goods.id).then(data => {
    // type 的目的是将来点击可以区分点的是不是标签
    data.result.tags.unshift({ type: 'img', title: '有图', tagCount: data.result.hasPictureCount })
    data.result.tags.unshift({ type: 'all', title: '全部评价', tagCount: data.result.evaluateCount })
    commentInfo.value = data.result
  })
  return commentInfo
}
export default {
  name: 'GoodsComment',
  props: {
    goods: {
      type: Object,
      default: () => {}
    }
  },
  setup (props) {
    const commentInfo = getCommentInfo(props)
    return { commentInfo }
  }
}
  • 渲染模版 + tag选中效果 src/views/goods/components/goods-comment.vue
    <!-- 头部 -->
    <div class="head" v-if="commentInfo">
      <div class="data">
        <p><span>{{commentInfo.salesCount}}</span><span>人购买</span></p>
        <p><span>{{commentInfo.praisePercent}}</span><span>好评率</span></p>
      </div>
      <div class="tags">
        <div class="dt">大家都在说:</div>
        <div class="dd">
          <a
            v-for="(item,i) in commentInfo.tags"
            :key="item.title"
            href="javascript:;"
            :class="{active:currTagIndex===i}"
            @click="changeTag(i)"
          >
            {{item.title}}({{item.tagCount}})
          </a>
        </div>
      </div>
    </div>
    <!-- 排序 -->
    <div class="sort" v-if="commentInfo">
  setup (props) {
    const commentInfo = getCommentInfo(props)
    // 记录当前激活的索引
+    const currTagIndex = ref(0)
+    const changeTag = (i) => {
+      currTagIndex.value = i
+    }
+    return { commentInfo, currTagIndex, changeTag }
  }

22-商品详情-评价组件-实现列表

目的:完成列表渲染,筛选和排序。

在这里插入图片描述

大致步骤:

  • 列表基础布局
  • 筛选条件数据准备
  • 何时去获取数据?
    • 组件初始化
    • 点标签
    • 点排序
  • 渲染列表

落地代码:

  • 列表基础布局
    <!-- 列表 -->
    <div class="list">
      <div class="item">
        <div class="user">
          <img src="http://zhoushugang.gitee.io/erabbit-client-pc-static/uploads/avatar_1.png" alt="">
          <span>兔****m</span>
        </div>
        <div class="body">
          <div class="score">
            <i class="iconfont icon-wjx01"></i>
            <i class="iconfont icon-wjx01"></i>
            <i class="iconfont icon-wjx01"></i>
            <i class="iconfont icon-wjx01"></i>
            <i class="iconfont icon-wjx02"></i>
            <span class="attr">颜色:黑色 尺码:M</span>
          </div>
          <div class="text">网易云app上这款耳机非常不错 新人下载网易云购买这款耳机优惠大 而且耳机🎧确实正品 音质特别好 戴上这款耳机 听音乐看电影效果声音真是太棒了 无线方便 小盒自动充电 最主要是质量好音质棒 想要买耳机的放心拍 音效巴巴滴 老棒了</div>
          <div class="time">
            <span>2020-10-10 10:11:22</span>
            <span class="zan"><i class="iconfont icon-dianzan"></i>100</span>
          </div>
        </div>
      </div>
    </div>
  .list {
    padding: 0 20px;
    .item {
      display: flex;
      padding: 25px 10px;
      border-bottom: 1px solid #f5f5f5;
      .user {
        width: 160px;
        img {
          width: 40px;
          height: 40px;
          border-radius: 50%;
          overflow: hidden;
        }
        span {
          padding-left: 10px;
          color: #666;
        }
      }
      .body {
        flex: 1;
        .score {
          line-height: 40px;
          .iconfont {
            color: #ff9240;
            padding-right: 3px;
          }
          .attr {
            padding-left: 10px;
            color: #666;
          }
        }
      }
      .text {
        color: #666;
        line-height: 24px;
      }
      .time {
        color: #999;
        display: flex;
        justify-content: space-between;
        margin-top: 5px;
      }
    }
  }
  • 筛选条件数据准备
    • 定义筛选条件
    // 筛选条件准备
    const reqParams = reactive({
      page: 1,
      pageSize: 10,
      hasPicture: null,
      tag: null,
      sortField: null
    })
  • 收集排序条件
      <!-- 排序 -->
      <div class="sort">
        <span>排序:</span>
        <a
          @click="changeSort(null)"
          href="javascript:;"
          :class="{active:reqParams.sortField===null}"
        >默认</a>
        <a
          @click="changeSort('praiseCount')"
          href="javascript:;"
          :class="{active:reqParams.sortField==='praiseCount'}"
        >最热</a>
        <a
          @click="changeSort('createTime')"
          href="javascript:;"
          :class="{active:reqParams.sortField==='createTime'}"
        >最新</a>
      </div>
      // 改变排序
      const changeSort = (type) => {
        reqParams.sortField = type
         reqParams.page = 1
      }
  • 收集标签和是否有图条件
      const changeTag = (i) => {
        currTagIndex.value = i
+      // 设置有图和标签条件
+      const currTag = commentInfo.value.tags[i]
+      if (currTag.type === 'all') {
+        reqParams.hasPicture = false
+        reqParams.tag = null
+      } else if (currTag.type === 'img') {
+        reqParams.hasPicture = true
+        reqParams.tag = null
+      } else {
+        reqParams.hasPicture = false
+        reqParams.tag = currTag.title
+      }
+      reqParams.page = 1
      }
  • 获取数据(当组件初始化的时候,筛选条件改变的时候)
    // 初始化或者筛选条件改变后,获取列表数据。
    const commentList = ref([])
    watch(reqParams, async () => {
      const data = await findCommentListByGoods(props.goods.id, reqParams)
      commentList.value = data.result.items
    }, { immediate: true })
  • 渲染模版
    • 处理数据,昵称加*号,规格拼接字符串。
    // 定义转换数据的函数(对应vue2.0的过滤器)
    const formatSpecs = (specs) => {
      return specs.reduce((p, c) => `${p} ${c.name}${c.nameValue}`, '').trim()
    }
    const formatNickname = (nickname) => {
      return nickname.substr(0, 1) + '****' + nickname.substr(-1)
    }
  • 所有数据和函数
return { commentInfo, currentTagIndex, changeTag, reqParams, commentList, changeSort, formatSpecs, formatNickname }
  • 渲染html
  <!-- 列表 -->
    <div class="list">
      <div class="item" v-for="item in commentList" :key="item.id">
        <div class="user">
          <img :src="item.member.avatar" alt="">
          <span>{{formatNickname(item.member.nickname)}}</span>
        </div>
        <div class="body">
          <div class="score">
            <i v-for="i in item.score" :key="i+'1'" class="iconfont icon-wjx01"></i>
            <i v-for="i in 5-item.score" :key="i+'2'" class="iconfont icon-wjx02"></i>
            <span class="attr">{{formatSpecs(item.orderInfo.specs)}}</span>
          </div>
          <div class="text">{{item.content}}</div>
          <div class="time">
            <span>{{item.createTime}}</span>
            <span class="zan"><i class="iconfont icon-dianzan"></i> {{item.praiseCount}}</span>
          </div>
        </div>
      </div>
    </div>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/373179.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CentOS 7安装Docker并使用tomcat测试

文章目录环境准备Docker安装安装tomcat环境准备 CentOS 7以上版本linux内核版本需要在3.10以上&#xff0c;可通过uname -r 查看系统内核。 Docker安装 检查docker安装源 yum list docker yum安装docker &#xff1a; yum install docker.x86_64 启动 docker &#xff1a; s…

操作系统权限提升(十六)之绕过UAC提权-CVE-2019-1388 UAC提权

系列文章 操作系统权限提升(十二)之绕过UAC提权-Windows UAC概述 操作系统权限提升(十三)之绕过UAC提权-MSF和CS绕过UAC提权 操作系统权限提升(十四)之绕过UAC提权-基于白名单AutoElevate绕过UAC提权 操作系统权限提升(十五)之绕过UAC提权-基于白名单DLL劫持绕过UAC提权 注&a…

QML Item和Rectangle详解

1.Item和Rectangle Item类型是Qt Quick中所有可视项的基本类型。 Qt Quick中的所有可视项都继承Item。尽管Item对象没有视觉外观&#xff0c;但它定义了视觉项中常见的所有属性&#xff0c;例如x和y位置、宽度和高度、锚定和键处理支持。 Rectangle继承自Item&#xff0c;多…

数组初始化方式与decimal.InvalidOperation

数组初始化方式与decimal.InvalidOperation调用函数主函数: 数组声明不同带来的报错与否1. 报错decimal.InvalidOperation的数组初始化版本2. 可行的初始化版本输出结果1. 报错时的内容2. 正常的输出计算结果原因&#xff08;是否是数组与列表不同引起&#xff08;&#xff1f;…

因果推断10--一种大规模预算约束因果森林算法(LBCF)

论文&#xff1a;A large Budget-Constrained Causal Forest Algorithm 论文&#xff1a;http://export.arxiv.org/pdf/2201.12585v2.pdf 目录 0 摘要 1 介绍 2 问题的制定 3策略评价 4 方法 4.1现有方法的局限性。 4.2提出的LBCF算法 5验证 5.1合成数据 5.2离线生…

gitlab部署使用,jenkins部署使用

gitlab部署使用&#xff0c;jenkins部署使用gitlab下载gitlab安装gitlab使用gitlab设置中文修改管理员密码创建组,创建项目,创建用户jenkins下载jenkins安装jenkin使用jenkins更改管理员密码配置拉取代码配置登录gitlab拉取代码的账号密码配置项目配置gitlab仓库配置构建构建构…

动态分区分配计算

动态分区分配 内存连续分配管理分为&#xff1a; 单一连续分配固定分区分配动态分区分配&#xff08;本篇所讲&#xff09; 首次适应算法&#xff08;First Fit&#xff0c;FF&#xff09; 该算法又称最先适应算法&#xff0c;要求空闲分区按照首地址递增的顺序排列。 优点…

数据结构——树

深度优先/广度优先遍历深度优先&#xff1a;访问根节点对根节点的 children 挨个进行深度优先遍历const tree {val: "a",children: [{val: "b",children: [{val: "d",children: [],},{val: "e",children: [],},],},{val: "c&quo…

可靠性设计

目录 一、可靠性设计概述 二、冗余的类型 三、冗余系统的设计 1.N版本程序设计 2.恢复块设计 3.防卫式程序设计 4.双机容错 一、可靠性设计概述 可靠性指系统能够正常运行的概率。如何设计出一个具有高可靠性的系统呢&#xff1f;可以利用避错技术&#xff0c;容错技术…

【LeetCode】剑指 Offer 16. 数值的整数次方 p110 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/ 1. 题目介绍&#xff08;16. 数值的整数次方&#xff09; 实现 pow(x, n) &#xff0c;即计算 x 的 n 次幂函数&#xff08;即&#xff0c;xn&#xff09;。不得使用库函数&#xff0c;…

文献计量分析方法:Citespace安装教程

Citespace是一款由陈超美教授开发的可用于海量文献可视化分析的软件&#xff0c;可对Web of Science&#xff0c;Scopus&#xff0c;Pubmed&#xff0c;CNKI等数据库的海量文献进行主题、关键词&#xff0c;作者单位、合作网络&#xff0c;期刊、发表时间&#xff0c;文献被引等…

数据结构入门5-2(数和二叉树)

目录 注&#xff1a; 树的存储结构 1. 双亲表示法 2. 孩子表示法 3. 重要&#xff1a;孩子兄弟法&#xff08;二叉树表示法&#xff09; 森林与二叉树的转换 树和森林的遍历 1. 树的遍历 2. 森林的遍历 哈夫曼树及其应用 基本概念 哈夫曼树的构造算法 1. 构造过程 …

响应性基础API

一.什么是proxy和懒代理&#xff1f;什么是proxy?proxy对象是用于定义基本操作的自定义行为(如&#xff1a;属性查找&#xff0c;赋值&#xff0c;枚举&#xff0c;函数调用等等)。什么是懒代理&#xff1f;懒代理&#xff1a;在初始化的时候不会进行全部代理&#xff0c;而是…

数据仓库Hive

HIve介绍 Hive是建立在Hadoop上的数据仓库基础构架。它提供了一系列的工具&#xff0c;可以用来进行数据提取转化加载&#xff0c;可以简称为ETL。 Hive 定义了简单的类SQL查询语言&#xff0c;称为HQL&#xff0c;它允许熟悉SQL的用户直接查询Hadoop中的数据&#xf…

三万字全面概述关于5G-V2X技术和应用

5G技术有望实现更快的网联链接、更低的延迟、更高的可靠性、更大的容量和更广的覆盖范围。希望依靠这些技术来实现车辆到一切&#xff08;V2X&#xff09;的通信&#xff0c;除了道路安全外&#xff0c;还能提高车辆的安全性和自动驾驶性能&#xff0c;节约能源和成本。车辆通信…

算法设计与分析期末考试复习(四)

贪心算法&#xff08;Greedy Algorithm&#xff09; 找零钱问题 假设有4种硬币&#xff0c;面值分别为&#xff1a;二角五分、一角、五分和一分&#xff0c;现在要找给顾客六角三分钱&#xff0c;如何找使得给出的硬币个数最少&#xff1f; 首先选出1个面值不超过六角三分的最…

improve-2

BFC 块级格式化上下文&#xff0c;是一个独立的渲染区域&#xff0c;让处于 BFC 内部的元素与外部的元素相互隔离&#xff0c;使内外元素的定位不会相互影响。 IE下为 Layout&#xff0c;可通过 zoom:1 触发 触发条件: 根元素position: absolute/fixeddisplay: inline-block /…

[计算机网络(第八版)]第三章 数据链路层(学习笔记)

物理层解决了相邻节点透明传输比特的问题 3.1 数据链路层的几个共同问题 3.1.1 数据链路和帧 链路&#xff1a; 从一个节点到相邻节点的一段物理线路&#xff0c;中间没有任何其他的交换节点 数据链路&#xff1a; 节点间的逻辑通道是把实现控制数据传输的协议的硬件和软件加…

Unity Avatar Foot IK - Avatar Foot Placement Resolution

文章目录简介实现Avatar FBX Import SettingsAnimator SettingsOn Animator IKCalculate IK Position & RotationBody PositionApply IK Position & Rotation简介 通过Unity内部的Mecanim动画系统实现的FootIK功能&#xff0c;效果如图所示&#xff0c;左右分别为开启…

计算机网络协议—应用层

应用层网络协议 应用层的常见协议 超文本传输&#xff1a;HTTP、HTTPS文本传输&#xff1a;FTP电子邮件&#xff1a;SMTP、POP3、IMAP动态主机配置&#xff1a;DHCP域名系统&#xff1a;DNS 域名&#xff08;Domain Name&#xff09; 由于IP地址不方便记忆&#xff0c;并且不…