笔记整理——Vue2项目尚品汇

目录

一、vue-cli脚手架初始化项目各文件夹

二、 项目的其他配置

2.1 项目运行,让浏览器自动打开

2.2 eslint校验功能(各种规范的报错)的关闭

2.3 src文件夹简写方法,配置别名

2.4 样式的引入

三. 本次项目路由的分析

四. 完成非路由组件Header与Footer业务

五. 路由组件的搭建

5.1 配置路由

5.2 路由组件与非路由组件的区别?

5.3 路由的跳转的两种形式

5.4 重定向    

六. Footer组件显示与隐藏

6.1 v-if和v-show的区别

6.2 Footer组件编写

七. 路由传参

7.1 路由跳转的两种形式

7.2 路由传参(params、query)

7.3 路由传参相关问题

八. 重写push和replace

8.1 为什么编程式导航进行路由跳转时,会有这种警告错误?

九. Home首页组件拆分业务分析

9.1. TypeNav的三级联动全局组件

9.2. 完成其余静态组件

十. POSTMAN测试接口

十一. axios二次封装

11.1 为什么需要进行二次封装axios?

11.2 在项目中,经常会有API文件夹【里面存放的就是axios请求】

 十二. API接口统一管理

12.1 跨域问题

十三. nprogress进度条的使用

13.1 打开页面时,页面上方显示的进度条。

十四. Vuex状态管理库

14.1 vuex是什么?

14.2 Vuex的四个大核心概念

14.3 this.$state.dispatch与this.$state.commit的主要区别

14.4 vuex实现模块式开发的大致概念

十五. TypeNav三级联动展示数据业务

十六. 完成三级联动动态背景颜色

十七. 函数的防抖与节流【lodash插件】

17.1 卡顿现象引入函数的防抖与节流

17.2 函数防抖的理解

17.3 函数节流的理解 

十八. 三级联动

18.1 三级联动中的节流

18.2 三级联动中的路由跳转分析

18.3 用编程式导航 + 事件的委派

十九. Search模块

19.1 Search模块商品模块分类与过渡动画

19.2 typeNav商品分类列表的优化

19.3 合并query和params参数

19.4 mockjs模拟数据

19.5 获取banner轮播图的数据

二十. swiper的基本使用

20.1 Banner实现轮播图的第一种方法

二十一. 轮播图通过watch+nectTick解决问题

21.1 若只用watch监听bannerList轮播图列表的属性

21.2 用watch + this.$neckTick(较为完美的解决方案)

二十二. 获取Floor组件mock数据

22.1 组件通信的方式有哪些?

22.2 动态展示Floor组件

22.3 共用组件Carsouel(轮播图)

二十三. Search模块的静态组件

23.1 写一个模块的步骤(套路):

23.2 箭头函数

二十四. search模块中动态展示产品列表

24.1 Search模块中子组件SearchSelector.vue的动态开发

二十五. Object.assign的用法

二十六. 面包屑

26.1 面包屑处理分类的操作

26.2 面包屑处理关键字的操作

26.3 面包屑处理品牌信息

二十七.平台售卖属性的操作

27.1 子组件传给父组件(用自定义事件)

27.2 将平台售卖属性放置面包屑(数组去重)

二十八. 排序操作(上)

二十九. 操作排序——对升序降序的操作(下)

三十. 分页器静态组件(分页器原理)

三十一. 分页器起始与结束数字计算(分页器逻辑)

31.1 分页器起始与结束(分页器显示的逻辑)

31.2 分页器的动态展示(分页器按钮显示的逻辑)

31.3 分页器的完成

31.4 分页器添加类名

三十二. 产品详情页面——滚动行为

三十三. 产品详情页面数据获取

33.1 产品详情页面数据获取

33.2 产品详情页面动态展示数据

33.3 产品详情页面动态展示数据——右侧

三十四. Zoom放大镜展示数据—裁剪

三十五. detail路由组件展示商品售卖属性

三十六. 产品售卖属性值——排他操作—裁剪

三十七. 放大镜操作(上)

37.1 放大镜操作——ImageList组件和Zoom组件之间的小操作

37.2 放大镜操作——大图片随着小图片的点击也进行改变

37.3 放大镜操作——遮罩层

三十八. 购买产品个数的操作

三十九. “加入购物车”路由

39.1 ”加入购物车“按钮的步骤

39.2 路由传递参数结合会话存储(成功路由跳转与参数传递)

39.3 购物车静态组件与修改

39.4 UUID游客身份获取购物车数据

39.5 购物车动态展示数据

39.6 处理产品数量、修改购物车产品的数量完成

39.7 修改产品个数【对函数进行节流】

39.8 删除购物车产品的操作

39.9 修改产品状态

四十. 删除全部选中的商品

四十一. "全部"产品的勾选状态修改

四十二. 登录注册静态组件【重要】

42.1 注册的静态组件

42.2 登录的静态组件

42.3 携带token获取用户信息

42.4 上一节登录业务存在的问题讲解(不完美的解决办法)

42.5 退出登录

四十三. 导航守卫理解

43.1 导航守卫的判断与操作

四十四. trade交易静态组件

44.1. trade交易静态组件

44.2 用户地址信息的展示(排他思想)

44.3 交易页面完成

四十五. 提交订单(不用vuex)

45.1 提交订单静态组件(不用vuex)

45.2 提交订单(没有vuex时,可以用的方法)

四十六. 获取订单号与展示信息

四十七. 支付页面中使用Element UI以及按需引入

四十八. 微信支付业务(上)

48.1 二维码生成(插件QRCODE)

48.2 获取支付订单状态

四十九. 个人中心——二级路由搭建

五十. 我的订单

五十一. 未登录的导航守卫判断(前置守卫)

五十二. 用户登录(路由独享与组件内守卫)

52.1 路由独享守卫

52.2 组件内守卫(用得不多)

五十三. 图片懒加载(插件:vue-lazyload)

五十四. 表单验证(插件:vee-validate)【了解即可,看懂就行】

五十五. 路由的懒加载

五十六. 处理map文件、打包上线

五十七. 购买服务器等操作(先了解)

57.1 利用xshell工具登录服务器

57.2 nginx反向代理



VUE2项目尚品汇笔记

将Typora记录的笔记、以及手写的笔记进行二次整理。

整理完本次笔记,也会继续将之前学习HTML、CSS、JS、Vue的笔记进行二次整理。

方便以后查找,同时有需要改正或补充的,还请大家指教。

一、vue-cli脚手架初始化项目各文件夹

node_modules文件夹:项目依赖文件夹

public文件夹:一般放置一些静态资源(图片等)。注:放在public文件夹中的静态资源,当webpack进行打包时候,会原封不动打包到dist文件夹中

src文件夹(程序员源代码文件夹):

        assets文件夹:一般放置静态资源(一般放置多个组件共用的静态资源)。注:放置在assets文件夹里的静态资源,在webpack打包时,会把它当做一个模块,打包到JS文件里

         components文件夹一般放置的是非路由组件(全局组件)。

        App.vue:唯一的根组件,Vue当中的组件(.vue)。

        main.js:程序入口文件,也是整个程序当中最先执行的文件

babel.config.js:配置文件(babel相关)。

package.json文件:类似于项目的‘身份证’,记录项目叫什么,当中有哪些依赖,如何运行

package.lock.json文件:缓存性文件。

README.md文件:说明性文件。

二、 项目的其他配置

2.1 项目运行,让浏览器自动打开

package.json文件中配置

{
......
        "scripts": {
        "serve": "vue-cli-service serve --open",
        "build": "vue-cli-service build",
        "lint": "vue-cli-service lint"
    },
......

2.2 eslint校验功能(各种规范的报错)的关闭

eg:声明了变量,但未进行使用,则eslint校验工具会报错

  • 在根目录下创建文件vue.config.js
    module.exports = {
        //关闭eslint
        lintOnSave: false
    }

2.3 src文件夹简写方法,配置别名

①.jsconfig.json配置别名,可用@提示

【@代表的是src文件夹,常在js文件中使用。"exclude"表示“除了......”,意为配置的别名不能在"node_modules"和"dist"使用】

{
    "compilerOptions":{
        "baseUrl":"./",
        "paths":{
                "@/*":["src/*"]
            }

    //表示不能在"node_modules"和"dist"中使用这种配置的别名。
    "exclude":["node_modules","dist"]
    },

②.也可在.css中配置别名@提示 【在@前面加上~这个符号】

<style>
......
background-image: url(~@/assets/images/icons.png);
......
</style>

2.4 样式的引入

public文件夹下的index.html中引入同级reset.css样式

    <link rel="stylesheet" href="/reset.css">

三. 本次项目路由的分析

vue-router 前端的路由:KV键值对。

key:URL(地址栏中的路径) value:相应的路由组件 注:本次项目是上中下结构

  • 本次项目的路由组件可分为:

        Home首页路由组件、Search搜索路由组件、login登录路由组件、Refister注册路由组件

  • 本次项目的非路由组件可分为:

         Header组件:【存在于首页、搜索页】 Footer组件:【存在于首页、搜索页,但登录和注册页面没有】

四. 完成非路由组件Header与Footer业务

本次项目主要关注业务、逻辑。

  • 开发项目步骤:
  1. 书写静态页面(HTML+CSS)(本次项目已提前准备好了)
  2. 拆分组件(静态组件、路由组件等)
  3. 获取服务器的数据动态展示
  4. 完成相应的动态业务逻辑(eg:Js动态业务等)
  • 注意:
  1. 创建组件=组件结构 + 组件的样式 + 图片资源。
  2. 本次采用less样式。

        需通过less、less-loader【安装版本五npm install --save less less-loader@5进行处理less,将其变为css样式。

        若想让组件识别less样式,需在style标签上加上lang=less。<style lang="less" scoped>

五. 路由组件的搭建

        经过上面的分析,本次项目的路由组件有四个:

                 Home首页、Search搜索、Login登录、Register注册。

        components文件夹:经常放置非路由组件(共用的全局组件).

        pagesviews文件夹:经常放置路由组件

5.1 配置路由

项目当中配置的路由一般放置在router文件夹中的index.js里。路由配置好之后在入口文件main.js中引入。

5.2 路由组件与非路由组件的区别?

  • 共同点:

         注册完路由,不管是路由组件、还是非路由组件,它们身上都会有$route、$router属性
​            $route:一般获取路由信息【路径、query、params等】
​            $router:一般进行编程式导航,进行路由跳转【push或replace(其中一个是有缓存记忆的)】

  • 不同点:
路由组件 非路由组件(普通组件)
一般放置在pagesviews文件夹中 一般放置在components文件夹中。

一般需要在router文件夹中进行注册

(使用的名字即为组件的名字,例如router文件中的index.js的写法)

在App.vue中展示时,

用的是<router-view></router-view>

一般以标签的形式使用

(例如App.vue里的<Header></Header>标签)。

5.3 路由的跳转的两种形式

        ① 声明式导航:router-link ​

        ② 编程式导航:push或replace

        编程式导航:声明式导航能做的,编程式导航都能做;而且编程式导航不仅可以进行路由跳转,还做一些其他业务逻辑。

5.4 重定向    

        redirect重定向:在项目跑起来时就访问该页面(该方法可以立马让其定向到首页)

        在router的index.js里书写重定向代码:

  //redirect重定向:在项目跑起来时就访问该页面(该方法可以立马让其定向到首页)

//配置路由,路由的单词都是小写的
export default [
......
{
        path: '*',
        redirect: './home'
    }
......
]

六. Footer组件显示与隐藏

6.1 v-if和v-show的区别

显示or隐藏,可用v-if或者v-show。两者都是动态显示DOM元素。

v-if初始化较快,但代价较高;v-show初始化较慢,但切换成本低。

v-if v-show
动态向Dom内添加或删除DOM元素 通过设置DOM元素的display样式属性控制显示或隐藏
切换有一个局部编译/卸载的过程,过程中可能会销毁和重建内部的事件监听和子组件。 单纯地基于css切换

惰性的;

初始值为假时,不作任何操作;只有在条件第一次为真时才开始局部编译。被缓存后,再次切换时进行局部卸载。

无论首次条件是否为真,都可被编译;被缓存且DOM元素保留。
有更高的切换消耗 有更高的初始化渲染消耗
适合运营条件不大可能改变的场景 适合频繁切换的场景

6.2 Footer组件编写

本次项目在Home首页、Search搜索显示Footer组件,但是在Login登录Register注册时隐藏Footer组件。

可根据组件身上的$route获取当前路由的信息,通过路由路径判断HomeFooter这俩非路由组件的显示与隐藏。

<!-- 写法一(不推荐): -->
      <Footer v-show="$route.path=='/home'||$route.path=='/search'"></Footer>

配置路由时,可给路由添加路由元信息【meta】,注意路由配置对象的key不能乱写。

APP.vue文件中:

 <!-- 写法二: -->
      <Footer v-show="$route.meta.show"></Footer>

router文件index.js中配置【meta】

//配置路由
export default new VueRouter({
    routes: [{
            path: "/home",
            component: Home,
            meta: { show: true }
        },{
            path: "/search",
            component: Search,
            meta: { show: true }
        },{
            path: "/login",
            component: Login,
            meta: { show: false }
        },{
            path: "/register",
            component: Register,
            meta: { show: false }
        },
        //重定向:在项目跑起来时就访问该页面(该方法可以立马让其定向到首页)
        {
            path: '*',
            redirect: './home'
        }
    ]
})

七. 路由传参

了解URL语法格式

https://blog.csdn.net/Thaley/article/details/122286201

格式:protocol :// hostname[:port] / path / [;parameters][?query]#fragment

   [ ]中的内容可有可无

        即:协议 :// 主机名[:端口号] / 路径 / [;参数][?查询]#信息片断

7.1 路由跳转的两种形式

eg:A -> B

①声明式导航:router-link(务必要有to属性),<router-link to="......"></router-link>可实现路由跳转。

②编程式导航:利用组件实例的$router.pushreplace方法,可实现路由的跳转,也可书写一些自己的业务逻辑。

7.2 路由传参(params、query)

①params参数:属于路径的一部分,需注意,在配置路由的时候,需要占位

如路径的path:"/search/:keyword",/:keyword即为params参数的占位符。

②query参数:不属于路径的一部分,类似于ajax中的queryString /home?k=v&kv=, 不需占位

params参数 query参数
属于路径的一部分,需要占位 不属于路径的一部分, 不需占位
用name来引入路由 用path来引入路由
取值用法:this.$route.params.name 取值用法this.$route.query.name
有些类似于post,在浏览器地址栏中不显示参数,所以params传值相对安全一些。 类似于我们ajax中get传参,在浏览器地址栏中显示参数。
传值一刷新就没。 传值刷新还存在。

7.3 路由传参相关问题

        问1. 路由传参(对象的写法)path是否可以结合params参数一起使用?

        不能。路由跳转传参时,对象写法可为name、path形式,但是path这种写法不能与params参数一起使用。而且,路径参数缺失则无法匹配path里的占位符。

//错误写法【错误写法!】
this.$router.push({
    path:"search",
    params:{keyword:this.keyword},
    query:{k:this.keyword.toUpperCase()}
})

//应改写成:
this.$router.push({
    name:"search",
    params:{keyword:this.keyword},
    query:{k:this.keyword.toUpperCase()}
})

      

        问2. 如何指定params参数可传可不传?

        若路由要求传params参数,但未传,则URL会产生问题

  • 未传递params参数时,得到的地址情况:
......
methods:{
  this.$router.push(
    {name:"search",
    query:{
        k:this.keyword.toUpperCase()//由其他程序可得,调用toUpperCase()返回ABC
    	}
    }
  )
},
......
​
// 上面的代码,得到的地址为:http://localhost:8080/#/?k=ABC  此地址缺少了/search。

​
  • 传递了params参数时,得到的地址情况:
......
methods:{
  this.$router.push(
    {name:"search",
    params:{
        keyword:this.keyword},
    query:{
        k:this.keyword.toUpperCase()//由其他程序可得,调用toUpperCase()返回ABC
    	}
    }
  )
},
......
//​  则得到的地址为:http://localhost:8080/#/search/abc?k=ABC​   此地址有/search

        如何指定params参数可传或可不传?

        在配置路由(router文件中的index.js时),改变path,在占位的后面加上一个问号?

即:path: "/search/:keyword?"

【这里的?表示params可传递或可不传递(和正则表达式雷同,?代表出现次数为0次或1次,即可有可无)

//配置路由
export default new VueRouter({
    //配置路由
    routes: [
        {
            path: "/search/:keyword?",
            component: Search,
            meta: { show: true },
            name: "search"
        },
    ]
})

        问3. params参数可传递也可不传递,但若传递空字符串,如何解决?

        params传递空字符串也会产生URL问题。可通过在params传递的空字符串后面加上||undefined进行解决。

......
methods:{
  this.$router.push(
    {name:"search",
    params:{
        keyword:''||undefined},
    query:{
        k:this.keyword.toUpperCase()
    	}
    }
  )
},
......

        问4. 路由组件能否传递props数据?若有,有几种?

        可以。有三种写法:

this.$router.push({
    path:"search",
    params:{keyword:this.keyword},
    query:{k:this.keyword.toUpperCase()}
})
  • 方式一:props用布尔值,但只能传递params

                props: true

  • 方式二:对象写法。额外给路由组件传递一些props

                props: { a: 1, b: 2 }

  • 方式三:函数写法可通过props传递给路由组件params参数、query参数。

                props: ($route) => {

                        return { keyword: $route.params.keyword,  k: $route.query.k }

                }

引用路由传参的三种方法 - 醉温柔 - 博客园

点击当前页的某个按钮跳转到另外一个页面去,并将某个值带过去

<div class="examine" @click="insurance(2)">查看详情</div>
  • 第一种方法:页面刷新数据不会丢失。直接调用$router.push 实现携带参数的跳转。
methods:{
  insurance(id) {
       //直接调用$router.push 实现携带参数的跳转
        this.$router.push({
          path: `/particulars/${id}`,
        })
}

需要对应路由配置如下:

{
     path: '/particulars/:id',
     name: 'particulars',
     component: particulars
   }

可以看出需要在path中添加/:id来对应 $router.push 中path携带的参数。在子组件中可以使用来获取传递的参数值
另外页面获取参数如下

this.$route.params.id

  • 第二种方法:页面刷新数据会丢失。通过路由属性中的name来匹配路由,通过params来传递参数。
methods:{
  insurance(id) {
       this.$router.push({
          name: 'particulars',
          params: {
            id: id
          }
        })
  }

对应路由配置: 注意这里不能使用:/id来传递参数了,因为组件中,已经使用params来携带参数了

 {
     path: '/particulars',
     name: 'particulars',
     component: particulars
   }

子组件中: 这样来获取参数

this.$route.params.id

  • 第三种方法:使用path来匹配路由,然后通过query来传递参数。

这种情况下 query传递的参数会显示在url后面?id=?

methods:{
  insurance(id) {
        this.$router.push({
          path: '/particulars',
          query: {
            id: id
          }
        })
  }

对应路由配置:

{
     path: '/particulars',
     name: 'particulars',
     component: particulars
   }

对应子组件: 这样来获取参数

this.$route.query.id

八. 重写push和replace

--路由跳转的两种形式:①.声明式导航、②.编程式导航

为什么编程式路由跳转到当前路由(参数不变),多次执行会抛出NavigationDuplicated的警告错误?

--声明式导航没有这类问题,因为vue-router底层已经处理好了。

8.1 为什么编程式导航进行路由跳转时,会有这种警告错误?

因为最新版本的vue-router引入了promise,promise需要传递成功和失败两个参数。

1.而push的返回是一个promise,所以通过给push方法传递相应的成功、失败的回调函数,可捕获到当前错误,可以解决。

  • 方法一(治标不治本,在将来的组件当中push或replace,编程式导航还是会有类似警告错误):
this.$router.push({
    name:"search",
    params:{keyword:this.keyword},
    query:{k:this.keyword.toUpperCase()}
},()=>{},()=>{})
// ()=>{},()=>{}表示执行成功和执行失败的回调函数

2.通过底部的代码,也可实现解决错误。

  • 方法二(在router文件夹中的index.js中):
//若有成功和失败的回调,有则返回这俩值,无则自己手写() => {}
//先把VueRouter原型对象的push先保存一份
let originPush = VueRouter.prototype.push;
//先把VueRouter原型对象的replace先保存一份
let originReplace = VueRouter.prototype.replace;
//重写push|replace
//第一个参数location:告诉原来的push方法,你往哪里跳转(传递哪些参数)
//第二个参数resolve:成功回调。
//第三个参数reject:失败回调。
//call|apply区别
//相同点:都可调用函数一次,都可篡改函数的上下文一次。
//不同点:call与apply传递参数:call传递参数用逗号隔开,apply方法执行,传递数组。
VueRouter.prototype.push = function(location, resolve, reject) {
    if (resolve && reject) {
        originPush.call(this, location, resolve, reject);
    } else {
        originPush.call(this, location, () => {}, () => {})
    }
}
VueRouter.prototype.replace = function(location, resolve, reject) {
    if (resolve && reject) {
        originReplace.call(this, location, resolve, reject);
    } else {
        originReplace.call(this, location, () => {}, () => {})
    }
}

九. Home首页组件拆分业务分析

本次项目的Home首页被拆分为了七个部分。

<template>
  <div>
    <!-- 三级联动全局组件 -->
    <!-- 不需要再用import引入三级联动了,因为已经是全局组件了,可以直接使用 -->
    <TypeNav />
    <!-- 轮播图列表 -->
    <ListContainer />
    <!-- 今日推荐 -->
    <TodayRecommend />
    <!-- 商品排行 -->
    <Rank />
    <!-- 猜你喜欢 -->
    <Like />
    <!-- 楼层 -->
    <Floor />
    <!-- 商标 -->
    <Brand />
  </div>
</template>

<script>
//引入其余的组件
import ListContainer from "@/pages/Home/ListContainer";
import TodayRecommend from "@/pages/Home/TodayRecommend";
import Rank from "@/pages/Home/Rank";
import Like from "@/pages/Home/Like";
import Floor from "@/pages/Home/Floor";
import Brand from "@/pages/Home/Brand";

export default {
  name: "Home",
  components: {
    ListContainer,
    TodayRecommend,
    Rank,
    Like,
    Floor,
    Brand,
  },
};
</script>

完成步骤:

-- 先把静态(css、html)页面完成。

-- 拆分出静态组件。

-- 获取服务器的数据进行展示。

-- 若有js的动态业务,则将其完成即可。

9.1. TypeNav的三级联动全局组件

    ——由于三级联动,在Home、Search、Detai都有使用,故把三级联动注册为全局组件。优点:只需注册一次,即可在项目任意地方使用。

    ——本次讲解的组件是属于Home模块下的组件,所以暂时在pages的Home文件夹下新建个文件夹(这里取名为TypeNav)

9.2. 完成其余静态组件

需要耐心、需要注意:

HTML + CSS + 图片静态资源 —————信息的【结构、样式、图片资源】,

其文件的名字、文件引用路径需要一一对应

十. POSTMAN测试接口

利用postman工具测试接口是否正常

​        --通过postman工具测试,接口无问题。

​        --若服务器返回的数据code字段为200(此项目设置的),代表服务器返回数据成功。

​        --整个项目,接口前缀会有/api字样

十一. axios二次封装

npm官网中的axios文档:axios - npm

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

封装的方法有:XMLHttpRequest、fetch、JQ、axios

本次项目在api文件夹下的request.js文件进行axios的二次封装。

11.1 为什么需要进行二次封装axios?

​        为了请求拦截器、响应拦截器。

​        **请求拦截器**:可以在发请求之前,可处理一些业务

​        **响应拦截器**:当服务器数据返回后,可处理一些事情

安装axios : npm install axios

11.2 在项目中,经常会有API文件夹【里面存放的就是axios请求】

​        使接口中,路径都带有/api:*baseURL:"/api"

//利用axios对axios进行二次封装
//故先引入axios
import axios from 'axios'
//1.利用axios对象的方法create,创建一个axios实例
//2.request就是axios,但需要稍微进行配置。
const requests = axios.create({
    //配置对象
    //baseURL基础路径,发请求时,路径当中会出现api
    baseURL: "/api",
    //timeout代表请求超时的时间
    timeout: 5000,
});
//请求拦截器:可以在发请求之前,可处理一些业务。
requests.interceptors.request.use((config) => {
    //config:配置对象,对象中有一个属性很重要(即:headers请求头)
    return config;
})
//响应拦截器
requests.interceptors.request.use((res) => {
    //响应成功的回调函数:服务器响应数据回来之后,响应拦截器可检测到,可做一些事情
    return res.data;
}, (error) => {
    //响应失败的回调函数
    return Promise.reject(new Error('faile'));
});
//对外暴露
export default requests;

 十二. API接口统一管理

当项目很小时:完全可以在组件的生命周期函数中发请求。

当项目很大时:axios.get('xxx')

接口一般写在API文件夹的index.js文件中。

//当前模块的功能:API接口统一管理
//用到了二次封装的requests,需要将其引入
import requests from "./request";
//三级联动接口
//WORD接口文档中已经说明三级联动的接口为
// /api/product/getBaseCategoryList  methods为get   无参数
//发请求:axios发请求返回的结果是Promise对象
export const reqCategoryList = () => {
    //二次封装时,已经写了/api,所以这里不用再写/api了
    return requests({ 
        url: '/product/getBaseCategoryList', 
        method: 'get' })
} 
//上面代码=>箭头函数的简写形式
/* export const reqCategoryList = () => requests({ 
        url: '/product/getBaseCategoryList', method: 'get' 
}) */
export const reqCategoryList = () => requests.get('/product/getBaseCategoryList')

 写好接口,即可再书写仓库中的内容

12.1 跨域问题

(服务器与服务器之间是没有跨域问题的,只有浏览器与浏览器之间才有)

        问1:什么是跨域?

                协议、域名、端口号不同请求,称之为跨域。

`webpack.config.js`文件实质就是`vue.config.js`

`target`是要获取的那台服务器的IP地址

​        问2:跨域的解决方案是什么?

​        JSONP方法、CROS方法、代理(Proxy)方法【较为常用】

十三. nprogress进度条的使用

        安装nprogressnpm install --save nprogress

13.1 打开页面时,页面上方显示的进度条。

start:进度条开始

done:进度条结束

API文件夹里的request.js文件中写:

//利用axios对axios进行二次封装
//故先引入axios
import axios from 'axios'
//①.引入进度条
import nprogress from 'nprogress';
// console.log(nprogress),输出的内容其中start:表示进度条开始;done:表示进度条结束
//②.引入进度条样式
import "nprogress/nprogress.css";

//1.利用axios对象的方法create,创建一个axios实例
//2.request就是axios,但需要稍微进行配置。
const requests = axios.create({
    baseURL: "/api",
    timeout: 5000,
});

requests.interceptors.request.use((config) => {
    nprogress.start() //③.进度条开始动
    return config;
})

//响应拦截器
requests.interceptors.response.use((res) => {
    nprogress.done() //③.进度条结束
    return res.data;
}, (error) => {
    return Promise.reject(new Error('faile'));
});

//对外暴露
export default requests;

进度条的颜色可修改,在nprogress.css中修改即可。

十四. Vuex状态管理库

14.1 vuex是什么?

是官方提供的一个插件,状态管理库,集中式管理项目中组件共用的数据。

但并不是全部项目都需要Vuex,若项目很小,完全不需要;若项目很大、组件很多、数据很多,数据维护很费劲,则需要使用Vuex。Vuex可以模块化开发。

​        安装Vuex:npm install --save vuex

  • 配置仓库Vuex:在src文件夹下新建一个store的文件夹,再里面再建一个index.js文件。
  • 在入口文件main.js引入建好的仓库
  • 使用到该仓库的组件中引入{mapState} from 'vuex'映射到组件身上,成为组件的数组
  • 三连环:在actions里面提交mutations,让mutations进来修改state。

14.2 Vuex的四个大核心概念

  • ​state:仓库存储数据的地方。

​                const state = {};

  • mutation:修改state的唯一手段。

​                const mutations = {};

  • action:处理action,可书写自己的的业务逻辑,也可处理异步。

​               const actions = {};

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

​               const getters = {};

//写完接口,接着就写小仓库
import { reqCategoryList } from '@/api';
const state = {};
const mutations = {};
const actions = {};
const getters = {};
//默认暴露
export default {
    state,
    mutations,
    actions,
    getters
}

14.3 this.$state.dispatch与this.$state.commit的主要区别

dispatch:含有异步操作数据提交至actions,可用于向后台提交数据

this.$store.dispatch('action', payload);

commit:同步操作数据提交至 mutations ,可用于读取用户信息写到缓存里

this.$store.commit('add',1);

14.4 vuex实现模块式开发的大致概念

项目很大、组件很多、数据很多,数据维护很费劲,则需要使用Vuex,Vuex可以模块化开发(把大仓库变成小仓库,按模块式进行存储)

        1.可以先给每一个组件模块来一个小仓库。

        2.再将每个小仓库引入到store文件夹里的index.js(大仓库)中,用modules对外暴露,实现Vuex仓库模块式开发存储数据。

import Vue from 'vue';
import Vuex from 'vuex'
//需要使用插件一次
Vue.use(Vuex);
//引入小仓库
import home from '@/store/home';

//对外暴露Store类的一个实例
export default new Vuex.Store({
    //实现Vuex仓库模块式开发存储数据
    modules: {
        home,
    }
})

十五. TypeNav三级联动展示数据业务

前提已经将axios二次封装好了,vuex也准备好了,vuex中的模块化也准备好了。

注:项目中所有的全局组件的文件最好都放在components文件夹

多练练一眼识别几层分类的思想。

state 相当于 data(){return{}} 区域定义属性;

mutations 相当于 created()mounted() 调用方法;

actions 相当于 methods 定义方法;

getters 相当于 computed 是为了简化数据而生的。

十六. 完成三级联动动态背景颜色

  • 方法一:写鼠标事件的css样式
	.item:hover{
		background:skyblue;
	}
  • 方法二:写js
     <template>
      <div @mouseleave="leaveIndex">
        <h2 class="all">全部商品分类</h2>
        ......
           <h3 @mouseenter="changeIndex(index)">
        ......
       </div>
     </template>
     <script>
     ......
	  methods: {
	    //鼠标进入修改响应式数据currentIndex属性
	    changeIndex(index) {
  	    //index:鼠标移上某一个一级分类的元素的索引值
    	  this.currentIndex = index;
   		 },
   		//一级分类鼠标移除的事件回调
	    leaveIndex(){
	      //鼠标移除currentIndex,变为-1
  	    this.currentIndex = -1;
  		 }
	  },
     ......
     </script>
  • 通过js动态去控制二、三级分类的隐藏和显示业务

二、三级分类应有一个动态的样式,动态地显示和隐藏。

判断条件:只要谁有类名,谁就应该显示;currentIndex是否等于当前的索引值index。

:style="{display:currentIndex==index?'block':'none'}"

代码如下:

<template>
	......
	  <!-- 事件委派|事件代理 -->
      <div @mouseleave="leaveIndex">
        <h2 class="all">全部商品分类</h2>
        <!-- 三级联动 -->
        <div class="sort">
        ......
        	<!-- 二级、三级分类 -->
        	<div class="item-list clearfix"  
                :style="{display:currentIndex==index?'block':'none'}">
	......
</template>

十七. 函数的防抖与节流【lodash插件】

17.1 卡顿现象引入函数的防抖与节流

    ● 卡顿:由于用户的行为过快,导致浏览器反应不过来。若当前回调函数中有一些大量业务,则可能出现卡顿现象。

        ○ 正常情况下(用户慢慢操作):鼠标一进入每一个一级分类的h3,触发鼠标进入事件,可正常执行。

        ○ 非正常情况下(用户操作过快):本身全部的一级分类都应该触发鼠标进入事件,但经测试,只有部分h3触发了。

    ● 防抖:前面的所有的触发都被取消,最后一次执行在规定的时间之后才会触发即若连续快速地触发,也只会执行最后一次

    ● 节流:规定的间隔时间范围内不会重复触发回调,只有大于这个事件间隔才会触发回调,频繁触发变为少量触发,使浏览器有充分时间解析代码

17.2 函数防抖的理解

    ● 防抖:前面的所有的触发都被取消,最后一次执行在规定的时间之后才会触发,即若连续快速地触发,也只会执行最后一次

        安装lodash.jsnpm install --save lodash

防抖事例代码_.debounce

input.oninput = _.debounce(function() {
      console.log('ajax发请求')
 }, 1000)//放个延时器

防抖事例进行使用:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>防抖</title>
    <!-- 引入lodash:lodash全部的功能引入 -->
    <script src="js/lodash.js"></script>
</head>
<body>
    <p>请输入搜索内容:<input type="text"></p>
</body>
</html>

<script>
    //防抖:前面的所有触发都被取消,最后一次执行在规定时间之后才会触发,即若连续快速的触发,只会执行一次。
    let input = document.querySelector('input');
    //文本发生变化立即执行
    /*     input.oninput = function() {
            console.log('ajax发请求')
        } */
    input.oninput = _.debounce(function() {
            console.log('ajax发请求')
        }, 1000)
        //lodash插件:里面封装函数的防抖与节流的业务【闭包+延迟器】
        //1.lodash函数库对外暴露的是_函数
</script>

17.3 函数节流的理解 

    ● 节流:规定的间隔时间范围内不会重复触发回调,只有大于这个事件间隔才会触发回调,频繁触发变为少量触发,使浏览器有充分时间解析代码

        安装lodash.jsnpm install --save lodash

节流事例用代码_.throttle

    button.onclick = _.throttle(function() {
        //节流:目前这个回调函数5s执行一次
        //加入这里有很多的业务代码,是可以给浏览器充裕的时间进行解析的。
        count++;
        span.innerHTML = count;
        console.log('执行');
    }, 5000);

节流事例进行使用:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>节流</title>
    <!-- 引入lodash:lodash全部的功能引入 -->
    <script src="js/lodash.js"></script>
</head>
<body>
    <div>
        <h1>我是计数器<span>0</span></h1>
        <button>点我加一</button>
    </div>
</body>
</html>

<script>
    //节流:在规定的间隔时间范围内不会重复触发回调,只有大于这个事件间隔才会触发回调,把频繁触发变为少量触发。
    //获取节点
    let span = document.querySelector('span');
    let button = document.querySelector('button');
    let count = 0;
    //计数器:在一秒以内,数字只能加上1
    button.onclick = _.throttle(function() {
        //节流:目前这个回调函数5s执行一次
        //加入这里有很多的业务代码,是可以给浏览器充裕的时间进行解析的。
        count++;
        span.innerHTML = count;
        console.log('执行');
    }, 5000);
</script>

十八. 三级联动

18.1 三级联动中的节流

throttle回调函数别用箭头函数,否则可能出现上下文this的问题。

......
methods: {
..........
      changeIndex:throttle(function(index) {
      //index:鼠标移上某一个一级分类的元素的索引值  
      this.currentIndex = index;
    },50),
          .......
}
......

18.2 三级联动中的路由跳转分析

三级联动用户的分类:一级分类、二级分类、三级分类

Home模块跳转到Search模块,一级会把用户选中的产品(产品名字、产品ID)在路由跳转的时候进行传递。

路由跳转的两种方式:

①.声明式导航:router-link

在本次项目中,router-link容易出现卡顿问题。

②.编程式导航:push|replace

本次较好的解决方案:编程式导航 + 事件委派

18.3 用编程式导航 + 事件的委派

解决方案:用编程式导航 + 事件委派  完成三级联动的路由跳转与传递参数的业务

利用事件委派存在一些问题以及解决方法

①.点击的不一定都是a标签

        利用自定义属性data-categoryname解决,区分是否为a标签,带有data-categoryname这样的节点【一定是a标签】。

②.如何获取子节点参数【产品名、产品id】
      节点有一个属性dataset属性,可获取节点的自定义属性与属性值。
      通过categoryname区分是否为a标签通过category1id、category2id、category3id区分是否为一级、二级、三级标签。再通过函数中传入的event参数,获取当前点击事件,通过event.target属性获取当前节点通过dataset属性获取节点属性信息

<template>
......
	<div class="all-sort-list2" @click="goSearch" @mouseleave="leaveIndex">
	......
    </div>
......
</template>

<script>  
......
methods{
......
   //进行路由跳转的方法
    goSearch(event){
      //最好的解决方案:编程式导航 + 事件委派
      //利用事件委派存在一些问题:①.点击的不一定都是a标签    ②.如何获取参数【产品名、产品id】
        console.log(event.target)
    }
......
}
</script>  

通过categoryname区分是否为a标签通过category1id、category2id、category3id区分是否为一级、二级、三级标签。再通过函数中传入的event参数,获取当前点击事件,通过event.target属性获取当前节点通过dataset属性获取节点属性信息

<template>
    ........
              <h3 @mouseenter="changeIndex(index)">
                <a 
                    :data-categoryName="c1.categoryName" 
                    :data-category1Id="c1.categoryId">
                {
  { c1.categoryName }}--{
  { index }}
                </a>
              </h3>
              <!-- 二级、三级分类 -->
              <div 
                    class="item-list clearfix"  
                    :style="{display:currentIndex==index?'block':'none'}">
                <!-- 因为:Key里已经有categoryId了,所以不用写index -->
                <div
                  class="subitem"
                  v-for="(c2, index) in c1.categoryChild"
                  :key="c2.categoryId">
                  <dl class="fore">
                    <dt>
                      <a 
                        :data-categoryName="c2.categoryName" 
                        :data-category2Id="c2.categoryId">
                      {
  { c2.categoryName }}--{
  { index }}
                      </a>
                    </dt>
                    <dd>
                      <em v-for="c3 in c2.categoryChild" :key="c3.categoryId">
                        <a 
                            :data-categoryName="c3.categoryName" 
                            :data-category3Id="c3.categoryId">
                        {
  { c3.categoryName }}
                        </a>
                      </em>
                    </dd>
                  </dl>
                </div>
              </div>
    ........
</template>
<script>
    ........
        goSearch(event){
      //最好的解决方案:编程式导航 + 事件委派
      //利用事件委派存在一些问题:①.点击的不一定都是a标签    ②.如何获取参数【产品名、产品id】
      // this.$router.push('/search')
      let element = event.target;
      console.log(element)
      //获取到当前触发这个事件的节点【h3、a、dt、dl】,需带有data-categoryname这样的节点【一定是a标签】
      //节点有一个属性dataset属性,可获取节点的自定义属性与属性值。
      
      // 通过categoryname区分是否为a标签,通过category1id,category2id,category3id区分是否为一级、二级、三级标签
      let {categoryname,category1id,category2id,category3id} = element.dataset;
      //如果标签身上拥有categoryname,则一定是a标签
      if(categoryname){
        //整理路由跳转的参数
        let location = {name:"search"}
        let query = {categoryname:categoryname}
        //一级分类、二级分类、三级分类
        if(category1id){
          query.category1Id =category1id;
        }else if(category2id){
          query.category2Id =category2id;
        }else if(category3id){
          query.category3Id =category3id;
        }
        //整理完参数
        // console.log(location,query)
        location.query=query;

        //将其加入路由跳转
        this.$router.push(location);
      } 
    }
    ........
</script>

十九. Search模块

19.1 Search模块商品模块分类与过渡动画

全局组件可直接使用,不需引用

Search模块中  typeNav三级联动商品分类菜单  的过渡动画效果

过渡动画:前提组件、元素务必要有v-if或v-show指令才可以进行过渡动画。

1).判断是否为某个路由组件(可用路径判断)

<templayte>
......
   	<div @mouseleave="leaveShow" @mouseenter="enterShow">
	......
	</div>
......
</templayte>
......
<script>
......
    //当鼠标移入时,让商品分类列表进行展示
    enterShow(){
      if(this.$route.path !="/home"){
      this.show = true
      }
    },

    //当鼠标离开时,让商品分类列表进行隐藏
    leaveShow(){
      this.currentIndex = -1
      if(this.$route.path !="/home"){
      this.show = false
      }
    }
......
</script>
  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
重构Vue2项目Vue3可以按照以下步骤进行: 1. 首先,创建一个新的Vue3项目。可以使用命令行或者Vue CLI来创建一个空的Vue3项目。 2. 接下来,将Vue2项目的目录与创建的Vue3项目的目录进行对比。可以查看两个项目的目录结构和文件,找出需要迁移的文件和目录。 3. 逐步将Vue2项目的文件迁移到Vue3项目中。根据对比结果,修改不合适的地方,使其适配Vue3。可能需要更改的地方包括路由配置、组件引用、语法等。 4. 如果原先的Vue2项目中使用了一些Vue周边的库,需要确保这些库在Vue3项目中也能正常使用。可以查看这些库的官方文档或社区讨论,了解它们是否已经适配了Vue3,并按照相应的指导进行配置和迁移。 总之,重构Vue2项目Vue3需要创建一个新的Vue3项目,对比和迁移文件,并根据需要修改适配的部分。同时,还需确保原先使用的Vue周边库在Vue3项目中能够正常工作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [使用Vue3重构vue2项目](https://blog.csdn.net/qiwoo_weekly/article/details/109192667)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值