尚品汇前台项目总结

news2024/11/17 11:47:25

这是我的第一篇个人博客,主要是对我学习前端过程中的一些主记录。由于我在江苏,从2022年过完年,一直到年中,疫情反反复复,又正是大三,马上面临就业难题,我选择了前端。

    从html,css,js基础,webAPI,js进阶,ES6,ajax,node.js一直到最近刚学完尚硅谷的vue2+vue3的全家桶,近期也是刚做完一个尚品汇的项目,作为我第一次做一个相对完整的项目。尚品汇项目是一个电商项目,可以登陆注册账号,搜索查找,产品详情,放大镜,购买商品,加入购物车,下单,提交订单以及支付等模块。用vue-router控制路由的跳转,vuex对仓库中资源进行统一管理,用swiper展示轮播图,element-UI做弹出框,三级联动对分类进行路由跳转,路由之间的转参query和params,还有选中分类或者搜索都会有面包屑处理,综合与价格的排序,手写的分页器作为全局组件,在搜索页面与我的订单中使用,还有在未登录时与登录时的路由守卫判断,个人中心二级路由展示,图片懒加载,用vee-validate插件进行表单验证,路由懒加载。

    这个项目类似的界面,其实没有什么特色,做为培训机构给我们白嫖的练手项目也是非常不错的。在这个项目中,对vue2的使用,还有一些功能实现的原理,以后业务逻辑的实现,是不做项目不打代码练不出来的。在这个过程过我也遇到了非常多的困难,但是这项目比较得普遍,还有跟着老师来的,以及通过百度,很多debug也就相对比较容易一些,只不过还是有困扰的点,我会在之后的博客中详细介绍。

    在做完这个项目之后,我也算是对这阶段的学习告一段落了,在做完这个项目最后,我通过阿里云的学生活动,成功领到了一台服务器,看B站鱼皮大佬的教程部署了wordpress创建了一个很简易的个人博客。还有很多不足希望大佬可以提出来,感谢大佬可以给我的学习过程中提供帮助,我会继续学习,继续更新博客的。

本人博客: 孙浩的个人博客 – 前端学习之路

下面是具体细节问题:

三级联动路由传参:

三级联动

1、先把点击对象拿到,再解构出来(categoryname,categord1id,categord2id,categord3id)自定义属性
2、外层判断categoryname,有则为a链接,内层再判断是哪一级
3、准备好要给真正query参数的对象
let query = {categoryName:categoryname}//表示要查找的是哪个分类
3、判断原本这个有无params参数(可能搜索框有),把要跳转的对象给给真正的

if (this.$route.params) {//有
        location.params = this.$route.params;
        location.query = query;
        this.$router.push(location);
}

但是在跳转路由的时候,若是搜索框里面是空串就会出bug,(外加可能没有点分类,直接搜索)解决:

if (this.$route.query) {
        let loction = {
          name: "search",
          params: { keyword: this.keyword || undefined },//没有则是undefined
        };
        loction.query = this.$route.query;
        this.$router.push(loction);
}


浏览器报错,因为在push的时候是要返回一个promise的所以为了一劳永逸要重写push和replace方法。(当然不写也行,就是飘红)

let originPush = VueRouter.prototype.push;
VueRouter.prototype.push = function (location, resolve, reject) {
    if (resolve && reject) {
        //当传了成功与失败的回调时
        originPush.call(this, location, resolve, reject)
    } else {
        originPush.call(this, location, () => { }, () => { })//没有传的话就返回两个 空对象
    }
}

ngrogress,让请求的时候显示进度条

//请求拦截器:在发请求之前,请求拦截器可以检测到请请发之前做的一些事
requests.interceptors.request.use((config) => {
    //config:配置对象,里面有请求头
    //发请求前进度条开始
    nProgress.start()
    return config
})

//响应拦截器
requests.interceptors.response.use((res) => {
    //成功的回调:服务器响应数据回来以后,响应拦截器可以检测到
    //响应成功进度条结束
    nProgress.done()
    return res.data;
}, (err) => {
    return Promise.reject(new Error('faile'));
})

防抖和节流


防抖:在连续快速触发的时候,后面的会重复计时。
节流:在一定范围内重复快速触发,只有一次生效。
用lodash插件实现

mock插件的使用

因为后端没有主页下面的数据,所以我们还像调用接口一样,只不过请求会拦截,从而调用本地资源

src下新建文件夹,放mock中数据,还有模拟写的接口
//先引入mockjs模块
import mockjs from "mockjs";//把JSON数据格式引入进来
// webpack默认对外暴露:图片,JSON
import banner from "./banner.json"
import floor from "./floor.json"//mock数据:第一个参数为请求地址,第二个参数为请求数据
mockjs.mock("/mock/banner", { code: 200, data: banner })
mockjs.mock("/mock/floor", { code: 200, data: floor })
在api文件夹中再新建,再创建一个axios实例,发送请求
const requests = axios.create({
  baseURL: "/mock",//基础路径,发请求时路径会自动出现/api
  timeout: 5000,//代表请求超时时间
})


面包屑

面包屑


面包屑来源有3种:三级联动分类,搜索框,searchSelector子组件中的分类
前两种都只要把相应的categoryName变为undefined,再重新发送请求即可,搜索框多一步,要把input里清空,但搜索框不在同一个组件,所以就要用到兄弟间传参,选用$bus,再第三种,又分售卖的品牌和属性,只要把数据改了,再发一遍请求即可
排序(综合与价格)
先定义两个变量获取最开始是综合还是价格,升序还是降序。再定义一个新的用于再发请求,若点的是当前的元素,再排序反转,若点的是另一个,则默认为降序,然后把数据更新再发请求。

changeOrder(flag) {
      //1为综合,2为价格
      let originFlag = this.searchParams.order.split(":")[0]; //最开始是综合还是价格
      let originSort = this.searchParams.order.split(":")[1]; //最开始的升序还是降序
      let newOrder = "";
      //点的是当前的元素,再就是排序反转
      if (flag === originFlag) {
        newOrder = `${originFlag}:${originSort == "desc" ? "asc" : "desc"}`;
      } else {
        //点的不是当前元素,再转到目标元素且,默认desc降序
        newOrder = `${flag}:${"desc"}`;
      }
      //将新的order赋给searchParams并再次发请求
      this.searchParams.order = newOrder;
      this.getData();
},

分页器

分页器


点哪个把哪一页的编号,更新数据再发请求
重点是手写分页器
分3个部分
第一部分是:1和……
第二部分是:连续的页码
第三部分是:……和最后一页的编号
由于后端没有直接返回多少页,所以要计算。
主要是第二部分,中间的连续页。

分页器特殊情况,在前5后5之内,连续页为5(连续的页数可以自定义)

startNumAndEndNum() {
      //先定义两个变量存储起始数字和结束数字
      let start = 0,
        end = 0;
      //连续的页码至少要有5页
      //不正常现象(总页数没有连续的页码多)
      if (this.continues > this.totalPage) {
        start = 1;
        end = this.totalPage;
      } else {
        start = this.pageNo - parseInt(this.continues / 2);
        end = this.pageNo + parseInt(this.continues / 2);
        //若是算出来start可能会少于1
        if (start < 1) {
          start = 1;
          end = this.continues;
        }
        //若end大于了最大页数
        if (end > this.totalPage) {
          end = this.totalPage;
          start = this.totalPage - this.continues + 1;
        }
      }
      return { start, end };
},


返回一个对象,限定了连续的开始和结束(eg:若连续页为5,当前页为6,再连续页为4,5,6,7,8)对称
但要是算出来开始小于了1再把开始限定为1,算出来结束大于了最大页,再把结束限定为最大页,且开始再变为了最大页-连续页+1
点击进入详情页路由时,会默认到最底部,解决:
在配置路由的时候加scrollBehavior配置项

let router = new VueRouter({
    routes,
    //让路由跳转后,自动滚轮在最上方
    scrollBehavior() {
        return { y: 0 }
    }
})


放大镜

放大镜


放大镜效果本来在pink老师就练过一次,这里再练一次,且单独拿出来做为子组件。
首先绑定一个鼠标悬浮事件,出现一个遮罩层加一个大图,但是这个大图的显示出的大小还是一样的,只不过放大了2倍,然后就是移动的时候对应同时移动了
用$refs获取DOM,第一让遮罩层跟着鼠标移动,第二相对应放大层的背景图也要移动,但是鼠标向右移时,背景图是向左移2倍,第三约束遮罩层的范围

handler(e) {
      let mask = this.$refs.mask; //获取遮罩层DOM
      let big = this.$refs.big; //获取放大层DOM
      //获取遮罩层左上角的坐标:鼠标的坐标-0.5*遮罩层冠宽或高
      let left = e.offsetX - mask.offsetWidth / 2;
      let top = e.offsetY - mask.offsetHeight / 2;

      // 约束遮罩层的范围
      if (left <= 0) {
        left = 0;
      } else if (left >= mask.offsetWidth) {
        left = mask.offsetWidth;
      }
      if (top <= 0) {
        top = 0;
      } else if (top >= mask.offsetHeight) {
        top = mask.offsetHeight;
      }

      mask.style.left = left + "px";
      mask.style.top = top + "px";
      big.style.left = -2 * left + "px";
      big.style.top = -2 * top + "px";
},

uuid(之前禹哥教过用这个的轻量版nanoid)


因为要进购物车,但是未登录的话,后端是不会返回数据的,所以要用uuid生成一个token
新建一个utils,再建一个js文件,判断是还本地已经有了,没有就生成,存在本地存储的同时还要把数据返回
这里把两个方法再单独放一个模块,作为对浏览器中本地存储的操作

import { v4 as uuidv4 } from 'uuid'
export const getUUID = () => {
    //先从本地获取uuid是否有
    let uuid_token = localStorage.getItem('UUIDTOKEN')
    //如果没有
    if (!uuid_token) {
        //生成游客临时身份
        uuid_token = uuidv4();
        localStorage.setItem('UUIDTOKEN', uuid_token)
    }

    //返回id,没有return 再返回的是undefined
    return uuid_token;
}

购物车中全选


全选分两部分:第一部分是点击全选复选框,让所有的都选上,只需要把数据中的isChecked属性都变为1即可

async updataAllCartChecked(e) {
      try {
        let isChecked = e.target.checked ? "1" : "0";
        this.isAllChecked = e.target.checked;
        await this.$store.dispatch("updataAllCartIsChecked", isChecked);
        this.getData();
      } catch (error) {
        alert(error.message);
      }
    },


第二部分是当点击其余小项时判断,若当时状态全部的小项全勾上的时候,则把全选给勾上

let flag = true;
    //遍历的是数组所以直接用in的话,v就是键名,数组键名为索引
    //遍历判断若全是勾选状态再把全选也勾上
    for (let v of this.cartInfoList) {
      if (!v.isChecked) {
        flag = false;
      }
    }
    this.isAllChecked = flag;
    this.getData();
  } catch (error) {
    alert(error.message);
  }
},

导航守卫


因为商城项目是要有用户,然后访问对应购物车等每个用户私有的数据的,所以在登录或未登录的时候不能跳转到一些特定的路由去,所以就要用到路由导航守卫了。
当用户未登录:
要是去订单,支付,订单详情页面都把路由跳转到登录页面,为了登录之后可以直接访问原本要去的路由,则可以用params参数转到登录页方便跳转。
当用户登录了:
要去登录或者注册页,是不行的,直接去往主页(其实这个需求可以不要)
还有就是因为token是存在浏览器本地的,而name是存在仓库的,所以要判断有token但是没有用户名,有就放行,没有则再获取一下用户信息,但这里要判断一下成功与失败,若是失败的话再要跳转到登录界面,因为你即便有token,但是长时间不登录,后端的数据会更新,从而token会失效

大概如下图,来自CSDN的@毛毛虫鸣鸣

个人中心(二级路由,路由懒加载,路由重定位)

{
        name: 'center',
        path: '/center',
        component: () => import('@/pages/Center'),//路由懒加载
        children: [
            {
                path: 'myorder',
                component: () => import('@/pages/Center/myOrder')
            }, {
                path: 'grouporder',
                component: () => import('@/pages/Center/groupOrder')
            }, , {
                path: '',//当路径默认的时候(完全的路径的/center/)
                redirect: '/center/myorder'//重定向到myorder路由
            }
        ]
    },

想要去支付页面,一定要从订单来才行,所以要用独享路由守卫

{
        name: 'pay',
        path: '/pay',
        component: () => import('@/pages/Pay'),
        beforeEnter: (to, from, next) => {
            //只有是从trade订单来的才能进入pay支付路由
            if (from.path == '/trade') {
                next()
            } else {
                next(false)
            }
        }
},

使用图片懒加载(用vue-lazyload插件)

图片懒加载

//引入插件(图片懒加载)
import VueLazyload from 'vue-lazyload'
//引入懒加载的图片
import loadimage from '@/assets/images/111.jpg'
//注册图片懒加载插件
Vue.use(VueLazyload, {
  loading: loadimage,
})

使用plugins表单验证插件(其实用element-UI也行)

eg:手机号 :

<div class="content">
        <label>手机号:</label>
        <input
          placeholder="请输入你的手机号"
          v-model="phone"
          name="phone"
          v-validate="{ required: true, regex: /^1\d{10}$/ }"        //以1开始,后面10个数字
          :class="{ invalid: errors.has('phone') }"                         //否则提示
        />
        <span class="error-msg">{{ errors.first("phone") }}</span>
</div>

为了方便也是全局引入

import "@/plugins/validate"

再新建一个文件使用插件

//vee-validate插件:表单验证区域
import Vue from 'vue'
import VeeValidate from 'vee-validate';
//中文提示
import zh_CN from "vee-validate/dist/locale/zh_CN"
//使用注册
Vue.use(VeeValidate)

//表单验证
VeeValidate.Validator.localize("zh_CN", {
    messages: {
        ...zh_CN.messages,
        is: (field) => `${field}必须与密码相同`,//修改内置规则的message,让确认密码与密码相同

    },
    attributes: {
        phone: "手机号",
        code: "验证码",
        password: "密码",
        password1: "确认密码",
        agree: "协议"
    }
})

//自定义校验规则,必须要打勾才行
VeeValidate.Validator.extend("tongyi", {
    validate: (value) => {
        return value
    },
    getMessage: (field) => field + "必须同意"
})

大概的项目就是这样了,项目配置,因为现在默认是vue3了,所以像脚手架一定要安装对应的版本,最新本是不能向下兼容的。还有不是所有路由中,footer组件都要显示的所以要加一个属性,来判断是否显示,路由中不能直接绑定自定义属性所以要在meta配置项下定义一个show来判断。还有就是因为要解决跨域问题,这次项目通过代理的方法解决,在vue.confing.js中加入

devServer: {
    proxy: {
      '/api': {
        target: 'http://gmall-h5-api.atguigu.cn',//访问的接口地址
      }
    }
}



    还有因为要请求,所以就要涉及到异步,就要用到async与await配合使用,若要判断成功还是失败,还要用到try……catch()
再一个问题就是在切换组件的时候,因为三级联动组件不仅在home路由中使用,在别的也要,所以要注册为全局组件,还有就是切换的时候会销毁组件,但是在一些路由中要用到,为了不重复得请求接口,只发一次请求,就把请求放在App.vue中mounted中(对仓库的操作)

    整个项目完全,差不多不到两周的时间,其中学到了很多东西,编程还是要打代码才可以,很多问题就是在实践中发现的,所以我打算再做一个后台项目,加深对vue2的使用,之后再学小程序,再深入原码。不得不说因为这个项目是培训机构上的课,不是专门拿出来当做网上的白嫖福利,所以开发周期太长了,不过好在非常得细。

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

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

相关文章

15个awk的经典实战案例

目录 一、插入几个新字段 二、格式化个空白 三、筛选IPV4地址 命令及结果 第一种查询方式 第二种查询方式 第三种查询方式 四、读取.ini配置文件中的某段 命令及结果 第一种查询方式 第二种查询方式 五、根据某字段去重 命令及结果 第一种方式 第二种方式 六、…

你是这样的 CSS,19个唯美的边框

作者&#xff1a;niemvuilaptrin 译者&#xff1a;前端小智 来源&#xff1a;medium 有梦想&#xff0c;有干货&#xff0c;微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。 本文 GitHub https://github.com/qq449245884/xiaozhi 已收录&#xff0c;有一线大厂面试完整…

Vue之插槽

1. 插槽是什么 插槽就是子组件中的提供给父组件使用的一个占位符&#xff0c;用 表示&#xff0c;父组件可以在这个占位符中填充任何模板代码&#xff0c;如 HTML、组件等&#xff0c;填充的内容会替换子组件的标签。简单理解就是子组件中留下个“坑”&#xff0c;父组件可以使…

STM32入门教程课程简介(B站江科大自化协学习记录)

课程简介 STM32最小系统板面包板硬件平台 硬件设备 STM32面包板入门套件 Windows电脑 万用表、示波器、镊子、剪刀等 软件介绍 Keil MDK 5.24.1 是一款嵌入式软件开发工具&#xff0c;它提供了一个完整的开发环境&#xff0c;包括编译器、调试器和仿真器。它支持各种微控制…

微信小程序富文本解析器rich-text、web-view、wxParse、mp-html、towxml对比

微信小程序解析富文本html大概有几种方式&#xff0c;我用过的有这三种rich-text、web-view、wxParse、mp-html&#xff0c;各有各的优缺点&#xff0c;接下来聊一聊。 一、rich-text 二、web-view 三、wxParse 四、mp-html 五、towxml 一、rich-text rich-text富文本组件…

XSS漏洞攻防

目录XSS攻击简介XSS攻击的危害XSS攻击分类XSS产生原因实战靶场搭建构造xss攻击脚本弹窗警告页面嵌套页面重定向弹窗警告并重定向图片标签利用绕开过滤的脚本存储型xss基本演示访问恶意代码&#xff08;网站种马&#xff09;XSS获取键盘记录XSS盲打htmlspecialchars()函数自动xs…

SpringBoot - ZooKeeper

SpringBoot - ZooKeeper1、Curator框架的集成2、构建zookeeper客户端3、Master选举3.1、LeaderSelector3.2、LeaderLatch4、成员组注册5、节点监听1、Curator框架的集成 <dependency><groupId>org.apache.curator</groupId><artifactId>curator-recip…

博客系统前端实现

目录 1.预期效果 2.实现博客列表页 3.实现博客正文页 4.实现博客登录页 5.实现博客编辑页面 1.预期效果 对前端html,css,js有大致的了解后,现在我们实现了一个博客系统的前端页面.一共分为四个页面没分别是:登陆页面,博客列表页,博客正文页,博客编辑页 我们看下四个界面…

功能:vue:浏览器打印小票、打印参数配置

一、需求说明 1、要实现点击打印小票按钮&#xff0c;弹出预览弹框&#xff0c;点击弹框里面的打印&#xff0c;则实现浏览器打印预览&#xff0c;以及浏览器打印。 2、根据对应需求可以做步骤的加减&#xff0c;本例多了一个本地预览。 3、环境&#xff1a;pc端打印、chrome浏…

在 TypeScript 中导入 JavaScript 包,解决声明文件报错问题

前言 如果你在 TypeScript 中引入了一个纯 JavaScript 包&#xff0c;那很有可能会看到这样的报错&#xff1a; Could not find a declaration file for module ‘koumoul/vjsf/lib/VJsf’. ‘c:/*/node_modules/koumoul/vjsf/lib/VJsf.js’ implicitly has an ‘any’ type. …

uniapp拍照+上传后台 + pc端上传后台

uniapp 一、拍照&#xff0c;拿到本地路径 首先调用uniapp的api实现拍照 uni.chooseImage({sourceType: [camera,album],//拍照或是打开系统相册选择照片count: 3, //最多三张success(res) {if (Array.isArray(res.tempFilePaths)) {//最多选择三张&#xff0c;如果多选删掉…

新安webpack插件后编译报错compiler.plugin is not a function

安装使用generate-asset-webpack-plugin时报错TypeError&#xff1a;compiler.plugin is not a function&#xff0c;网上搜索了一下大概就是webpack5与这些插件不匹配。推荐的方法几乎都是换一个适配的插件版本&#xff0c;但我所需要的这个插件在npm上最近更新时间是7年前&am…

Vue 之 插件 轮播组件 vue-awesome-swiper 的简单使用整理

Vue 之 插件 轮播组件 vue-awesome-swiper 的简单使用整理 目录 Vue 之 插件 轮播组件 vue-awesome-swiper 的简单使用整理 一、简单介绍 二、安装 vue-awesome-swiper 三、引入&#xff08;全局或局部引入&#xff09; 四、简单使用 一、简单介绍 Vue 开发的一些知识整理…

八个步骤实现一个Web项目(在线聊天室)

实现一个在线网页的聊天室 Hello&#xff0c;今天给大家带来的是我的一个Web项目的开发过程的相关步骤&#xff0c;这个项目实现的功能是一个Web在线聊天室&#xff0c;简单的来说就是实现在网页版的聊天框&#xff0c;能够实现对于用户信息进行注册&#xff0c;登录&#xff…

vue3、ts如何封装 axios,使用mock.js

今天我们一起来看一看 vue3ts如何优雅的封装axios&#xff0c;并结合 mock.js 实现敏捷开发&#xff1b; 但是我们要注意区分 Axios 和 Ajax &#xff1a; Ajax 是一种技术统称&#xff0c;技术内容包括&#xff1a;HTML 或 XHTML, CSS, JavaScript, DOM, XML, XSLT, 以及最重要…

Vue首次加载太慢之性能优化

Vue首次加载太慢之性能优化前言一、防止编译文件中出现map文件二、vue-router 路由懒加载三、使用gzip压缩四、使用CDN加载第三方库第一步&#xff1a;引入资源第二步&#xff1a;添加配置第三步&#xff1a;去掉原有的引用五、去掉代码中的console.log前言 首页加载很慢的问题…

Vite4 + Vue3 + vue-router4 动态路由

动态路由&#xff0c;基本上每一个项目都能接触到这个东西&#xff0c;通俗一点就是我们的菜单是根据后端接口返回的数据进行动态生成的。表面上是对菜单的一个展现处理&#xff0c;其实内部就是对router的一个数据处理。当然你只对菜单做处理也是可以的&#xff0c;但是没有任…

js中的内存泄漏

简版 内存泄漏一般是指变量的内存没有及时的回收&#xff0c;导致内存资源浪费。一般有三种情况出现内存泄露比较多。&#xff08;1&#xff09;常见的声明了一个全局变量&#xff0c;但是又没有用上&#xff0c;那么就有点浪费内存了&#xff0c;&#xff08;2&#xff09;定…

【Vue3】用Element Plus实现列表界面

&#x1f3c6;今日学习目标&#xff1a;用Element Plus实现列表界面 &#x1f603;创作者&#xff1a;颜颜yan_ ✨个人格言&#xff1a;生如芥子&#xff0c;心藏须弥 ⏰本期期数&#xff1a;第四期 &#x1f389;专栏系列&#xff1a;Vue3 文章目录前言效果图目录简介修改vite…

uniapp微信小程序实现连接低功耗蓝牙打印功能

微信小程序项目中有使用到蓝牙连接打印&#xff0c;参考官方文档做了一个参考笔记&#xff0c;这样使用的时候就按着步骤查看。 uni-app蓝牙连接 蓝牙&#xff1a; 1、初始化蓝牙 uni.openBluetoothAdapter(OBJECT) uni.openBluetoothAdapter({success(res) {console.log(…