当前位置: 首页 > news >正文

【VUE2】综合练习——智慧商城

目录

0 前言

1 准备工作

1.1 vue-cli 脚手架 创建项目

1.2 调整目录结构

1.2.1 删除

1.2.2 修改 

1.2.3 新增

1.3 引入 vant 组件

1.3.1  按需导入

1.3.2 全部导入(略)

1.4 vw适配

1.5 路由配置(略)

2 登录页面

2.1 静态资源(略)

 2.2 request模块 - axios 封装

2.3 封装图片验证码 api (略)

2.4 toast 轻提示

2.5 短信验证倒计时(略)

2.6 封装登录 api(略)

2.7 响应拦截器统一处理错误提示(略)

2.8 将登录权证信息存入vuex及本地(略)

2.9 请求拦截器添加 loading 效果(略)

2.10 配置路由前置守卫

3 首页(略)

3.1 静态资源准备(略)

3.2 动态渲染(略)

4 搜索

4.1 静态布局准备(略)

4.2 历史记录-基本管理

 4.3 历史记录-持久化(略)

5 搜索列表(略)

5.1 静态布局(略)

5.2 动态渲染(略)

5.2.1 关键字搜索(略)

5.2.2 分类id搜索(略)

6 商品详情(略)

6.1 静态布局(略)

6.2 动态渲染介绍(略)(图片懒加载)

6.3 动态渲染评论(略)

7 加入购物车

7.1 唤起弹窗(略)

 7.2 封装数字框组件(略)

 7.3 判断token登录提示

 7.4 封装接口进行请求 

8 购物车

8.1 静态布局(略)

8.2 构建vuex模块(略)

8.3 渲染购物车列表

8.4 封装getters

8.5 全选与反选功能(略)

8.6 数字框修改数量

8.7 编辑切换状态(略)

8.8 删除功能(略)

8.9 空购物车处理(略)

9 订单结算台(略)

9.1 静态布局(略)

9.2 获取收货地址列表(略)

9.3 订单结算(略)

9.4 mixins复用

9.5 提交订单并支付(略)

10 订单管理(略)

10.1 静态布局(略)

10.2 点击tab切换渲染(略)

11 个人中心(略)

11.1 基本渲染(略)

11.2 退出功能(略)

12 项目打包优化

12.1 打包命令

12.2 配置publicPath

 12.3 路由懒加载


0 前言

接口文档:wiki - 智慧商城-实战项目

记录跟随黑马程序所做项目的重点步骤,简单复制粘贴步骤请见文档

为什么省略内容的标题要保留?为了看清整个项目的流程!

黑马程序员视频地址:104-项目演示-查看项目效果,明确功能模块

黑马文档:黑马文档.zip - 蓝奏云

注意:黑马文档中部分链接失效,在本文中可查找相应链接(若本文中链接也失效,请私信up!)


1 准备工作

1.1 vue-cli 脚手架 创建项目

见  【VUE2】第五期——VueCli创建项目

注意:本项目需要勾选下图模块


1.2 调整目录结构

1.2.1 删除

src/assets/logo.png
src/components/HelloWorld.vue
src/views/AboutView.vue
src/views/HomeView.vue

1.2.2 修改 

// router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)


const router = new VueRouter({
  routes: []
})

export default router
// app.vue
<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<style lang="less">
</style>

1.2.3 新增

src/api 目录:存储接口模块 (发送ajax请求接口的模块)
src/utils 目录:存储一些工具模块 (自己封装的方法)

新建 styles/common.less 重置默认样式

// 重置默认样式
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

// 文字溢出省略号
.text-ellipsis-2 {
  overflow: hidden;
  -webkit-line-clamp: 2;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-box-orient: vertical;
}

在main.js中引入

import '@/styles/common.less'

1.3 引入 vant 组件

文档:Vant 2 - 轻量、可靠的移动端组件库

其他组件库:

pc:

Element - 网站快速成型工具 | 一个 Vue 3 UI 框架 | Element Plus | iView / View Design 一套企业级 UI 组件库和前端解决方案 | Ant Design - 一套企业级 UI 设计语言和 React 组件库

移动:

Vant 4 | Mint UI (饿了么)| cube-ui(滴滴) 


1.3.1  按需导入

1.安装vant-ui

yarn add vant@latest-v2

2.安装一个插件

yarn add babel-plugin-import -D

3.在babel.config.js中配置

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [
    ['import', {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    }, 'vant']
  ]
}

 4.此时可以直接在main.js进行导入注册

但是:为了方便管理,新建utils/vant-ui.js,放入其中,再在main.js中导入

// utils/vant-ui.js
import { Button, Icon } from 'vant'

Vue.use(Button)
Vue.use(Icon)
// main.js 导入按需导入的配置文件
import '@/utils/vant-ui'

1.3.2 全部导入(略)

见黑马笔记或官方文档,此处不赘述,不推荐


1.4 vw适配

 文档:Vant 2 - 轻量、可靠的移动端组件库

vw适配在文档的进阶用法中 

 步骤:

1.安装 postcss-px-to-viewport 插件

yarn add postcss-px-to-viewport@1.1.1 -D

2.项目根目录, 新建postcss的配置文件postcss.config.js 

// postcss.config.js
module.exports = {
  plugins: {
    'postcss-px-to-viewport': {
      viewportWidth: 375,
    },
  },
};

viewportWidth:设计稿的视口宽度

vant-ui中的组件就是按照375的视口宽度设计的

恰好面经项目中的设计稿也是按照375的视口宽度设计的,所以此时我们只需要配置375就可以了

如果设计稿不是按照375而是按照750的宽度设计请见 Vue 项目引入Vant


1.5 路由配置(略)

见黑马文档 或 【VUE2】第四期——路由_vue路由传参query-CSDN博客


2 登录页面

2.1 静态资源(略)

见黑马文档


 2.2 request模块 - axios 封装

我们会使用 axios 来请求后端接口, 一般都会对 axios 进行一些配置 (比如: 配置基础地址,请求响应拦截器等等)

一般项目开发中, 都会对 axios 进行基本的二次封装, 单独封装到一个模块中, 便于使用

目的:为了配置不同的基地址、请求响应拦截器等 

步骤: 

1.安装axios

npm i axios

2.新建 utils/request.js 封装 axios 模块

利用 axios.create 创建一个自定义的 axios 来使用

文档:axios中文文档|axios中文网 | axios 

/* 封装axios用于发送请求 */
import axios from 'axios'

// 创建一个新的axios实例
const request = axios.create({
  baseURL: 'http://cba.itlike.com/public/index.php?s=/api/',
  timeout: 5000
})

// 添加请求拦截器
request.interceptors.request.use(function (config) {
  // 在发送请求之前做些什么
  return config
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error)
})

// 添加响应拦截器
request.interceptors.response.use(function (response) {
  // 对响应数据做点什么
  return response.data
}, function (error) {
  // 对响应错误做点什么
  return Promise.reject(error)
})

export default request

注意:在响应拦截器中分为成功与失败两个代码块区域,指的是是否能从服务器拿到数据,因此得到的response包含了响应状态,response.data是服务器响应的数据,而这个data数据中也包含了响应状态(服务器给的)和数据data


2.3 封装图片验证码 api (略)

见黑马文档

请求服务器数据api记得单独抽离出来放到api文件夹中


2.4 toast 轻提示

详情见文档:Vant 2 - 轻量、可靠的移动端组件库

1.导入调用 ( 组件内非组件中均可 )

import { Toast } from 'vant';
Toast('提示内容');

2.通过this直接调用 ( 组件内 )

//在utils/vant-ui.js中注册
import { Toast } from 'vant';
Vue.use(Toast)

//直接在vue组件中使用
this.$toast('提示内容')

2.5 短信验证倒计时(略)

见黑马文档

注意:页面销毁事件触发时,记得销毁定时器


2.6 封装登录 api(略)

见黑马文档 

记得封装单独函数结合正则表达式来判断输入内容是否正确,如:

// 校验输入框内容
validFn () {
  if (!/^1[3-9]\d{9}$/.test(this.mobile)) {
    this.$toast('请输入正确的手机号')
    return false
  }
  if (!/^\w{4}$/.test(this.picCode)) {
    this.$toast('请输入正确的图形验证码')
    return false
  }
  return true
}

正则表达式见:【JavaScript】APIs篇03——正则表达式-CSDN博客 


2.7 响应拦截器统一处理错误提示(略)

见黑马文档


2.8 将登录权证信息存入vuex及本地(略)

见黑马文档

记得将存入本地相关的代码封装为api,放在 utils/storage.js 中,便于调用与管理


2.9 请求拦截器添加 loading 效果(略)

文档:Vant 2 - 轻量、可靠的移动端组件库

注意toast的特性:单例


2.10 配置路由前置守卫

文档:导航守卫 | Vue Router

基础用法:

router.beforeEach((to, from, next) => {
  // 1. to   往哪里去, 到哪去的路由信息对象  
  // 2. from 从哪里来, 从哪来的路由信息对象
  // 3. next() 是否放行
  //    如果next()调用,就是放行
  //    next(路径) 拦截到某个路径页面
})

示例:(图来源:黑马笔记)

// 需要权限的页面
const authUrls = ['/myorder', '/pay']

router.beforeEach((to, from, next) => {
  const token = store.getters['user/getToken']
  // 不需要权限的页面直接放行
  if (!authUrls.includes(to.path)) {
    next()
    return // 执行完需要return,否则还会判断是否存在token
  }

  if (token) {
    // 如果token存在,直接放行
    next()
  } else {
    // 否则跳转到登录页面
    next('/login')
  }
})

3 首页(略)

3.1 静态资源准备(略)

见黑马文档


3.2 动态渲染(略)

见黑马文档


4 搜索

4.1 静态布局准备(略)

见黑马文档


4.2 历史记录-基本管理

注意:此处判断是否显示不能直接写history,因为在js中,空数组是真值 

<div class="search-history" v-if="history.length > 0">

<!--省略一万行代码-->

<script>
    data () {
      return {
        //...
        history: []
      }
    }
</script>

ai解释: 

其他见黑马文档,此处略 


 4.3 历史记录-持久化(略)

见黑马文档


5 搜索列表(略)

5.1 静态布局(略)

5.2 动态渲染(略)

5.2.1 关键字搜索(略)

5.2.2 分类id搜索(略)


6 商品详情(略)

6.1 静态布局(略)

见黑马文档


6.2 动态渲染介绍(略)(图片懒加载)

懒加载文档:Vant 2 - 轻量、可靠的移动端组件库


6.3 动态渲染评论(略)

评分文档:Vant 2 - 轻量、可靠的移动端组件库


7 加入购物车

7.1 唤起弹窗(略)

ActionSheet 动作面板文档:Vant 2 - 轻量、可靠的移动端组件库


 7.2 封装数字框组件(略)

步进器文档:Vant 2 - 轻量、可靠的移动端组件库

也可以像黑马那样自己封装个组件

如果自己封装记得判断用户输入的数据是否为整数

可以将type改为number来限制用户输入(但无法避免负数与零的情况,仍然需要判断)

<input @change="update($event)" class="inp" type="text" :value="value">
    update (e) {
      const num = +e.target.value
      if ((num % 1) !== 0 || num < 1) {
        e.target.value = this.value
        return
      }
      this.$emit('input', num)
    }

 7.3 判断token登录提示

1.注册dialog组件

import { Dialog } from 'vant'
Vue.use(Dialog)

2.按钮添加点击事件

<div class="btn" v-if="mode === 'cart'" @click="addCart">加入购物车</div>

3.添加 token 鉴权判断,跳转携带回跳地址

async addCart () {
  // 判断用户是否有登录
  if (!this.$store.getters.token) {
    this.$dialog.confirm({
      title: '温馨提示',
      message: '此时需要先登录才能继续操作哦',
      confirmButtonText: '去登录',
      cancelButtonText: '再逛逛'
    })
      .then(() => {
        this.$router.replace({
          path: '/login',
          query: {
            backUrl: this.$route.fullPath
          }
        })
      })
      .catch(() => {})
    return
  }
  console.log('进行加入购物车操作')
}

问题1:登录完成后跳转首页,而我想要跳回商品详情页

解决方案:向登录页面传参,再在登录时判断是否传参,传参则需跳转到参数对应页面

问题2:登录完跳回商品详情页,点击返回上一页又会跳回登录页而不是搜索列表

解决方案:将this.$router.push改为this.$router.replace

重点:这里要使用replace而不是push

区别:push是新增历史记录,replace是替换历史记录,点击上一页的区别不同

获取当前页面的完整路径:this.$route.fullPath

4.登录后,若有回跳地址,则回跳页面

// 判断是否有参数
this.$router.replace(this.$route.query.backUrl || '/')

 7.4 封装接口进行请求 

重点:请求拦截器中统一配置token

// 添加请求拦截器
instance.interceptors.request.use(function (config) {
  // 在发送请求之前做些什么
  //...
  const token = store.getters['user/getToken']
  if (token) {
    config.headers['Access-Token'] = token
    config.headers.platform = 'H5'
  }
  return config
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error)
})

其他请见黑马文档


8 购物车

8.1 静态布局(略)

8.2 构建vuex模块(略)

8.3 渲染购物车列表

记得判断是否存在token,从而选择是否显示购物车列表

  created () {
    if (this.token) {
      this.getCartList()
    } else {
      this.$router.replace({
        path: '/login',
        query: {
          backUrl: this.$route.fullPath
        }
      })
    }

  },
  computed: {
    token () {
      return this.$store.getters['user/getToken']
    }
  },

其他见黑马文档 


8.4 封装getters

这里新学了可以在getters中调用getters的方法

getters: {
  cartTotal (state) {
    return state.cartList.reduce((sum, item, index) => sum + item.goods_num, 0)
  },
  selCartList (state) {
    return state.cartList.filter(item => item.isChecked)
  },
  selCount (state, getters) {
    return getters.selCartList.reduce((sum, item, index) => sum + item.goods_num, 0)
  },
  selPrice (state, getters) {
    return getters.selCartList.reduce((sum, item, index) => {
      return sum + item.goods_num * item.goods.goods_price_min
    }, 0).toFixed(2)
  }
}

其他见黑马文档


8.5 全选与反选功能(略)

见黑马文档


8.6 数字框修改数量

传递除了子组件传过来以外的其他值的方法

@事件名称="形参1 => 函数(形参1, 其他参数1, 其他参数2)

这里的形参1就是子组件传递过来的值

用法示例: 

<CountBox :value="item.goods_num" @input="value => changeCount(value, item.goods_id, item.goods_sku_id)"></CountBox>

注意要先判断服务器是否能提交,再修改本地vuex,防止库存不足 

详细见黑马文档


8.7 编辑切换状态(略)

8.8 删除功能(略)

我在写调用接口时遇到一个bug:无论传几个值,都会把购物车清空,你们可以试一试,告诉我是不是我的问题 

8.9 空购物车处理(略)


9 订单结算台(略)

9.1 静态布局(略)

9.2 获取收货地址列表(略)

9.3 订单结算(略)

9.4 mixins复用

1.新建一个 mixin 文件   mixins/loginConfirm.js

export default {
    methods: {},
    data () {
        return {}
    },
    created () {}
}

注意:在此文件中可以使用vue中的data,methods等等属性,最后会合并到调用该文件的组件中,如果方法、属性冲突,则组件内的优先级更高

2.页面中导入,混入方法

import loginConfirm from '@/mixins/loginConfirm'

export default {
  name: 'ProDetail',
  mixins: [loginConfirm],
  ...
}

3.页面中即可直接使用 


9.5 提交订单并支付(略)


10 订单管理(略)

10.1 静态布局(略)

10.2 点击tab切换渲染(略)

使用tab组件


11 个人中心(略)

11.1 基本渲染(略)

11.2 退出功能(略)

清除token以及vuex中的数据

在user中提供相应方法,及在user中清除user以及cart中的数据,这就涉及到了调用全局vuex方法

示例:

methods: {
  logout () {
    this.$dialog.confirm({
      title: '温馨提示',
      message: '你确认要退出么?'
    })
      .then(() => {
        this.$store.dispatch('user/logout')
      })
      .catch(() => {

      })
  }
}

actions: {
  logout (context) {
    context.commit('setUserInfo', {})
    context.commit('cart/setCartList', [], { root: true })    //跨模块调用
  }
},

12 项目打包优化

12.1 打包命令

yarn build

在项目的根目录会自动创建一个文件夹dist,dist中的文件就是打包后的文件,只需要放到服务器中即可  


12.2 配置publicPath

// vue.config.js
module.exports = {
  // 设置获取.js,.css文件时,是以相对地址为基准的。
  // https://cli.vuejs.org/zh/config/#publicpath
  publicPath: './'
}

 12.3 路由懒加载

路由懒加载 & 异步组件, 不会一上来就将所有的组件都加载,而是访问到对应的路由了,才加载解析这个路由对应的所有组件

文档:路由懒加载 | Vue Router

const ProDetail = () => import('@/views/prodetail')
const Pay = () => import('@/views/pay')
const MyOrder = () => import('@/views/myorder')

快捷键:

Alt+Shift+单击起始行 :快速选中多行

Ctrl+右箭头:光标会直接跳到下一个单词的结尾

相关文章:

  • visio导出pdf公式变形
  • Embedding原理
  • zk基础—1.一致性原理和算法一
  • 《算法:递归+记忆化搜索》
  • 【计算机视觉】OpenCV实战项目- 抖音动态小表情
  • ESP32移植Openharmony外设篇(11) mfrc522射频读卡器
  • 数据处理与机器学习入门
  • MyBatisPlus不等于如何使用
  • qml 中的anchors
  • dfs复习
  • 内核自旋锁
  • 从0到1:Rust 如何用 FFmpeg 和 OpenGL 打造硬核视频特效
  • 如何使用分块策略生成高覆盖率测试用例:需求文档与接口文档的最佳实践
  • 力扣125.验证回文串
  • 标题:Linux系统文件句柄优化全攻略:彻底解决“Too Many Open Files”错误
  • 【算法竞赛】动态规划+记忆化搜索(作物杂交问题)
  • 31天Python入门——第18天:面向对象三大特性·封装继承多态
  • nacos 2.x使用java语言实现自定义Loadbalance
  • 了解可观察性指标:类型、黄金信号和最佳实践
  • SpringBoot框架—classpath、Bean、容器的概念
  • 做医学网站/搜索引擎优化方法与技巧
  • 网站访问量大 处理/品牌营销与推广
  • 如何做网站赌博的教程/公司宣传网站制作
  • 做网站便宜/收录情况
  • 外管局网站做延期收汇报告/百度推广代理
  • 在网站做博客/网站统计分析工具的主要功能