Vue(尚品汇)第一天

Vue(猴品汇)

  • 一、准备工作
  • 二、项目配置
    • 2.1关闭vue语法检测
    • 2.2脚手架使用介绍
    • 2.3项目跑起来自动打开浏览器
  • 三、OneDay
    • 3.1准备相关依赖
    • 3.2配置路由
    • 3.3路由push传参
    • 3.4页面重定向当前路径抛出异常
    • 3.5注册全局组件
  • 四、TwoDay
    • 4.1二次封装axios
    • 4.2api接口统一管理
    • 4.3nprogress进度条
    • 4.4 vuex的基本使用
    • 4.5三级联动获取数据
    • 4.6三级联动渲染数据
    • 4.7函数防抖和节流(节流是CD,防抖是回城)
  • 五、ThreeDay
    • 5.1路由跳转以及传参
    • 5.2search页面的typeNav显示隐藏
    • 5.3合并参数
    • 5.4mock模拟数据
    • 5.5获取Banner轮播图数据
    • 5.6Banner轮播图完善
    • 5.7获取Floor数据
    • 5.8Floor数据动态渲染
  • 六、FourDay
    • 6.1公用组件Carsoule
    • 6.2Search模块获取数据
    • 6.3完善search搜索功能
    • 6.4处理面包屑(有bug的版本)
    • 6.5处理面包屑(无bug的版本)
    • 6.6点击品牌查询数据
    • 6.7根据goods属性信息查询
  • 七、FiveDay
    • 7.1排序操作
    • 7.2分页器
    • 7.3商品详情
    • 7.4购物车操作
  • 八、登录注册
    • 8.1注册功能
    • 8.2登录功能
    • 8.3退出登录
    • 8.4全局前置路由守卫
    • 8.5用户地址信息展示
    • 8.6提交订单功能
    • 8.7实现支付功能
    • 8.8订单详情

一、准备工作

配置淘宝镜像源为了提高下载速度

npm config set registry https://registry.npm.taobao.org

安装vue-cli脚手架

npm install -g vue-cli

正式创建一个vue2的项目

vue create 项目名

二、项目配置

2.1关闭vue语法检测

为避免一些奇怪的错误
Vue(尚品汇)第一天_第1张图片

2.2脚手架使用介绍

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

2.3项目跑起来自动打开浏览器

Vue(尚品汇)第一天_第2张图片

三、OneDay

3.1准备相关依赖

下载安装6版本less

npm install less less-loader@6

安装完成只需要在style标签加上lang=“less”属性即可识别less文件

安装router模块

npm install vue-router@3

3.2配置路由

Vue(尚品汇)第一天_第3张图片

3.3路由push传参

Vue(尚品汇)第一天_第4张图片
小总结

params参数:路由需要占位,程序就崩了,属于URL当中一部分
query参数:路由不需要占位,写法类似于ajax当中query参数

3.4页面重定向当前路径抛出异常


解决问题就是重写路由的跳转方法(个人感觉就是抛出异常没处理,然后让这个报错消失)

//先拷贝一份VueRouter原型上的push方法
let originPush = VueRouter.prototype.push;
//重写push|replace
//第一个参数:告诉原来的push方法,往哪里调准(传递什么参数)
VueRouter.prototype.push = function(location,resolve,reject){
    if(resolve && reject){   //如果成功和失败的回调函数传了
        //篡改函数的上下文 ,保证了这里的this指向还是VueRouter类的实例,不改这里指向window,
        originPush.call(this,location,resolve,reject);
    }else{
        originPush.call(this,location,() => {},() => {})
    }
}

3.5注册全局组件

Vue(尚品汇)第一天_第5张图片

四、TwoDay

4.1二次封装axios

安装axios

npm install axios

//对于axios进行二次封装
import axios from "axios";

//axios.create方法执行,其实返回一个axios和request一样的
let requests = axios.create({
    //基础路径,发请求URL携带api【发现:真实服务器接口都携带/api】
    baseURL: "/api",
    //超时的设置
    timeout: 5000
});

//请求拦截器:将来项目中【N个请求】,只要发请求,会触发请求拦截器!!!
requests.interceptors.request.use(config => {
    //请求拦截器:请求头【header】,请求头能否给服务器携带参数
    //请求拦截器:其实项目中还有一个重要的作用,给服务器携带请求们的公共的参数
    return config;
});

//响应拦截器:请求数据返回会执行
requests.interceptors.response.use((res) => {
    //res:实质就是项目中发请求、服务器返回的数据
    return res.data;
}, (error) => {
    return Promise.reject(new Error("faile"));
});

export default requests;

4.2api接口统一管理

统一管理模块代码

//统一管理项目前部的接口
import requests from "./requests";
//封装函数:复用
//将来这个函数可以在别的地方使用,需要对外暴露【分别暴露】
//获取商品分类的数据
export const reqCategoryList = () => {
   //箭头函数可以在程序任意地方使用,箭头函数返回即为服务器的数据
   //下面箭头函数返回值:返回的是什么? promise,即为返回服务器的数据
   //return关键字,千万别忘记书写,如果忘记书写,你在任意地方获取的都是undeinfed
   return requests({url: '/product/getBaseCategoryList', method: 'get', });
}

通过代理解决跨域 在vue.config.js中添加

//配置代理跨域
  devServer: {
    proxy: {
      "/api": {
        target: "http://gmall-h5-api.atguigu.cn",
      },
    },
  },

在mainjs中测试一下接口
Vue(尚品汇)第一天_第6张图片
请求成功
Vue(尚品汇)第一天_第7张图片

4.3nprogress进度条

安装

npm install nprogress

在请求拦截器和响应拦截器中应用
Vue(尚品汇)第一天_第8张图片

效果:
请添加图片描述

4.4 vuex的基本使用

安装3.6.2版本的vuex

npm install [email protected]

vuex的基本配置在src中的store的目录下
Vue(尚品汇)第一天_第9张图片
配置完成后在入口文件进行引入和注册
Vue(尚品汇)第一天_第10张图片
先在仓库中准备数据,再到Home组件中进行一个引入和计算属性挂载,vue的开发工具中绑定上数据即为成功

Vue(尚品汇)第一天_第11张图片

4.5三级联动获取数据

先对home仓库进行模块化
Vue(尚品汇)第一天_第12张图片
因为是axios发出的请求返回是一个promise对象我们需要使用ansyc和await函数来处理
Vue(尚品汇)第一天_第13张图片
在三级联动模块挂载发出请求
Vue(尚品汇)第一天_第14张图片
页面加载完成成功拿到数据
Vue(尚品汇)第一天_第15张图片

4.6三级联动渲染数据

对获取到的数据进行处理 home仓库的代码
Vue(尚品汇)第一天_第16张图片
借助辅助函数mapState从仓库中获取数据 并且保存到到本地的categoryList
Vue(尚品汇)第一天_第17张图片
前端v-for渲染
Vue(尚品汇)第一天_第18张图片
效果图

背景颜色处理
Vue(尚品汇)第一天_第19张图片
cur这个样式已经写好
Vue(尚品汇)第一天_第20张图片
效果图

这是之前css写好的一个效果 现在我们用js来替换一下css
Vue(尚品汇)第一天_第21张图片

4.7函数防抖和节流(节流是CD,防抖是回城)

Vue(尚品汇)第一天_第22张图片

问题:浏览器跟不上鼠标速度
防抖和节流需要一个插件lodash vue项目也依赖这个所以无需下载
节流我的理解就是减少触发次数 一个时间内只能触发一次

//按需引入lodash的功能
import throttle from "lodash/throttle.js";

Vue(尚品汇)第一天_第23张图片
效果图:

防抖就是间隔时间不大于防抖的时间那么会一直不执行

//按需引入lodash的功能
import debounce from "lodash/debounce.js";

Vue(尚品汇)第一天_第24张图片
效果图:

五、ThreeDay

5.1路由跳转以及传参

data-属性名 这是一个自定义属性
这里给a标签添加了两个自定义属性,用于获取categoryname属性和区别是一二三级菜单
并且通过事件委派给外层的div一个search事件
Vue(尚品汇)第一天_第25张图片
search跳转代码

goSearch(event){
        let element = event.target;
        //节点中有一个dataset属性可以获取自定义属性和值
        //通过解构赋值取出categoryName和categoryid  本来应该是大写 浏览器解析后是小写我们就用小写
        let {categoryname,category1id,category2id,category3id} = element.dataset;
        //有这个属性值一定是a标签
        if(categoryname){
          //整理路由跳转需要的参数
          let location = {name:"search"};
          let query = {categoryName:categoryname};
          //判断一二三级菜单
          if(category1id){
            query.category1Id = category1id;
          }else if(category2id){
            query.category2Id = category2id;
          }else{
            query.category3Id = category3id;
          }
          //完善参数
          location.query = query;
          //路由跳转
          console.log(location);
          this.$router.push(location);
        }
      }

效果图:
Vue(尚品汇)第一天_第26张图片

5.2search页面的typeNav显示隐藏

上两个事件和一个v-show来控制
Vue(尚品汇)第一天_第27张图片
默认展示,如果不是home路由就隐藏
Vue(尚品汇)第一天_第28张图片
离开也需要指定路由组件 不然home路由会跟着隐藏
Vue(尚品汇)第一天_第29张图片
通过css写点儿动画
Vue(尚品汇)第一天_第30张图片

效果图:

5.3合并参数

我们的search是params传参,而三级联动点击是query传参
我们要做合并就是把两个参数都传上服务器不管先点哪一个
这个是点解搜索的params传参代码
Vue(尚品汇)第一天_第31张图片
三级联动的query传参
Vue(尚品汇)第一天_第32张图片
效果图:

5.4mock模拟数据

下载安装mockjs

npm install mockjs

mockServe.js代码

//引入mockjs
import Mock from "mockjs";
//把json数据格式引入进来(json数据格式是默认暴露的)
//webpack默认对外暴露:图片,json
import banner from "./banner.json"
import floor from "./floor.json"

//mock数据 :第一个参数请求地址,第二个参数:请求数据
Mock.mock("/mock/banner",{code:200,data:banner});
Mock.mock("/mock/floor",{code:200,data:floor});

最后别忘在main.js中引入
Vue(尚品汇)第一天_第33张图片

5.5获取Banner轮播图数据

mockRequests.js文件代码

//对于axios进行二次封装
import axios from "axios";
//引入进度条
import nprogress from 'nprogress';
//引入相关进度条的样式
import "nprogress/nprogress.css";

//axios.create方法执行,其实返回一个axios和request一样的
let requests = axios.create({
    //基础路径,发请求URL携带api【发现:真实服务器接口都携带/api】
    baseURL: "/mock",
    //超时的设置
    timeout: 5000
});

//请求拦截器:将来项目中【N个请求】,只要发请求,会触发请求拦截器!!!
requests.interceptors.request.use(config => {
    //请求拦截器:请求头【header】,请求头能否给服务器携带参数
    //请求拦截器:其实项目中还有一个重要的作用,给服务器携带请求们的公共的参数
    //进度条开始
    nprogress.start();
    return config;
});

//响应拦截器:请求数据返回会执行
requests.interceptors.response.use((res) => {
    //res:实质就是项目中发请求、服务器返回的数据
    //进度条结束
    nprogress.done();
    return res.data;
}, (err) => {
    //温馨提示:某一天发请求,请求失败,请求失败的信息打印出来
    alert(err.message);
    //终止Promise链
    return new Promise();
});

//最后需要暴露:暴露的是添加新的功能的axios,即为requests
export default requests;

在api/index.js中引入和使用
Vue(尚品汇)第一天_第34张图片
前端路由组件挂载完毕就向Vuex发起通知获取mock数据
Vue(尚品汇)第一天_第35张图片
最后在仓库中保存数据
Vue(尚品汇)第一天_第36张图片
在Vue开发者工具中能正常加载数据说明以上代码成功
在这里插入图片描述

5.6Banner轮播图完善

利用计算属性把仓库中的数据给组件
Vue(尚品汇)第一天_第37张图片
安装swiper

npm install swiper@6

组件中引入js

import Swiper from "swiper/swiper-bundle.js";

在全局main.js入口文件中引入css

//引入swiper的css --- 轮播图
import "swiper/swiper-bundle.min.css"

使用v-for动态渲染数据
Vue(尚品汇)第一天_第38张图片
使用watch监听属性和this.$nextTick添加轮播图功能
watch监听到bannerList中的数据变化执行,使用$nextTick是等待dom渲染完毕执行

  watch:{
    bannerList:{
      handler(){
       this.$nextTick(()=> {
       var mySwiper = new Swiper('#mySwiper', {
            loop: true, // 循环模式选项
            autoplay: true,//可选选项,自动滑动
            // 如果需要分页器
            pagination: {
                el: '.swiper-pagination',
                clickable:true,
            },
            // 如果需要前进后退按钮
            navigation: {
                nextEl: '.swiper-button-next',
                prevEl: '.swiper-button-prev',
            },
        });
       })
      }
    }
  }

效果图:

5.7获取Floor数据

先写接口api
Vue(尚品汇)第一天_第39张图片
仓库中保存数据
Vue(尚品汇)第一天_第40张图片
由于我们的Floor组件需要复用所以拉取数据到他的父组件中并且通过v-for生成Floor组件
通过props传递数据给floor这个组件
Vue(尚品汇)第一天_第41张图片
Vue(尚品汇)第一天_第42张图片
打开开发者工具检查是否拿到数据
Vue(尚品汇)第一天_第43张图片

5.8Floor数据动态渲染

代码对应的地方v-for渲染一下
Vue(尚品汇)第一天_第44张图片
这个小轮播图的地方不需要之前Banner像使用watch的原因是
他的数据是父组件挂载完毕,父组件传过来的数据
Vue(尚品汇)第一天_第45张图片
效果图

六、FourDay

6.1公用组件Carsoule

首先调整两个小轮播的代码和大轮播图写法风格一致
Vue(尚品汇)第一天_第46张图片
开始封装全局组件Carsoule代码:

<template>
  <div class="swiper-container" ref="mySwiper">
          <div class="swiper-wrapper">
            <div
              class="swiper-slide"
              v-for="(carousel, index) in list"
              :key="carousel.id">
              <img :src="carousel.imgUrl" />
            </div>
          </div>
          <!-- 如果需要分页器 -->
          <div class="swiper-pagination"></div>

          <!-- 如果需要导航按钮 -->
          <div class="swiper-button-prev"></div>
          <div class="swiper-button-next"></div>
        </div>
</template>

<script>
import Swiper from "swiper/swiper-bundle.js";
export default {
    name:"Carsoule",
    props:['list'],
      watch:{
    bannerList:{
      immediate:true,
      handler(){
       this.$nextTick(()=> {
       var mySwiper = new Swiper(this.$refs.mySwiper, {
            loop: true, // 循环模式选项
            autoplay: true,//可选选项,自动滑动
            // 如果需要分页器
            pagination: {
                el: '.swiper-pagination',
                clickable:true,
                
            },
            // 如果需要前进后退按钮
            navigation: {
                nextEl: '.swiper-button-next',
                prevEl: '.swiper-button-prev',
            },
        });
       })
      }
    }
  }
}
</script>

main.js入口文件中引入和注册为全局组件
在这里插入图片描述
两个写轮播图的地方用全局组件替换
Vue(尚品汇)第一天_第47张图片
效果图:

6.2Search模块获取数据

第一步写接口,这里是post请求了
Vue(尚品汇)第一天_第48张图片
第二步写小仓库代码

import { reqPostSearchInfo } from "@/api";
const state = {
    searchList:{},
};
const mutations = {
    REQPOSTSEARCHLIST(state,searchList){
        state.searchList = searchList;
    }
};
const actions = {
    //不传参数默认空对象
   async reqPostSearchList({commit},params = {}){
        let result = await reqPostSearchInfo(params);
        if(result.code == 200){
            commit("REQPOSTSEARCHLIST",result.data)
        }
    }
};
const getters = {
    //这个形参是当前仓库的state
    goodsList(state){
        return state.searchList.goodsList;
    }
};
export default ({
    state,
    mutations,
    actions,
    getters
});

注意大仓库需要引用和注册
Vue(尚品汇)第一天_第49张图片
第三步组件发起请求和映射到本地
Vue(尚品汇)第一天_第50张图片
检查是否拿到数据
Vue(尚品汇)第一天_第51张图片
v-for渲染数据
Vue(尚品汇)第一天_第52张图片
效果图

开始完善子组件 先写仓库
Vue(尚品汇)第一天_第53张图片
拿数据,品牌和下面的属性api是分别返回了两条数据
Vue(尚品汇)第一天_第54张图片
v-for渲染
Vue(尚品汇)第一天_第55张图片
效果图:
Vue(尚品汇)第一天_第56张图片

6.3完善search搜索功能

<script>
  import {mapGetters} from "vuex";
  import SearchSelector from './SearchSelector/SearchSelector'
  export default {
    name: 'Search',
    components: {
      SearchSelector
    },
    data:function(){
      return {
        searchParams:{    //search需要带的参数列表
          category3Id: "",
          category2Id: "",
          category1Id: "",
          categoryName: "",
          keyword: "",
          order: "",
          pageNo: 1,
          pageSize: 3,
          props: [],
          trademark: ""
        }
      } 
    },
    //这个函数是在mounted挂载之前执行的
    beforeMount(){
      //整理一下发起search请求的参数
      Object.assign(this.searchParams,this.$route.query,this.$route.params);
    },
    mounted(){
      this.getData();   //页面加载完毕就搜索所有数据
    },
    methods:{
      getData(){
         this.$store.dispatch("reqPostSearchList",this.searchParams);
      }
    },
    computed:{
      //这个是直接大仓库中找这个goodsList所以不需要写search
        ...mapGetters(["goodsList"])
    },
    watch:{
      $route(){
        //每次搜索的东西不一样嘛  咱们重新整理一下数据
        Object.assign(this.searchParams,this.$route.query,this.$route.params);
        //再次发送ajax请求 
        this.getData();
        //清空分类id   给下一次发送请求做准备
        this.searchParams.category3Id = "";
        this.searchParams.category2Id = "";
        this.searchParams.category1Id = "";
      }
    }
  }
</script>

效果图

6.4处理面包屑(有bug的版本)

v-for动态渲染和绑定对应的事件
Vue(尚品汇)第一天_第57张图片
method方法

methods:{
      getData(){
         this.$store.dispatch("reqPostSearchList",this.searchParams);
      },
      removeCategoryName(){
        this.searchParams.categoryName = undefined;
        this.remove();
        //重新获取全部数据
        this.getData();
        //如果搜索框keyword有数据依然带着请求
        if(this.$route.params){
            this.$router.push({name:"search",params:this.$route.params});
        }
      },
      removeKeyword(){
        this.searchParams.keyword = undefined;
        this.remove();
        this.getData();
        if(this.$route.query){
            this.$router.push({name:"search",params:this.$route.query});
        }
      },
      remove(){
        //值为undefined的时候浏览器不会把这个字段带给服务器  提高性能
        this.searchParams.category3Id = undefined;
        this.searchParams.category2Id = undefined;
        this.searchParams.category1Id = undefined;
      }
    },

效果图:这里产生了bug,点击x按钮后没有带keyword数据,list请求头也没有这个参数,但路径上依然有这个参数

6.5处理面包屑(无bug的版本)

上一个版本是点击搜索之后就清空输入框,这一次是叉掉面包屑后清空输入框
首先在入口文件注册全局事件总线来通知兄弟组件清空输入框
Vue(尚品汇)第一天_第58张图片
这里的keyWord就是通过v-model双向绑定的输入框
Vue(尚品汇)第一天_第59张图片
动态渲染的代码不变
提示:三级联动点击是query参数,搜索框输入是params参数

    methods:{
      getData(){
         this.$store.dispatch("reqPostSearchList",this.searchParams);
      },
      removeCategoryName(){
        this.searchParams.categoryName = undefined;
        //值为undefined的时候浏览器不会把这个字段带给服务器  提高性能
        this.searchParams.category3Id = undefined;
        this.searchParams.category2Id = undefined;
        this.searchParams.category1Id = undefined;
        //重新获取全部数据
        this.getData();
        //如果搜索框keyword有数据依然带着请求
        if(this.$route.params){
            this.$router.push({name:"search",params:this.$route.params});
        }
      },
      removeKeyword(){
        this.searchParams.keyword = undefined;
        //通知Header组件把搜索框的内容清空
        this.$bus.$emit("clear");
        this.getData();
        if(this.$route.query){
            this.$router.push({name:"search",query:this.$route.query});
        }
      },
    },

相比较上个版本最核心的错误就是在search路由中最后没有这个?
Vue(尚品汇)第一天_第60张图片
效果图:

6.6点击品牌查询数据

子给父传数据这里使用的是自定义事件
子组件点击品牌然后触发自定义事件
在这里插入图片描述
这是父组件绑定的自定义事件
Vue(尚品汇)第一天_第61张图片
先测试一下是否能拿到数据
Vue(尚品汇)第一天_第62张图片
Vue(尚品汇)第一天_第63张图片
一样的发起请求获取数据和点击删除

//删除品牌搜索产生的面包屑
      removeTrademark(){
          this.searchParams.trademark = undefined;
          this.getData();
      },
      //自定义事件接受子组件传过来的品牌数据
      trademarkInfoMessage(msg){
       //重新整理需要携带的数据
       this.searchParams.trademark = `${msg.tmId}:${msg.tmName}`;
       //再次发送请求
       this.getData();
      }

v-for渲染的代码
Vue(尚品汇)第一天_第64张图片
效果图:

6.7根据goods属性信息查询

子组件一个点击事件传递商品的id,商品的属性和属性值
Vue(尚品汇)第一天_第65张图片
触发父组件的一个自定义事件
Vue(尚品汇)第一天_第66张图片

父组件绑定自定义事件
Vue(尚品汇)第一天_第67张图片
打印一下是否成功拿到数据
Vue(尚品汇)第一天_第68张图片
Vue(尚品汇)第一天_第69张图片
两个事件点击属性添加和删除

 //自定义事件接受子组件传过来的goods属性
      receiveAttrInfo(attr,value){
        //[属性id:属性值:属性名]       这是请求需要带给后端的数据
        let props = `${attr.attrId}:${value}:${attr.attrName}`;
        //这个判断是防止多次点击同一个属性进行重复添加
        if(this.searchParams.props.indexOf(props) == -1) this.searchParams.props.push(props);
        this.getData();
      },
      //删除属性产生的面包屑
      removeAttribute(index){
        //通过索引删除点击的数组中存在的属性
          this.searchParams.props.splice(index,1);
          this.getData();
      }

使用vfor渲染
在这里插入图片描述
效果图
Vue(尚品汇)第一天_第70张图片

七、FiveDay

7.1排序操作

正确使用阿里巴巴在线图标库
在index.html中引入需要加https: 在使用的类名前面要加iconfont
Vue(尚品汇)第一天_第71张图片
oreder参数说明

 // 1:综合/2:价格/asc:升序/desc:降序
          order: "1:desc",

active表示有类名,上下箭头也是这个类名来控制

 <ul class="sui-nav">
                <li :class="{active:!isActive}">
                  <a href="#">综合
                    <span style="padding-left:5px;" 
                     v-show="!isActive"
                    class="iconfont"
                    :class="{'icon-long-arrow-up':isUp,'icon-long-arrow-down':isDown}">
                    </span>
                  </a>
                </li>
                <li :class="{active:isActive}">
                  <a href="#">价格
                    <span style="padding-left:5px;" 
                    v-show="isActive"
                    class="iconfont"
                    :class="{'icon-long-arrow-up':isUp,'icon-long-arrow-down':isDown}">
                  </span>
                  </a>
                </li>
              </ul>

新增三个computed计算属性

		isActive(){
        return this.searchParams.order.indexOf("1") == -1;
      },
        isUp(){
          return this.searchParams.order.indexOf("asc") != -1;
        },
         isDown(){
          return this.searchParams.order.indexOf("desc") != -1;
        },

效果
Vue(尚品汇)第一天_第72张图片
两个按钮绑定同一个事件通过1和2来区分是综合还是价格
Vue(尚品汇)第一天_第73张图片
绑定的函数

changeOrder(flag){
        //记录一下当前状态
        let originOrder = this.searchParams.order;
        //分别记录下来当前状态
        let OrderFlag = originOrder.split(":")[0];
        let OrderSort = originOrder.split(":")[1];
        //声明一个新的属性值
        let newOrder = "";
        //还是点击的当前状态的按钮
        if(OrderFlag == flag){
          newOrder = `${flag}:${OrderSort=="desc"?"asc":"desc"}`;
        }else{   //点了另外一个按钮默认降序
          newOrder = flag+":desc";
        }
        this.searchParams.order = newOrder;
        //再次发送请求
        this.getData();
      }

效果图

7.2分页器

多个地方写成全局组件 静态代码偷的
Vue(尚品汇)第一天_第74张图片
main.js中注册为全局组件
Vue(尚品汇)第一天_第75张图片

// pageNo:当前页数
// pageSize:每一页展示多少条数据
// total:代表整个分页一共有多少数据
// continues:分页连续页码个数

写点儿假数据玩玩
Vue(尚品汇)第一天_第76张图片
props接受计算一下当前分页的最大数据
Vue(尚品汇)第一天_第77张图片
效果图:
Vue(尚品汇)第一天_第78张图片
通过当前页码和需要的连续页码 计算出当前页码相连的页码

 startNumAndEndNum(){
        //解构一下 分页连续页码个数和当前页和当前分页的最大页
        const {continues,pageNo,totalPage} = this;
        //定义两个变量起始数字合结束数字
        let start = 0 , end = 0;
        //1.不正常现象 总页数没有连续页码数多
        if(continues > totalPage){
          start = 1;
          end = totalPage;
        }else{
          //示范 当前页码5  连续页码应该显示 3 4 5 6 7
          start = pageNo - Math.floor(continues / 2);
          end = pageNo + Math.floor(continues / 2);
          //2.不正常现象起始越界    当前页码为1 起始页码就算出来是-1了
          if(start < 1){
              start = 1;
              end = continues;
          }
          //3.不正常现象结束越界    当前页码91 总页码91 结束页码就93了
          if(end > totalPage){
            end = totalPage;
            start = totalPage - continues + 1;
          }
        }
        return {start,end};
      }

上数据测试
Vue(尚品汇)第一天_第79张图片
Vue(尚品汇)第一天_第80张图片
Vue(尚品汇)第一天_第81张图片
动态控制1和省略按钮的显示和隐藏和动态渲染页码
v-for动态渲染1开始到end结束的页码,v-if控制小于start的值进行隐藏
Vue(尚品汇)第一天_第82张图片
当前页是第一页效果图
Vue(尚品汇)第一天_第83张图片
动态控制尾页
Vue(尚品汇)第一天_第84张图片
Vue(尚品汇)第一天_第85张图片
Vue(尚品汇)第一天_第86张图片
pageNo和pageSize是本地定义好的数据 而total最大页码是服务端获取的
在这里插入图片描述
total数据在本地仓库中需要借助mapState来获取
Vue(尚品汇)第一天_第87张图片
给父组件添加自定义事件
Vue(尚品汇)第一天_第88张图片
当前页是第一页不可以点击上一页,点击上一页传参数当前页减一
Vue(尚品汇)第一天_第89张图片
继续完善
Vue(尚品汇)第一天_第90张图片
search组件整理参数重新发送请求

 getPageNo(pageNo){
        this.searchParams.pageNo = pageNo;
        this.getData();
      }

效果图

动态背景色

Vue(尚品汇)第一天_第91张图片

7.3商品详情

静态页面咱们偷
:skuid是接受params传参过来的id
Vue(尚品汇)第一天_第92张图片
效果图 当然这个url路径是手敲上去的
Vue(尚品汇)第一天_第93张图片
商品详情肯定是点击商品列表的图片跳转过来的
这里使用声明式导航写的
Vue(尚品汇)第一天_第94张图片
这里出现了一个问题,跳转过去滚轮在底下

router做了模块化 这里是vue路由3x提供的一个api
Vue(尚品汇)第一天_第95张图片
1.写接口
Vue(尚品汇)第一天_第96张图片
2.写仓库 第七行Goods应该是小写
Vue(尚品汇)第一天_第97张图片
组件挂载完毕发送请求派发actions
在这里插入图片描述
效果图
Vue(尚品汇)第一天_第98张图片
动态展示数据 导航路径区域
借助Getters简化数据
Vue(尚品汇)第一天_第99张图片
vue静态页面拉取数据
Vue(尚品汇)第一天_第100张图片
动态渲染数据
Vue(尚品汇)第一天_第101张图片
Vue(尚品汇)第一天_第102张图片
这里出现了一个新问题
出现上面这个的原因就是服务器没有来得及返回数据
categoryView的数据就为undefined 所以安排一个默认值{}
Vue(尚品汇)第一天_第103张图片
动态渲染详情数据
Vue(尚品汇)第一天_第104张图片
效果图
Vue(尚品汇)第一天_第105张图片
完善放大镜 先看一下后端返回的数据结构
Vue(尚品汇)第一天_第106张图片
咱们借助props子组件传递数据
Vue(尚品汇)第一天_第107张图片
子组件接受数据和渲染
Vue(尚品汇)第一天_第108张图片
效果图 当然这个报错也是网络原因
Vue(尚品汇)第一天_第109张图片
因为数据在服务端还没有完全的返回回来
我们在传递给子组件的时候数据为undefined的时候传一个空数组
在这里插入图片描述
又出现了新问题还是数据为undefined
Vue(尚品汇)第一天_第110张图片
这里得借助computed计算属性处理一下
Vue(尚品汇)第一天_第111张图片

ok即使网络不好也不会报错了
Vue(尚品汇)第一天_第112张图片
接下来解决底部的小轮播图 一样的props传参
在这里插入图片描述
props接受动态渲染
Vue(尚品汇)第一天_第113张图片
接下来搞商品属性 还是先写仓库的getters
Vue(尚品汇)第一天_第114张图片
v-for渲染
Vue(尚品汇)第一天_第115张图片

根据数据结构动态渲染红色区域
Vue(尚品汇)第一天_第116张图片
解决这个选中状态 是通过类名active控制的
后端是返回了一个isChecked数据默认选中的
Vue(尚品汇)第一天_第117张图片
我们需要添加一个点击事件传递两个形参是 当前点击的元素和所有的元素
Vue(尚品汇)第一天_第118张图片
效果图
Vue(尚品汇)第一天_第119张图片
完善商品详情的轮播图
使用watch数据监听到服务器数据返回
在使用this.nextTick等待dom渲染完毕执行
Vue(尚品汇)第一天_第120张图片
动态添加类名和绑定点击事件
Vue(尚品汇)第一天_第121张图片
配置data和methods方法
Vue(尚品汇)第一天_第122张图片
效果图Vue(尚品汇)第一天_第123张图片
当然我们这里点击小图并没有切换大图
在之前点击切换高亮的methods方法中我们绑定全局事件总线
Vue(尚品汇)第一天_第124张图片
兄弟组件接受index并且修改当前图片
Vue(尚品汇)第一天_第125张图片
接下来完善放大镜功能
这个event就是放整个图片的盒子 图片盒子是400x400大小的
Vue(尚品汇)第一天_第126张图片
撸代码
在这里插入图片描述
运行测试一下
Vue(尚品汇)第一天_第127张图片
Vue(尚品汇)第一天_第128张图片
咱们再打印mask看看
Vue(尚品汇)第一天_第129张图片
还需要约束一下这个遮罩层
Vue(尚品汇)第一天_第130张图片
添加约束
Vue(尚品汇)第一天_第131张图片
效果图

大图还没有动态跟着改变 可以看到大图和小图是两倍的关系
Vue(尚品汇)第一天_第132张图片
所以我们这里的移动需要x2 我们的遮罩层向右移动left值增大,所以图片的left值应该减小
大图片才会有从右往左的一个效果
总之遮罩层的left值越大,实际大图片的left值才会更小

Vue(尚品汇)第一天_第133张图片
效果图

处理用户输入的购买商品数量的问题
Vue(尚品汇)第一天_第134张图片
对应的回调函数
Vue(尚品汇)第一天_第135张图片

7.4购物车操作

加入购物车 先写接口 需要带两个参数 这里就直接写在仓库中了
Vue(尚品汇)第一天_第136张图片
Promise返回任意字符串就是成功
在商品详情中点击购物车派发actions
Vue(尚品汇)第一天_第137张图片
先偷代码注册路由
Vue(尚品汇)第一天_第138张图片
写路由跳转并且传递参数 因为保存字符串所以用JSON转一下
Vue(尚品汇)第一天_第139张图片
兄弟组件用计算属性读取本地会话的数据
Vue(尚品汇)第一天_第140张图片
打开开发者工具看一下数据是否成功
Vue(尚品汇)第一天_第141张图片
页面动态展示
Vue(尚品汇)第一天_第142张图片
点击商品详情进行回退和去购物车结算功能完善
Vue(尚品汇)第一天_第143张图片
偷组件和注册组件
Vue(尚品汇)第一天_第144张图片
效果图

拉取购物车列表
这里就得考虑一个问题拉取谁的数据,以及存入的时候算谁的数据,需要一个唯一持久化的标识符我们这里使用的uuid,vue项目的依赖无需下载安装
Vue(尚品汇)第一天_第145张图片
在商品详情的仓库中我们就进行调用获取
Vue(尚品汇)第一天_第146张图片
存放在本地存储里面的并且仓库也能正常拉取不删除就不会改变了
Vue(尚品汇)第一天_第147张图片
唯一标识符弄出来了 我们每次请求数据都给他带到后端去
我们把唯一标识符通过拦截请求头加在请求头中
Vue(尚品汇)第一天_第148张图片
然后我们每一次请求都会带上这个id
Vue(尚品汇)第一天_第149张图片
同样的仓库三连环嘛
Vue(尚品汇)第一天_第150张图片
组件拉取数据
Vue(尚品汇)第一天_第151张图片
v-for动态渲染数据
Vue(尚品汇)第一天_第152张图片
计算总价单独用计算属性来算
Vue(尚品汇)第一天_第153张图片
效果图

这里还有一个全选的问题 这里就没做响应式了
Vue(尚品汇)第一天_第154张图片
购物车商品详情数量处理(带正数表示加多少,带负数表示减去多少,带0不改变)
点击加减和直接修改绑定同一个函数,这里cart是vfor渲染的数据
在这里插入图片描述
先做点击按钮进行加减
Vue(尚品汇)第一天_第155张图片
对直接修改进行处理
Vue(尚品汇)第一天_第156张图片
效果图

删除购物车中商品 先写接口
在这里插入图片描述
对应的写仓库
在这里插入图片描述
组件发送删除请求并且刷新数据
Vue(尚品汇)第一天_第157张图片
效果图
Vue(尚品汇)第一天_第158张图片
当我们疯狂点击减的时候会出现不正常的现象我们得用节流处理一下
Vue(尚品汇)第一天_第159张图片
这里做一下商品状态的修改 先写接口
Vue(尚品汇)第一天_第160张图片
再写仓库接口
Vue(尚品汇)第一天_第161张图片
组件派发actions和做节流
Vue(尚品汇)第一天_第162张图片
效果图:
Vue(尚品汇)第一天_第163张图片
删除选中的商品
Vue(尚品汇)第一天_第164张图片
actions处理
在这里插入图片描述
效果图
Vue(尚品汇)第一天_第165张图片
全选按钮处理
Vue(尚品汇)第一天_第166张图片
checked是未改变的效果,所以跟他不一样的按钮进行替换就行
Vue(尚品汇)第一天_第167张图片
效果图无

八、登录注册

8.1注册功能

两个接口获取验证码和点击登录发送注册请求
Vue(尚品汇)第一天_第168张图片
两次仓库中定义函数都是直接返回结果让前端做处理
Vue(尚品汇)第一天_第169张图片
如果验证码的请求成功 直接输入到组件的输入框里面
Vue(尚品汇)第一天_第170张图片
组件处理 注册请求
Vue(尚品汇)第一天_第171张图片
效果图
Vue(尚品汇)第一天_第172张图片

8.2登录功能

1.先写接口 这里带一个配置对象data接受手机号和密码两个参数
2.写仓库
Vue(尚品汇)第一天_第173张图片
组件处理登录成功跳转
Vue(尚品汇)第一天_第174张图片
登录成功之后头部应该展示用户信息和退出登录
Vue(尚品汇)第一天_第175张图片
先写接口
Vue(尚品汇)第一天_第176张图片
在写仓库actions
Vue(尚品汇)第一天_第177张图片
当然我们获取用户信息需要带上token
Vue(尚品汇)第一天_第178张图片
我们在home组件挂载时派发actions
一刷新就失效的原因是我们的token保存在vuex中的
Vue(尚品汇)第一天_第179张图片
接下来仓库三连环把登录成功数据保存在仓库中
Vue(尚品汇)第一天_第180张图片
组件通过计算属性是否登录
Vue(尚品汇)第一天_第181张图片
Vue(尚品汇)第一天_第182张图片
效果图刷新失效的原因是我们没有解决token的持久化保存

接下来做token的持久化存储
我们只需要在点击登录的时候往本地仓库中存储一份再次刷新读取本地仓库
Vue(尚品汇)第一天_第183张图片

这里做了模块化
Vue(尚品汇)第一天_第184张图片
读取和保存的代码
Vue(尚品汇)第一天_第185张图片
当然还有问题 派发actions是在home路由下,进入了别的路由刷新就不会拿本地token了,还有就是登录成功了url输入照样能跳转login界面 这两个问题后面解决

8.3退出登录

先写接口
Vue(尚品汇)第一天_第186张图片
在写仓库 如果成功给组件返回成功并且提交mutations
Vue(尚品汇)第一天_第187张图片
mutations需要清除本地的一些信息
Vue(尚品汇)第一天_第188张图片
在组件中接受返回结果 清除成功则进行路由跳转
Vue(尚品汇)第一天_第189张图片

8.4全局前置路由守卫

出现8.2那种别的组件刷新登录信息丢失的原因是
获取userinfo的actions是home组件挂载完毕发出的,你进入了别的组件刷新触发不了这个函数,userinfo又是保存在vuex中的所以刷新就失效了
Vue(尚品汇)第一天_第190张图片
解决办法就是通过路由守卫每一次进行路由跳转都获取服务器的返回的用户信息
也解决了用户已经登录不让再去登录页面的问题
在这里插入图片描述
效果图

8.5用户地址信息展示

先写两个接口
Vue(尚品汇)第一天_第191张图片
仓库中保存数据
Vue(尚品汇)第一天_第192张图片
组件派发actions和mapState保存数据
Vue(尚品汇)第一天_第193张图片
动态渲染
Vue(尚品汇)第一天_第194张图片
Vue(尚品汇)第一天_第195张图片
Vue(尚品汇)第一天_第196张图片
-mounted发起请求,前两个计算属性拉取仓库数据,最后一个是计算商品提交的最后选中数据,methods方法切换选中状态
Vue(尚品汇)第一天_第197张图片
效果图

8.6提交订单功能

先写好提交订单的接口 这后面就没有使用vuex了
Vue(尚品汇)第一天_第198张图片

我们这里是直接把写api接口的文件直接配置成全局事件总线
Vue(尚品汇)第一天_第199张图片
点击提交订单携带query参数进行路由跳转
Vue(尚品汇)第一天_第200张图片
Pay组件计算属性获取订单号发起请求获取订单信息
Vue(尚品汇)第一天_第201张图片
效果图

8.7实现支付功能

咱们这里用的element-ui做的弹出框 具体参照饿了么官网
用后台返回的支付字符串生成二维码 下载qrcode库

npm i qrcode

这里只展示部分代码
Vue(尚品汇)第一天_第202张图片
通过element生产的弹窗和qrcode转换的微信支付二维码


现在实现支付功能和路由跳转 /我们需要一秒查询一次支付结果
Vue(尚品汇)第一天_第203张图片
效果图:

还有一些小细节问题需要进一步完善
Vue(尚品汇)第一天_第204张图片

8.8订单详情

先偷组件 在写路由,二级路由不需要带/
Vue(尚品汇)第一天_第205张图片
一定要注意些路由的出口
Vue(尚品汇)第一天_第206张图片
效果图:
Vue(尚品汇)第一天_第207张图片
接下来我的订单组件获取数据
Vue(尚品汇)第一天_第208张图片
效果图
Vue(尚品汇)第一天_第209张图片
动态渲染数据
Vue(尚品汇)第一天_第210张图片
分页器是之前search模块封装好的直接使用
Vue(尚品汇)第一天_第211张图片
效果图:

你可能感兴趣的:(vue.js)