暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Vue2项目笔记day_02

LLL的小屋 2022-11-30
693
  1. 编程式路由跳转到当前路由(参数不变),多次执行会抛出NavigationDuplicated的警告错误【不影响程序运行,但看着烦】

    1. 路由跳转两种方式:声明式导航,编程式导航

    2. 此类错误只会出现在编程式导航中,不会出现在声明式导航中,因为vue-router底层已经处理好了

    3. 此项目中vue-router版本是3.6.5版本,引入了promise

        this.$router.push({name:'search',params:{keyword:this.keyword},query:{k:this.keyword.toUpperCase()}})
      • 上面是编程式导航写法,其中push返回promise,相当于

          function push(){ return new Promise((resolve,reject)=>{ }) }
        • 解决办法:

          1. 给push方法传递相应的成功、失败的回调函数,可以捕获到当前的错误,可以解决【只治标不治本,只能解决当前跳转错误】

              this.$router.push({name:'search',params:{keyword:this.keyword},query:{k:this.keyword.toUpperCase()}},()=>{},()=>{})
            • push不是实例;this指vc,vc身上有个VueRouter的实例叫$router,这个实例的原型(也就是VurRouter)上有个push方法。所以对原型方法push进行修改,修改结果就会作用于组件实例的$router实例。【下面是解决办法:重写push|replace方法】

                // 解决vue-router在3.0版本以上重复点报错问题
                // 先把VueRouter原型对象的push方法备份
                // 此时originalPush的this是window
                const originalPush = VueRouter.prototype.push
                const originalReplace = VueRouter.prototype.replace
                // 重写 push|replace
                // 参数:location表示告诉原来的push方法往哪里跳;resolve:成功的回调;reject:失败的回调
                // call和apply的区别
                // 相同点:都可以调用函数一次,篡改函数上下文一次【改变this指向】
                // 不同点:call传参用逗号隔开,apply传参用数组
                VueRouter.prototype.push = function push(location,resolve,reject) {
                // 如果成功和失败的回调都传了,则调用原来的push方法,即originalPush
                // 但是此时的originalPush的上下文this是window,而要求push方法的this指向VueRouter的实例,所以用call
                if(resolve && reject){
                originalPush.call(this, location,resolve,reject)
                }else{
                // 如果成功和失败的回调没传,则给原来的push方法添加成功和失败的回调:()=>{},()=>{},此时同样要保证this指向VueRouter的实例
                originalPush.call(this, location,()=>{},()=>{})
                }
                // return originalPush.call(this, location).catch(err => err)
                }
                VueRouter.prototype.replace = function replace(location,resolve,reject) {
                if(resolve && reject){
                originalReplace.call(this, location,resolve,reject)
                }else{
                originalReplace.call(this, location,()=>{},()=>{})
                }
                }
          2. 三级联动组件

            1. 此组件在home、search、detail页面都被使用,所以将三级联动组件注册为全局组件

            2. 在main.js中注册

                // 三级联动组件--全局组件
                import TypeNav from '@/pages/Home/TypeNav'
                // 参数:第一个:全局组件的名字;第二个:哪一个组件
                Vue.component(TypeNav.name,TypeNav);
              • 先在home页面使用<TypeNav></TypeNav>

            3. 拆分其他home页面组件

              1. 注意结构、样式、图片资源

            4. 测试接口

            5. axios二次封装

              1. 为什么要二次封装?

                1. 目的是为了设置请求拦截器和响应拦截器

                2. 请求拦截器:在发请求前处理一些业务

                3. 响应拦截器:在服务器数据返回后处理一些业务

              2. 安装axios【0.24.0】我这里为1.2.0


              3. 在src下新建api文件,项目中的API文件夹通常放置关于axios请求的,在里面对axios进行二次封装// 对axios进行二次封装

                  // 对axios进行二次封装


                  // 引入axios
                  import axios from "axios";


                  // 1、利用axios对象的方法create,创建一个axios实例
                  // 2、request就是axios,只不过可以稍微配置一下
                  const requests=axios.create({
                  // 配置对象
                  // 基础路径,当发请求时,路径中会自动出现/api,不用自己手动写
                  baseURL:'/api',
                  // 超时设置5s
                  timeout:5000,


                  });
                  // 请求拦截器:在发请求前处理一些业务
                  requests.interceptors.request.use((config)=>{
                  // config:配置对象,里面 headers请求头 属性很重要
                  return config;
                  })


                  // 响应拦截器:在服务器数据返回后处理一些业务
                  requests.interceptors.response.use((res)=>{
                  // 成功的回调
                  return res.data;
                  },(error)=>{
                  // 失败的回调
                  // 终结promise链
                  return Promise.reject(new Error('faile'))
                  })


                  // 对外暴露
                  export default requests;


              4. 接口的统一管理

                1. 如果项目很小,只有一两个接口,完全可以在组件的生命周期函数中发送请求

                2. 如果项目较大,有一两百个接口,使用axios.get('xxx'),但如果接口要更改,则很麻烦,所以需要接口统一管理

                3. 代码写在一个文件里,通过暴露函数,让其他模块访问接口

                    // 统一管理API接口


                    // 引入封装后的axios,即requests
                    import requests from './request'


                    // 三级联动的接口
                    // 请求地址:/api/product/getBaseCategoryList GET请求,无参数


                    // 对外暴露函数,让别的模块拿到这个函数就可以发请求了
                    // 发请求,axios发送请求返回的结果是promise对象
                    // 简写 分别暴露引入要用{}
                    export const reqCatagoryList=()=> requests({url:'/product/getBaseCategoryList',method:'get'})


                4. 跨域问题解决

                  1. JSONP

                  2. CROS

                  3. 代理服务器【√】

                    1. 配置文件中设置

                        devServer:{
                        proxy:{
                        '/api':{
                        target:'http://gmall-h5-api.atguigu.cn',
                        }
                        }
                        }


                  4. nprogress进度条

                    1. 安装


                    2. 使用

                      1. 在请求和响应拦截器里使用

                      2. 引入:

                          // 引入nprogress进度条 
                          import nprogress from 'nprogress'
                          // 引入进度条样式,颜色可以改(改源码)
                          import "nprogress/nprogress.css"
                      3. nprogress上的start方法:进度条开始,done方法:进度条结束

                          // 请求拦截器:进度条开始动
                          nprogress.start();
                          // 响应拦截器:进度条结束
                              nprogress.done()
                      4. Vuex状态管理库

                        1. 管理组件间共用的数据

                        2. 配置对象

                          1. state:仓库存储数据的地方

                          2. mutations:修改state的唯一手段

                          3. actions:处理action,可以书写自己的业务逻辑,也可以处理异步

                          4. getters:理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便

                          5. modules

                        3. 安装:【3版本】


                        4. 使用

                        5. 在src下新建store文件夹

                            import Vue from 'vue';
                            import Vuex from 'vuex';


                            // 使用Vuex
                            Vue.use(Vuex)


                            const state={};
                            const mutations={};
                            const actions={};
                            const getters={};


                            // 对外暴露Store类的一个实例
                            // Vuex其实是一个对象,对象身上有Store方法,这个方法是个构造函数,可以初始化Vue仓库
                            export default new Vuex.Store({
                            // 配置对象
                            state,
                            mutations,
                            actions,
                            getters,


                            });
                          • main.js中引入并注册store

                              // 引入Vuex的仓库
                              store import store from '@/store'
                                // 注册Vuex仓库,此时,组件实例对象身上会多一个$store属性 
                                store,
                            • vuex实现模块式开发

                              1. 当项目过大,组件过多,数据过多,接口很多,可以采用模块式开发,将大仓库拆分成多个小仓库


                              2. 在小仓库中获取api数据,交给组件

                                  // home模块的小仓库


                                  // 引入reqCatagoryList的api接口函数
                                  import {reqCatagoryList} from '@/api';
                                  // 仓库存储数据的地方
                                  const state={
                                  // 起始值【起始值不能乱写,要看服务器返回的数据是什么类型】
                                  categoryList:[],
                                  };
                                  // 修改state的唯一手段
                                  const mutations={
                                  CATEGORYLIST(state,categoryList){
                                  state.categoryList=categoryList;
                                  }
                                  };
                                  // 处理action,可以书写自己的业务逻辑,也可以处理异步
                                  const actions={
                                  // 这里可以书写业务逻辑,但是不能修改state
                                  // 通过API里面的接口函数调用,向服务器发送请求,获取数据
                                  async categoryList({commit}){
                                  // 调用api接口函数,返回的是promise对象,利用async和await,获取成功的结果
                                  let result= await reqCatagoryList();
                                  if(result.code==200){
                                  commit("CATEGORYLIST",result.data)
                                  }
                                  }


                                  };
                                  // 理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
                                  const getters={};


                                  // 对外暴露
                                  export default {
                                  state,
                                  mutations,
                                  actions,
                                  getters,
                                  }
                                • 在组件中使用

                                  1. 引入

                                      // 获取到仓库中的数据,引入mapState
                                      // 注意mapState和mapGetters是映射在计算属性里面的,而mapActions和mapMutations是映射在methods里面的
                                      import {mapState} from 'vuex'
                                    • 发送请求,接收数据

                                        // 当组件挂载完毕,就可以向服务器发请求
                                        mounted() {
                                        // 通知Vuex发请求,获取数据,存储于仓库中
                                        this.$store.dispatch('categoryList')
                                        },
                                        computed:{
                                        ...mapState({
                                        // 右侧需要的是一个函数,参数state即为大仓库中的数据
                                        // categoryList:(state)=>{
                                        // return state.home.categoryList;
                                        // },
                                        // 简写为
                                        categoryList:state=>state.home.categoryList
                                        })
                                            },
                                      • 利用插值语法将获取的数据写入页面

                                  2. 完成一级分类动态添加背景颜色

                                    1. 方法一:采用样式完成


                                    2. 方法二:采用JS完成

                                      1. 先设置data,currentIndex,用于存储用户鼠标移动到哪一个一级分类上面


                                      2. 再定义鼠标进入事件,获取索引值并更改currentIndex,根据索引添加类cur



                                      3. 最后定义cur类的样式



                                  3. 通过JS控制二三级商品分类的显示与隐藏

                                    1. 目前通过样式display:none|block实现




                                    2. 隐藏上图:hover样式后,利用JS实现



                                  文章转载自LLL的小屋,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                  评论