Vue(尚品汇)第一天

一、准备工作

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

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

安装vue-cli脚手架

npm install -g vue-cli

正式创建一个vue2的项目

vue create 项目名

二、项目配置

2.1关闭vue语法检测

为避免一些奇怪的错误
l

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项目跑起来自动打开浏览器

在这里插入图片描述

三、OneDay

3.1准备相关依赖

下载安装6版本less

npm install less less-loader@6

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

安装router模块

npm install vue-router@3

3.2配置路由

在这里插入图片描述

3.3路由push传参

在这里插入图片描述
小总结

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注册全局组件

在这里插入图片描述

四、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中测试一下接口
在这里插入图片描述
请求成功
在这里插入图片描述

4.3nprogress进度条

安装

npm install nprogress

在请求拦截器和响应拦截器中应用
在这里插入图片描述

效果:
请添加图片描述

4.4 vuex的基本使用

安装3.6.2版本的vuex

npm install vuex@3.6.2

vuex的基本配置在src中的store的目录下
在这里插入图片描述
配置完成后在入口文件进行引入和注册
在这里插入图片描述
先在仓库中准备数据,再到Home组件中进行一个引入和计算属性挂载,vue的开发工具中绑定上数据即为成功

在这里插入图片描述

4.5三级联动获取数据

先对home仓库进行模块化
在这里插入图片描述
因为是axios发出的请求返回是一个promise对象我们需要使用ansyc和await函数来处理
在这里插入图片描述
在三级联动模块挂载发出请求
在这里插入图片描述
页面加载完成成功拿到数据
在这里插入图片描述

4.6三级联动渲染数据

对获取到的数据进行处理 home仓库的代码
在这里插入图片描述
借助辅助函数mapState从仓库中获取数据 并且保存到到本地的categoryList
在这里插入图片描述
前端v-for渲染
在这里插入图片描述
效果图
在这里插入图片描述
背景颜色处理
在这里插入图片描述
cur这个样式已经写好
在这里插入图片描述
效果图
请添加图片描述
这是之前css写好的一个效果 现在我们用js来替换一下css
在这里插入图片描述

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

在这里插入图片描述

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

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

在这里插入图片描述
效果图:
请添加图片描述
防抖就是间隔时间不大于防抖的时间那么会一直不执行

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

在这里插入图片描述
效果图:
请添加图片描述

五、ThreeDay

5.1路由跳转以及传参

data-属性名 这是一个自定义属性
这里给a标签添加了两个自定义属性,用于获取categoryname属性和区别是一二三级菜单
并且通过事件委派给外层的div一个search事件
在这里插入图片描述
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);
        }
      }

效果图:
请添加图片描述

5.2search页面的typeNav显示隐藏

上两个事件和一个v-show来控制
在这里插入图片描述
默认展示,如果不是home路由就隐藏
在这里插入图片描述
离开也需要指定路由组件 不然home路由会跟着隐藏
在这里插入图片描述
通过css写点儿动画
在这里插入图片描述

效果图:
请添加图片描述

5.3合并参数

我们的search是params传参,而三级联动点击是query传参
我们要做合并就是把两个参数都传上服务器不管先点哪一个
这个是点解搜索的params传参代码
在这里插入图片描述
三级联动的query传参
在这里插入图片描述
效果图:
请添加图片描述

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中引入
在这里插入图片描述

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中引入和使用
在这里插入图片描述
前端路由组件挂载完毕就向Vuex发起通知获取mock数据
在这里插入图片描述
最后在仓库中保存数据
在这里插入图片描述
在Vue开发者工具中能正常加载数据说明以上代码成功
在这里插入图片描述

5.6Banner轮播图完善

利用计算属性把仓库中的数据给组件
在这里插入图片描述
安装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动态渲染数据
在这里插入图片描述
使用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
在这里插入图片描述
仓库中保存数据
在这里插入图片描述
由于我们的Floor组件需要复用所以拉取数据到他的父组件中并且通过v-for生成Floor组件
通过props传递数据给floor这个组件
在这里插入图片描述
在这里插入图片描述
打开开发者工具检查是否拿到数据
在这里插入图片描述

5.8Floor数据动态渲染

代码对应的地方v-for渲染一下
在这里插入图片描述
这个小轮播图的地方不需要之前Banner像使用watch的原因是
他的数据是父组件挂载完毕,父组件传过来的数据
在这里插入图片描述
效果图
在这里插入图片描述

六、FourDay

6.1公用组件Carsoule

首先调整两个小轮播的代码和大轮播图写法风格一致
在这里插入图片描述
开始封装全局组件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入口文件中引入和注册为全局组件
在这里插入图片描述
两个写轮播图的地方用全局组件替换
在这里插入图片描述
效果图:
请添加图片描述

6.2Search模块获取数据

第一步写接口,这里是post请求了
在这里插入图片描述
第二步写小仓库代码

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
});

注意大仓库需要引用和注册
在这里插入图片描述
第三步组件发起请求和映射到本地
在这里插入图片描述
检查是否拿到数据
在这里插入图片描述
v-for渲染数据
在这里插入图片描述
效果图
在这里插入图片描述
开始完善子组件 先写仓库
在这里插入图片描述
拿数据,品牌和下面的属性api是分别返回了两条数据
在这里插入图片描述
v-for渲染

效果图:
在这里插入图片描述

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动态渲染和绑定对应的事件
在这里插入图片描述
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的版本)

上一个版本是点击搜索之后就清空输入框,这一次是叉掉面包屑后清空输入框
首先在入口文件注册全局事件总线来通知兄弟组件清空输入框
在这里插入图片描述
这里的keyWord就是通过v-model双向绑定的输入框
在这里插入图片描述
动态渲染的代码不变
提示:三级联动点击是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路由中最后没有这个?
在这里插入图片描述
效果图:
请添加图片描述

6.6点击品牌查询数据

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

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

v-for渲染的代码
在这里插入图片描述
效果图:
请添加图片描述

6.7根据goods属性信息查询

子组件一个点击事件传递商品的id,商品的属性和属性值
在这里插入图片描述
触发父组件的一个自定义事件
在这里插入图片描述

父组件绑定自定义事件
在这里插入图片描述
打印一下是否成功拿到数据
在这里插入图片描述
在这里插入图片描述
两个事件点击属性添加和删除

 //自定义事件接受子组件传过来的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渲染
在这里插入图片描述
效果图
请添加图片描述

七、FiveDay

7.1排序操作

正确使用阿里巴巴在线图标库
在index.html中引入需要加https: 在使用的类名前面要加iconfont
在这里插入图片描述
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;
        },

效果
在这里插入图片描述
两个按钮绑定同一个事件通过1和2来区分是综合还是价格
在这里插入图片描述
绑定的函数

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分页器

多个地方写成全局组件 静态代码偷的
在这里插入图片描述
main.js中注册为全局组件
在这里插入图片描述

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

写点儿假数据玩玩
在这里插入图片描述
props接受计算一下当前分页的最大数据
在这里插入图片描述
效果图:
在这里插入图片描述
通过当前页码和需要的连续页码 计算出当前页码相连的页码

 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};
      }

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

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

效果图
请添加图片描述
动态背景色

在这里插入图片描述

7.3商品详情

静态页面咱们偷
:skuid是接受params传参过来的id
在这里插入图片描述
效果图 当然这个url路径是手敲上去的
在这里插入图片描述
商品详情肯定是点击商品列表的图片跳转过来的
这里使用声明式导航写的
在这里插入图片描述
这里出现了一个问题,跳转过去滚轮在底下
请添加图片描述
router做了模块化 这里是vue路由3x提供的一个api
在这里插入图片描述
1.写接口
在这里插入图片描述
2.写仓库 第七行Goods应该是小写
在这里插入图片描述
组件挂载完毕发送请求派发actions
在这里插入图片描述
效果图
在这里插入图片描述
动态展示数据 导航路径区域
借助Getters简化数据
在这里插入图片描述
vue静态页面拉取数据
在这里插入图片描述
动态渲染数据
在这里插入图片描述
在这里插入图片描述
这里出现了一个新问题请添加图片描述
出现上面这个的原因就是服务器没有来得及返回数据
categoryView的数据就为undefined 所以安排一个默认值{}
在这里插入图片描述
动态渲染详情数据
在这里插入图片描述
效果图
在这里插入图片描述
完善放大镜 先看一下后端返回的数据结构
在这里插入图片描述
咱们借助props子组件传递数据
在这里插入图片描述
子组件接受数据和渲染
在这里插入图片描述
效果图 当然这个报错也是网络原因
在这里插入图片描述
因为数据在服务端还没有完全的返回回来
我们在传递给子组件的时候数据为undefined的时候传一个空数组
在这里插入图片描述
又出现了新问题还是数据为undefined
在这里插入图片描述
这里得借助computed计算属性处理一下
在这里插入图片描述

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

根据数据结构动态渲染红色区域
在这里插入图片描述
解决这个选中状态 是通过类名active控制的
后端是返回了一个isChecked数据默认选中的
在这里插入图片描述
我们需要添加一个点击事件传递两个形参是 当前点击的元素和所有的元素
在这里插入图片描述
效果图
请添加图片描述
完善商品详情的轮播图
使用watch数据监听到服务器数据返回
在使用this.nextTick等待dom渲染完毕执行
在这里插入图片描述
动态添加类名和绑定点击事件
在这里插入图片描述
配置data和methods方法
在这里插入图片描述
效果图请添加图片描述
当然我们这里点击小图并没有切换大图
在之前点击切换高亮的methods方法中我们绑定全局事件总线
在这里插入图片描述
兄弟组件接受index并且修改当前图片
在这里插入图片描述
接下来完善放大镜功能
这个event就是放整个图片的盒子 图片盒子是400x400大小的
在这里插入图片描述
撸代码
在这里插入图片描述
运行测试一下
在这里插入图片描述
在这里插入图片描述
咱们再打印mask看看
在这里插入图片描述
还需要约束一下这个遮罩层
在这里插入图片描述
添加约束
在这里插入图片描述
效果图
请添加图片描述
大图还没有动态跟着改变 可以看到大图和小图是两倍的关系
在这里插入图片描述
所以我们这里的移动需要x2 我们的遮罩层向右移动left值增大,所以图片的left值应该减小
大图片才会有从右往左的一个效果
总之遮罩层的left值越大,实际大图片的left值才会更小请添加图片描述

在这里插入图片描述
效果图
请添加图片描述
处理用户输入的购买商品数量的问题
在这里插入图片描述
对应的回调函数
在这里插入图片描述

7.4购物车操作

加入购物车 先写接口 需要带两个参数 这里就直接写在仓库中了
在这里插入图片描述
Promise返回任意字符串就是成功
在商品详情中点击购物车派发actions
在这里插入图片描述
先偷代码注册路由
在这里插入图片描述
写路由跳转并且传递参数 因为保存字符串所以用JSON转一下
在这里插入图片描述
兄弟组件用计算属性读取本地会话的数据
在这里插入图片描述
打开开发者工具看一下数据是否成功
在这里插入图片描述
页面动态展示
在这里插入图片描述
点击商品详情进行回退和去购物车结算功能完善
在这里插入图片描述
偷组件和注册组件
在这里插入图片描述
效果图
请添加图片描述
拉取购物车列表
这里就得考虑一个问题拉取谁的数据,以及存入的时候算谁的数据,需要一个唯一持久化的标识符我们这里使用的uuid,vue项目的依赖无需下载安装
在这里插入图片描述
在商品详情的仓库中我们就进行调用获取
在这里插入图片描述
存放在本地存储里面的并且仓库也能正常拉取不删除就不会改变了
在这里插入图片描述
唯一标识符弄出来了 我们每次请求数据都给他带到后端去
我们把唯一标识符通过拦截请求头加在请求头中
在这里插入图片描述
然后我们每一次请求都会带上这个id
在这里插入图片描述
同样的仓库三连环嘛
在这里插入图片描述
组件拉取数据
在这里插入图片描述
v-for动态渲染数据
在这里插入图片描述
计算总价单独用计算属性来算
在这里插入图片描述
效果图
请添加图片描述
这里还有一个全选的问题 这里就没做响应式了
在这里插入图片描述
购物车商品详情数量处理(带正数表示加多少,带负数表示减去多少,带0不改变)
点击加减和直接修改绑定同一个函数,这里cart是vfor渲染的数据
在这里插入图片描述
先做点击按钮进行加减
在这里插入图片描述
对直接修改进行处理
在这里插入图片描述
效果图
请添加图片描述
删除购物车中商品 先写接口
在这里插入图片描述
对应的写仓库
在这里插入图片描述
组件发送删除请求并且刷新数据
在这里插入图片描述
效果图
请添加图片描述
当我们疯狂点击减的时候会出现不正常的现象我们得用节流处理一下
在这里插入图片描述
这里做一下商品状态的修改 先写接口
在这里插入图片描述
再写仓库接口
在这里插入图片描述
组件派发actions和做节流
在这里插入图片描述
效果图:
请添加图片描述
删除选中的商品
在这里插入图片描述
actions处理
在这里插入图片描述
效果图
请添加图片描述
全选按钮处理
在这里插入图片描述
checked是未改变的效果,所以跟他不一样的按钮进行替换就行
在这里插入图片描述
效果图无

八、登录注册

8.1注册功能

两个接口获取验证码和点击登录发送注册请求
在这里插入图片描述
两次仓库中定义函数都是直接返回结果让前端做处理
在这里插入图片描述
如果验证码的请求成功 直接输入到组件的输入框里面
在这里插入图片描述
组件处理 注册请求
在这里插入图片描述
效果图
请添加图片描述

8.2登录功能

1.先写接口 这里带一个配置对象data接受手机号和密码两个参数
2.写仓库
在这里插入图片描述
组件处理登录成功跳转
在这里插入图片描述
登录成功之后头部应该展示用户信息和退出登录
在这里插入图片描述
先写接口
在这里插入图片描述
在写仓库actions
在这里插入图片描述
当然我们获取用户信息需要带上token
在这里插入图片描述
我们在home组件挂载时派发actions
一刷新就失效的原因是我们的token保存在vuex中的
请添加图片描述
接下来仓库三连环把登录成功数据保存在仓库中
在这里插入图片描述
组件通过计算属性是否登录
在这里插入图片描述
在这里插入图片描述
效果图刷新失效的原因是我们没有解决token的持久化保存
请添加图片描述
接下来做token的持久化存储
我们只需要在点击登录的时候往本地仓库中存储一份再次刷新读取本地仓库
在这里插入图片描述

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

8.3退出登录

先写接口
在这里插入图片描述
在写仓库 如果成功给组件返回成功并且提交mutations
在这里插入图片描述
mutations需要清除本地的一些信息
在这里插入图片描述
在组件中接受返回结果 清除成功则进行路由跳转
请添加图片描述

8.4全局前置路由守卫

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

8.5用户地址信息展示

先写两个接口
在这里插入图片描述
仓库中保存数据
在这里插入图片描述
组件派发actions和mapState保存数据
在这里插入图片描述
动态渲染
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
-mounted发起请求,前两个计算属性拉取仓库数据,最后一个是计算商品提交的最后选中数据,methods方法切换选中状态
在这里插入图片描述
效果图
请添加图片描述

8.6提交订单功能

先写好提交订单的接口 这后面就没有使用vuex了
在这里插入图片描述

我们这里是直接把写api接口的文件直接配置成全局事件总线
在这里插入图片描述
点击提交订单携带query参数进行路由跳转
在这里插入图片描述
Pay组件计算属性获取订单号发起请求获取订单信息

效果图
请添加图片描述

8.7实现支付功能

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

npm i qrcode

这里只展示部分代码
在这里插入图片描述
通过element生产的弹窗和qrcode转换的微信支付二维码

请添加图片描述
现在实现支付功能和路由跳转 /我们需要一秒查询一次支付结果
在这里插入图片描述
效果图:
请添加图片描述
还有一些小细节问题需要进一步完善
在这里插入图片描述

8.8订单详情

先偷组件 在写路由,二级路由不需要带/
在这里插入图片描述
一定要注意些路由的出口
在这里插入图片描述
效果图:
请添加图片描述
接下来我的订单组件获取数据
在这里插入图片描述
效果图
在这里插入图片描述
动态渲染数据
在这里插入图片描述
分页器是之前search模块封装好的直接使用
在这里插入图片描述
效果图:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值