商城项目整体构建

news/2024/3/29 20:15:32/文章来源:https://blog.csdn.net/weixin_42565135/article/details/125755111

一、

1.项目结构分配、模块的定义、组件封装调用(先定义、然后导入 注册 使用)、路由拦截、cookie理解、token权限、路由权限管理、动态路由、打包部署、vuex状态管理、接口文档

对于跳转,要先设置路由确保组件可以正常使用、路由可以正常跳转,再充实页面

对于左边导航与上边面包屑的联动,可以通过this.$route.matched获取该路由的所有信息,然后在每一个路由中写一个meta对应路由的内容,在面包屑那块通过遍历当前路由信息展示meta的值

对于导航栏的多级菜单,可以通过递归进行展示

父子组件传值的时候,子组件中通过props接收父组件传过来的值

二、流程

1.脚手架创建项目,并且 关闭eslint校验以防写代码时没错也报错

node_modules:放置项目依赖的地方。
public:一般放置一些共用的静态资源,打包上线的时候,public文件夹里面资源原封不动打包到dist文件夹里面。
src:程序员源代码文件夹:
assets:经常放置一些静态资源(公用的图片(即很多组件都用此图)),assets文件夹里面资源webpack会进行打包为一个模块(js文件夹里面)
components:一般放置非路由组件(如共用的组件)
App.vue:唯一的根组件
main.js:入口文件【程序最先执行的文件】
babel.config.js:babel配置文件
package.json:项目描述、项目依赖、项目运行
README.md:项目说明文件

2.在开发项目的时候:

非路由组件:

  • 书写静态页面(HTML + CSS)
  • 拆分组件
  • 获取服务器的数据动态展示
  • 完成相应的动态业务逻辑

路由组件

  • 创建组件:Vue.component(tagName, options)                   

                         var 组件内容 = Vue.extend({template: '<div>自定义全局组件,使用Vue.extend</div>'})Vue.component("组件名称",组件内容)

  • 在router中创建并配置具体路由
  • 在main.js中引入进行全局注册路由
  • 在app.vue中:<!-- 路由组件出口的地方、路由组件展示 --> <router-view></router-view>
  • 在需要的地方引入标签

3.mockjs模拟数据 

使用Mock.js插件,生成随机数据,拦截 Ajax 请求。

  • 前后端分离:让前端攻城师独立于后端进行开发。
  • 增加单元测试的真实性:通过随机数据,模拟各种场景。
  • 开发无侵入:不需要修改既有代码,就可以拦截 Ajax 请求,返回模拟的响应数据。
  • 用法简单:符合直觉的接口。
  • 数据类型丰富:支持生成随机的文本、数字、布尔值、日期、邮箱、链接、图片、颜色等。
  • 方便扩展:支持支持扩展更多数据类型,支持自定义函数和正则。

4.购物车的管理

1.逻辑:点击加入购物车,将详情页的数据加入购物车中;

此时需要对state中的cartList进行修改,点击加入购物车就会执行store文件中actions对象里定义的加入购物车方法,actions对象中对加入的商品进行判断,若之前商品已存在,则数量加1,若商品不存在,则将商品添加进cartList。其返回一个promise对象。

2.组件:在购物车模块里可以查看详细信息 更新数量,全选反全选  取消加购 去结款

  • 将加入购物车中的商品对象放到cartList中了,商品对象中包括需要在购物车中展示的详细信息。首先将通过store中的getters属性接收vuex中的数据,通过v-for来对cartList中的商品对象进行遍历,同时展示单个商品信息的组件通过props来接收父组件传来的单个商品对象;在计算属性computed中接收vuex中挂载的数据。
  • 通过数组的filter方法找出选中的商品 ,然后通过数组的reduce方法对选中商品的价值总额进行计算;
  • 全选的逻辑:若部分商品或者全部商品未被选中,则利用forEach使cartList中的每个商品为选中状态;若全部选中,则使cartList中的每个商品为未选中状态

3.数据交互:通过vuex状态管理机制来实现购物车的数据交互,创建store文件并挂载在vue实例上,在store文件中定义一个可以挂载数据的state,在其中定义一个数组cartList来存放商品信息,其他组件就可以获取并使用这个数据了。

store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)export default new Vuex.Store({state: {carList: [] //购物车的商品},mutations: {// 加addCar(state, params) {let CarCon = state.carList;// 判断如果购物车是否有这个商品,有就只增加数量,否则就添加一个// some 只要有一个isHas为true,就为truelet isHas = CarCon.some((item) => {if (params.id == item.id) {item.num++;return true;} else {return false;}})if (!isHas) {let obj = {"id": params.id,"title": params.title,"price": params.price,"num": 1,}this.state.carList.push(obj)}},// 减reducedCar(state,params){let len=state.carList.length;for(var i=0;i<len;i++){if(state.carList[i].id==params.id){state.carList[i].num--if(state.carList[i].num==0){state.carList.splice(i,1);break;}}}},//移出deleteCar(state,params){let len=state.carList.length;for(var i=0;i<len;i++){if(state.carList[i].id==params.id){state.carList.splice(i,1);break;}}},// 初始化购物车,有可能用户一登录直接进入购物车// initCar(state, car) {//     state.carList = car// },},actions: {// 加addCar({ commit }, params) {// console.log(params) //点击添加传过来的参数// 使用setTimeout模拟异步获取购物车的数据setTimeout(function () {let result = 'ok'if (result == 'ok') {// 提交给mutationscommit("addCar", params)}}, 100)},// 减reducedCar({ commit }, params) {// console.log(params) //点击添加传过来的参数// 使用setTimeout模拟异步获取购物车的数据setTimeout(function () {let result = 'ok'if (result == 'ok') {// 提交给mutationscommit("reducedCar", params)}}, 100)},// 移出deleteCar({ commit }, params) {// console.log(params) //点击添加传过来的参数// 使用setTimeout模拟异步获取购物车的数据setTimeout(function () {let result = 'ok'if (result == 'ok') {// 提交给mutationscommit("deleteCar", params)}}, 100)}// initCar({ commit }) {//     setTimeout(function () {//         let result = 'ok'//         if (result == 'ok') {//             // 提交给mutations//             commit("initCar", [{//                 "id": 20193698,//                 "title": '我是购物车原来的',//                 "price": 30,//                 "num": 100,//             }])//         }//     }, 100)// }},getters: {//返回购物车的总价totalPrice(state) {let Carlen = state.carList;let money = 0;if (Carlen.length != 0) {Carlen.forEach((item) => {money += item.price * item.num})return money;} else {return 0;}},//返回购物车的总数carCount(state) {return state.carList.length}},
})list.vue<template><!-- 商品列表 --><div id="listBox"><!--  --><router-link :to="{path:'/car'}" style="line-height:50px">跳转到购物车</router-link><el-table :data="tableData" border style="width: 100%"><el-table-column fixed prop="id" align="center" label="商品id"></el-table-column><el-table-column prop="title" align="center" label="商品标题"></el-table-column><el-table-column prop="price" align="center" label="商品价格"></el-table-column><el-table-column label="操作" align="center"><template slot-scope="scope"><el-button @click="addCar(scope.row)" type="text" size="small">加入购物车</el-button></template></el-table-column></el-table></div>
</template><script>
export default {name: "listBox",data() {return {tableData: [] //商品列表};},methods: {// 初始化商品列表initTable(){this.$gAjax(`../static/shopList.json`).then(res => {console.log(res)this.tableData=res;})["catch"](() => {});},// 加入购物车addCar(row){// console.log(row)// 提交给store里面actions 由于加入购物车的数据要同步到后台this.$store.dispatch('addCar',row)}},mounted () {this.initTable()}
};
</script>
<style>
#listBox {width: 900px;margin: 0 auto;
}
</stylecart.vue
<template><!-- 购物车 --><div id="carBox"><!-- 商品总数 --><h2 style="line-height:50px;font-size:16px;font-weight:bold">合计:总共{{count}}个商品,总价{{totalPrice}}元</h2><p v-if="count==0">空空如也!·······</p><div v-else><el-table :data="carData" border style="width: 100%"><el-table-column fixed prop="id" align="center" label="商品id"></el-table-column><el-table-column prop="title" align="center" label="商品标题"></el-table-column><el-table-column prop="price" align="center" label="商品价格"></el-table-column><el-table-column label="操作" align="center"><template slot-scope="scope"><el-button @click="reduceFun(scope.row)" type="text" size="small">-</el-button><span >{{scope.row.num}}</span><el-button @click="addCar(scope.row)" type="text" size="small">+</el-button><el-button @click="deleteFun(scope.row)" type="text" size="small">删除</el-button></template></el-table-column></el-table></div></div>
</template><script>
export default {name: "carBox",data() {return {};},computed: {//购物车列表carData() {return this.$store.state.carList;},//商品总数count() {return this.$store.getters.carCount;},//商品总价totalPrice() {return this.$store.getters.totalPrice;}},methods: {// 增加数量addCar(row){this.$store.dispatch('addCar',row)},// 减数量reduceFun(row){this.$store.dispatch('reducedCar',row)},// 删除deleteFun(row){this.$store.dispatch('deleteCar',row)}// 用户首次登录请求购物车的数据// initCar(){//   this.$store.dispatch('initCar')// }},created () {// this.initCar();},mounted() {}
};
</script><style>
#carBox {width: 900px;margin: 0 auto;
}
</style>

三、知识点记录

路由跳转的两种方式:

  • 声明式导航:router-link,可以进行路由的跳转<router-link to="/login">登录</router-link>
  • 编程式导航:利用组件实例的 $router.push | replace,可以进行路由跳转

编程式导航:声明式导航能做的,编程式导航都能;但是编程式导航除了可以进行路由跳转,还可以做一些其他的业务逻辑。

路由元信息:

将任意信息附加到路由上,如过渡名称、谁可以访问路由等。这些事情可以通过$route 的 meta属性 来实现,并且它可以在路由地址和导航守卫上都被访问到。

路由参数传递

params参数: 属于路径当中的一部分,需要注意,在配置路由的时候,需要占位

query参数: 不属于路径当中的一部分,类似于ajax中的queryString /home?k=v&kv=,不需要占位

路由传递参数(对象写法) path是否可以结合 params参数一起使用? 即:

this.$router.push({ path: '/search', params: { keyword: this.keyword }, query: { k: this.keyword.toUpperCase() }, });

答:报错,不能。

如何指定 params参数 可传可不传? 即:

this.$router.push({ name: "search", query: { k: this.keyword.toUpperCase() }, });

答:配置路由时,path上加个 ? 号,代表可传参数也可不传;若不加 ? ,则URL会出现问题。
params参数 可以传递也可以不传递,但是如果传递是空串,如何解决? 

可以使用 undefined 来解决params参数可以传递也可不传递(空的字符串)

路由组件能不能传递 props数据?

可以采用三种写法

 {path: "/search/:keyword",component: Search,meta: { show: true },// 对象形式路由传递参数name: "search",// 路由组件能不能传递 props数据?// 1、布尔值写法,但是这种方法只能传递params参数// props: true,// 2、对象写法:额外给路由组件传递一些props// props: { a: 1, b: 2 },// 函数写法(常用):可以params参数、query参数,通过props传递给路由组件props: ($route) => {return {keyword: $route.params.keyword, k: $route.query.k};}},

为什么进行axios 二次封装

为了请求拦截器、响应拦截器。

请求拦截器:在发请求之前可以处理一些业务;

响应拦截器:当服务器数据返回以后,可以处理一些事情。

// 对于axios进行二次封装
import axios from "axios"// 利用axios对象的方法create,去创建一个axios实例
// 这里的request 就是 axios,在这里配置一下
const request = axios.create({// 配置对象// 基础路径,发请求的时候,路径当中会默认有/api,不用自己写了baseURL: "/api",// 请求超时5stimeout: 5000,
})// 请求拦截器:在发请求之前,请求拦截器可以检测到,在请求发出之前做一些事情;
requests.interceptors.request.use((config) => {// config:配置对象,其有一个重要属性:header请求头})
// 响应拦截器:当服务器数据返回以后,可以处理一些事情。
requests.interceptors.response.use(((res) => {// 服务器响应成功的回调函数return res.data;
}, (error) => {// 服务器响应失败的回调函数return Promise.reject(new Error('faile'));
}))// 对外暴露
export default requests;

API接口统一管理

若项目很小,可以在组件的生命周期函数中发请求

但项目大,组件多,若有更改,将麻烦。所以API接口统一管理。比如跨域的代理可以统一管理

nprogress进度条的使用

在响应拦截器使用

// 请求拦截器:
requests.interceptors.request.use((config) => {// config:配置对象,其有一个重要属性:header请求头// 进度条开始动nprogress.start();return config;})
// 响应拦截器:
requests.interceptors.response.use((res) => {// 服务器响应成功的回调函数// 进度条结束nprogress.done();return res.data;
}, (err) => {// 服务器响应失败的回调函数return Promise.reject(new Error('faile'));
})

vuex 模块式开发

vuex 是官方提供的插件, 状态管理库,集中式管理项目中组件共用的数据 。

切记,并不是全部项目都需要 Vuex,如果项目很小,完全不需要Vuex,如果项目很大,组件很多、数据很多,数据维护很费劲,用Vuex

图片懒加载

// 引入图片懒加载插件
import VueLazeload from 'vue-lazyload';
// 引入懒加载默认图片(即真实图片没加载好之前,加载时显示的图片)
import tp from '@/assets/images/1.png';
// 注册插件
Vue.use(VueLazeload, {// 懒加载默认图片,(即真实图片没加载好之前,加载时显示的图片)loading: tp,
})<!-- v-lazy自定义指令图片懒加载 -->
<img v-lazy="good.defaultImg" />

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常用逻辑运算符

逻辑符号表格 逻辑符号含义描述&按位与将数字转成二进制计算&#xff0c;两个位都为1时&#xff0c;结果才为1|或两个位都为0时&#xff0c;结果才为0 &#xff0c;反知任何一个为1结果为1^异或两个位相同为0&#xff0c;不同为1<<左移整体二进位全部左移若干位&…

webrtc音视频通话(一)搭建turn服务器

全球定位&#xff1a;webrtc音视频通话&#xff08;一&#xff09;搭建turn服务器webrtc音视频通话&#xff08;二&#xff09;简单音视频通话webrtc音视频通话&#xff08;三&#xff09;整合websocket在学习webrtc之前呢&#xff0c;需要对websocket有一定基础&#xff0c;如…

腾讯云卖向“有币”区块链

曾经坚决“不涉币”的腾讯云将业务延伸向“有币区块链”。 在首届 Web3 全球峰会“腾讯云Web3构建日”上&#xff0c;腾讯云宣布进军Web3&#xff0c;并公开了与Ankr、Avalanche、Scroll和Sui 四个原生区块链项目的合作&#xff0c;其中前两个项目都发行了加密货币&#xff0c…

比特数据结构与算法(第四章_中_续②)堆解决Topk问题(最小的k个数)

TopK问题介绍&#xff1a;在N个数中找出最大/小的前K个 &#xff08;比如在1000个数中找出最大/小的前10个&#xff09;以前的方法&#xff1a;冒泡排序。时间复杂度&#xff1a; O(N^2)现在找最大的k个数的方法&#xff1a;方法1&#xff1a;堆排序降序&#xff0c;前N个就是最…

使用非对称加密(RSA) 实现前端加密后端解密

数据加密方式有&#xff1a; 单向加密、对称加密、非对称加密、加密盐、散列函数、数字签名。 1、单向加密 单向加密通过对数据进行摘要计算生成密文&#xff0c;密文不可逆推还原。只能加密&#xff0c;不能解密&#xff0c;常用于提取数据的指纹信息以此来验证数据的完整性…

JVM内存溢出与内存泄露

1. 什么是内存溢出? 当前创建的对象的大小大于可用的内存容量大小&#xff0c;发生内存溢出。2. 什么是内存泄露? 该回收的垃圾对象没有被回收&#xff0c;发生了内存泄露&#xff0c;垃圾对象越堆越多&#xff0c; 可用内存越来越少&#xff0c;若可用内存无法存放新的垃圾…

Tcpdump抓包验证zookeeper的心跳机制

一、背景 在分布式系统中&#xff0c;zookeeper可以作为服务注册中心&#xff0c;所有提供服务的节点都可以在zookeeper上面注册&#xff0c;并作为一个node被组织起来&#xff0c;如下图&#xff1a; 在RPC框架中&#xff0c;这些服务提供者就是RPC服务的提供者。zookeeper注…

185、【栈与队列】leetcode ——496. 下一个更大元素 I:单调栈-哈希表(C++版本)

题目描述 原题链接&#xff1a;496. 下一个更大元素 I 解题思路 本题与 739. 每日温度 的区别在于&#xff0c;需要先通过让nums1与nums2判定出为想等元素后&#xff0c;再去找nums2中更大的数。 因此&#xff0c;第一步需要找到想等数&#xff0c;第二步需要找到大于的数。…

c++之引用

目录 引用的概念 引用做函数参数 引用的本质 常引用 引用的概念 在c中新增加了引用的概念&#xff0c;引用可以看作一个已定义变量的别名。 引用的语法&#xff1a;Type &name var; int main() {int a 10;int &b a;printf("b%d\n", b);printf(&quo…

第四阶段02-酷鲨商城项目Mybatis相关的配置

14. 添加与Mybatis相关的配置 在每个项目中&#xff0c;当需要使用Mybatis实现数据库编程时&#xff0c;都需要添加2项一次性配置&#xff1a;配置Mapper接口所在的包&#xff08;package&#xff09;、配置XML文件在哪里。 关于配置Mapper接口所在的包&#xff0c;可以&…

【一】kubernetes集群部署

一、docker环境搭建 1、移除以前docker相关包 sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine2、配置yam源 sudo yum install -y yum-utilssudo yum-config-manager --ad…

C++进阶--二叉树编程题

文章目录力扣606. 根据二叉树创建字符串力扣102. 二叉树的层序遍历力扣236. 二叉树的最近公共祖先JZ36 二叉搜索树与双向链表力扣105--通过前序和中序遍历构造二叉树力扣144--二叉树的前序遍历&#xff08;非递归&#xff09;力扣94--二叉树的中序遍历&#xff08;非递归&#…

虹科新闻|虹科与iX systems正式建立合作伙伴关系

近日&#xff0c;虹科与美国iXsystems公司达成战略合作&#xff0c;虹科正式成为iXsystems公司在中国区域的认证授权代理商。未来&#xff0c;虹科将携手iXsystems&#xff0c;共同致力于提供企业级存储解决方案。虹科及iXsystems双方的高层领导人员都对彼此的合作有很大的信心…

操作系统基础教程

目录 第二章&#xff1a;处理器管理 概览 进程调度的层次 进程的调度方式&#xff1a; 调度的评价标准&#xff1a; 典型的调度算法&#xff1a; 第三章&#xff1a;同步、通信和死锁 什么是进程同步&#xff1f; 什么是进程互斥&#xff1f; 进程同步的实现方式 进程…

JVM总结

1. 内存结构 线程私有区 程序计算器 作用&#xff1a;是一块较小的内存空间&#xff0c;存储的是当前线程所执行的字节码文件的序号特点&#xff1a;线程私有&#xff0c;不会出现内存空间溢出 虚拟机栈 虚拟机栈是管理JAVA方法执行的内存模型&#xff0c;每个方法执行时都…

贴吧顶贴软件《今日/更新》

贴吧顶贴软件《今日/更新》百收贴吧工具箱&#xff0c;贴吧顶帖软件&#xff0c;贴吧推广引流神器#贴吧顶帖#贴吧推广 hello&#xff0c;大家好&#xff0c;我是软件的作者百收编辑狂潮老师。本次的视频讲解是作为一个百度顶贴的自动化脚本的视频安装教程和使用教程。你作为新…

SpringCloud(五)MQ消息队列

MQ概念常见消息模型helloworld案例实现实现spring AMQP发送消息实现spring AMQP接收消息工作消息队列实现发布订阅模型Fanout Exchange实现DirectExchange实现TopicExchange实现DirectExchange 和FanoutExchange的差异DirectExchange 和TopicExchange的差异基于RabbitListener注…

钉钉产品体验报告

一、调研的目的了解企业社交软件&#xff0c;借写竞品分析来帮助自己整理思路&#xff0c;看清市场的发展趋势&#xff1b;体验这类企业设计软件&#xff0c;掌握产品核心业务流程和产品结构&#xff0c;把握需求对应的功能点和界面结构&#xff0c;并侧面了解用户习惯&#xf…

用Python做数据分析有哪些优势?

众所周知&#xff0c;可以用作数据分析的语言有很多&#xff0c;包含Python、R语言等&#xff0c;而且Python被誉为数据分析的一大利器&#xff0c;更是该领域的首选语言&#xff0c;那么用Python做数据分析有哪些优势呢?跟着蛋糕往下看。 第一、Python语言自身的优势 Pytho…

ShardingSphere水平、垂直分库、分表和公共表

目录一、ShardingSphere简介二、ShardingSphere-分库分表1、垂直拆分&#xff08;1&#xff09;垂直分库&#xff08;2&#xff09;垂直分表2、水平拆分&#xff08;1&#xff09;水平分库&#xff08;2&#xff09;水平分表三、水平分库操作1、创建数据库和表2、配置分片的规则…