Vue项目--尚品汇笔记

Vue项目–尚品汇

项目简介

1.1前台项目

技术架构:vue+webpack+vuex+vue-router+axios+less…

主要内容:封装通用组件、登入注册、token、守卫、购物车、项目性能优化等。

1.2后台项目

技术架构:vue+webpack+vuex+vue-router+axios+scss+elementUI…

主要内容:elementUI、菜单权限、按钮权限、数据可视化等。

1.3实际代码

源码在gitee中,链接在此: https://gitee.com/marygood/vue-project-sph/tree/master/app

1.day01

1.1开发准备

在项目当前目录下,输入cmd,打开命令行提示符,再输入vue create app,安装vue2脚手架(前提是已安装npm)。

1.2项目文件夹功能介绍

  • node_modules文件夹:放置项目依赖的地方。

  • public文件夹:一般放置一些共用的静态资源(图片)。需要注意的是webpack进行打包的时候,public文件夹里面的内容会原封不动打包到dist文件夹里面。

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

    assets文件夹:放置静态资源(一般放置多个组件共用的静态资源),需要注意的是webpack进行打包时会把静态资源当作一个模块,打包到JS文件夹里面。

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

    App.vue:唯一的根组件。

    main.js:入口文件(程序最先执行的文件)。

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

    注:babel的作用是将JS语法进行解析,把高版本的语法解析为低版本的语法,主要是用于兼容。

  • package.json:项目的身份证。记录项目名称、项目中有哪些依赖、项目如何运行等。

  • package-lock.json缓存性文件。

  • README.md项目说明文件,依赖是哪里来的都给你记录了。

1.3项目配置

  1. package.json文件中设置项目运行浏览器自动打开

    //package.json
    "scripts": {
        "serve": "vue-cli-service serve --open", //项目运行完自动打开浏览器
        "build": "vue-cli-service build",
        "lint": "vue-cli-service lint"
    }
    
  2. vue.config.js文件中关闭eslint校验功能

    //vue.config.js
    module.exports = {
       lintOnSave:false,
    }
    
  3. vue.config.js中设置浏览器打开的IP地址及端口号。

    //vue.config.js
    module.exports = defineConfig({
     // 设置浏览器打开的IP地址及端口号
      devServer: {
        open: true,
        host: 'localhost',
        //这里因为8080端口已经被占用,如果没被占用忽略此步
        port: 8000
      }
    })
    
  4. src文件夹的别名的设置(现在的版本已经有这项配置)

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

1.4项目路由的分析

vue-router
前端所谓路由:KV键值对。
Key:URL(地址栏中的路径)
value:相应的路由组件
注意:项目是上中下结构

跳转的时候只有中间部分在发生变化,所以中间部分应该使用的是路由组件。
路由组件:
Home、Search、Login登录路由(没有底部的Footer组件–带有二维码的)、Register注册路由
非路由组件:
Header 【首页、搜索页】
Footer【首页、搜索页】,但是登入、注册页是没有的

1.5创建非路由组件Header与Footer业务

项目开发的时候:
1.书写静态页面(html+css)
2.拆分组件
3.获取服务器的数据动态展示
4.完成相应的动态业务逻辑
注意:
1.创建组件的时候需要:组件结构 + 组件样式 + 图片资源 
  注:复制粘贴的时候一部分一部分来。
2.本项目采用less样式,但是浏览器不识别,所以需要通过安装less、less-loader进行处理。
  注:此处安装的是npm i less-loader@5
3.安装完成之后,还是会报错,想让组件识别less样式,需要在style标签上添加lang="less"。

使用组件的步骤(非路由组件):
第一步:创建或定义
第二步:引入
第三步:注册
第四步:使用

1.6路由组件的搭建

安装vue-router注意安装@3版本(vue2只能安装3版本)
路由组件有四个:Home、Search、Login、Register
components文件夹:经常存放的是非路由组件(共用全局组件)
pages或views文件夹:经常存放路由组件
1.6.1路由的配置
项目当中配置的路由一般放在router文件夹中
router文件夹中创建index.js文件
需要引入Vue和VueRouter
然后暴露路由实例,然后里面配置对象(路由)----就是写一个个对象,里面是path和component
之后将要暴露的路由组件引入–对象中需要告诉路径path和组件component
之后需要路由文件执行一次,路由文件需要在入口文件main.js中注册
1.6.2小结
问:路由组件与非路由组件的区别?
1.路由组件放在pages或views中,非路由组件放在components中。
2.路由组件一般需要在router文件夹中进行注册,而非路由组件一般都以标签的形式使用。(重要)
3.注册完路由不管是路由组件还是非路由组件,都会拥有$route,$router属性。
$route:一般获取路由信息【路径、query、params等】
$router:一般进行编程式导航、路由跳转【push或replace】
1.6.3路由的跳转
路由的跳转就两种形式:
声明式导航router-link和编程式导航push|replace都可以进行路由跳转.
编程式导航更好用,声明式导航可以做的编程式导航都可以做,并且编程式导航除了路由跳转,还可以在路由跳转之前做一些其他的业务逻辑。

1.7Footer组件显示与隐藏

显示和隐藏组件:v-if或v-show(后者更好)
Footer组件在主页和搜索页显示,在登入和注册页隐藏。

面试题:
v-show与v-if区别?
v-show:通过样式display控制。
v-if:通过元素上树与下树进行操作,操作DOM,效率低。

我们可以根据组件身上的$route获取当前路由的信息,通过路由路径判断是否显示或隐藏。

// 第一种写法
<Footer v-show="$route.path == '/home' || $route.path == '/search'" />
// 第二种写法(优化写法)
<Footer v-show="$route.meta.show" />

配置路由时,如果想添加自定义内容时可以给路由添加路由元信息【meta】。

// router/index.js文件
// 第二种写法需要的配置
routes: [
	{
		path: "/home",
		component: Home,
		meta: { show: true }
	},
	{
		path: "/login",
		component: Login,
		meta: { show: false }
	},
	...都要配置meta...
]

1.8路由传参

1.8.1实践代码
params参数:属于路径中的一部分,在配置路由时需要占位。
query参数:不属于路径中的一部分,写法类似于ajax当中queryString(/home?k=v&k=v),不需要占位。
// components/Header/index.vue文件
// 小写是parans参数,大写是query参数(带问号的键值对形式)
goSearch() {
      // 路由传参
      // 第一种字符串形式
      /* this.$router.push(
        "/search/" + this.keyword + "?k=" + this.keyword.toUpperCase()
      ); */
      // 第二种模板字符串
      /* this.$router.push(
        `/search/${this.keyword}?k=${this.keyword.toUpperCase()}`
      ); */
      // 第三种对象写法,params要在router/index.js中配置name
      this.$router.push({
        name: "search",
        params: {
          keyword: this.keyword,
        },
        query: {
          k: this.keyword.toUpperCase(),
        },
      });
    },
//router/index.js文件
{
      name: "search",
      // params需要占位
      path: "/search/:keyword",
      component: Search,
      meta: { show: true }

},
1.8.2路由传参面试题
1.路由传递参数(对象写法)path是否可以结合params参数一起使用?
答:不可以。路由跳转传参时,对象的写法可以是name或者path,但是path写法不能与params参数一起使用。

2.如何指定params参数可传可不传?
答:在配置路由的时候,在占位的后面加上一个问号。path: "/search/:keyword?"

3.params参数可以传递也可以不传递,但是如果传递的是空串,该怎么解决?
答:使用undefind解决。
{ name: 'search', params: { keyword: ' ' || undefined }, query: {...} }

4.路由组件能不能传递props数据?
答:可以。
第一种:布尔值方式,不过这种写法只能传递params参数。
在配置路由的时候加上 { props: true }
同时在组件中用 props: ['keyword'] 接收,组件中就可以直接写{{ keyword }},不用写$route.params.XXX。
Header中该传的还得传:this.$router.push("/search/" + this.keyword);

第二种:对象写法,简单讲就是额外给路由组件传递一些参数。
props: { a: 1, b: 2 }

第三种:函数写法,可以传递params参数和query参数,通过props传递给路由组件,最常用。
这种方法也是为了组件获取参数方便,可以直接写{{ keyword }}、{{ k }}。
不过这里老师推荐最开始的写法。(建议使用模版字符串)
props: ($route) => {
	return {
		keyword: $route.params.keyword,
		k: $route.query.k
	}
}

1.9后续报错

之前我们为了去除默认样式在public文件夹中引入了resset.css文件。由于在reset.css文件中引入不存在的iconfont.css文件产生报错,所以我们要把@import "./iconfont.css";语句注释掉,不再引入不存在的文件。

2.day02

2.1重写push和replace方法(了解)

1.编程式导航路由跳转到当前路由(参数不变), 多次执行会抛出NavigationDuplicated的警告错误?
-路由跳转由两种形式:编程式导航(push|replace)、声明式导航router-link
-声明式导航是没有这种问题,因为vue-router底层已经处理好了。

1.1 编程式导航为什么会出现这种警告现象?
答:由于vue-router版本3.5.2,引入了promise。
1.2解决方案(其实不管这个警告也可以)
第一种解决方案:给push函数传入相应的成功、失败的回调,捕获当前错误。不过这种方案治标不治本。
components/Header/index.vue文件
this.$router.push(
  {
    name: "search",
    params: { keyword: this.keyword },
    query: { k: this.keyword.toUpperCase() },
  },
  () => {},
  () => {}
);
第二种解决方案:治标治本。
router/index.js文件
//先把VueRouter原型对象的push方法,先保存一份
let originPush = VueRouter.prototype.push
let originReplace = VueRouter.prototype.replace
//重写push和replace方法
//第一个参数:告诉原来的push方法,你往哪跳转(传递哪些参数)
//第二个参数是成功的回调,第三个是失败的回调
VueRouter.prototype.push = function (location, resolve, reject) {
//这里面的this还是VueRouter的实例
if (resolve && reject) {
// call与apply
// 相同点:都可以调用一次函数,都可以篡改函数的上下文一次
// 不同点:call传递参数用逗号隔开,apply方法执行,传递数组。
originPush.call(this, location, resolve, reject)
} else {
originPush.call(this, location, () => { }, () => { })
}
}
//同样的重写replace方法
VueRouter.prototype.replace = function (location, resolve, reject) {
if (resolve && reject) {
originReplace.call(this, location, resolve, reject)
} else {
originReplace.call(this, location, () => { }, () => { })
}
}

2.2Home模块组件

把Home模块拆分为三级联动、轮播图与快报、猜你喜欢、商品展示等组件。

2.2.1三级联动组件的完成
// main.js文件
// 注册全局组件
// 三级联动组件--全局组件
import TypeNav from '@/pages/Home/TypeNav'
// 第一个参数:全局组件的名字,第二个参数:哪个组件
Vue.component(TypeNav.name, TypeNav)

new Vue({
 render: h => h(App),
 router,
 //注册全局组件
 TypeNav,
}).$mount('#app')
// 注意:注册为全局组件之后,在使用该组件时不用再二次注册。
2.2.2其余静态组件完成
HTML + CSS +图片资源 => 放入相应的位置即可。

2.3测试接口

apifox软件下载地址是https://apifox.com/#pricing,直接点击免费下载即可。

在apifox软件上测试,老师使用的那个软件不是很好用。在get栏中输入如下网址:
http://gmall-h5-api.atguigu.cn/api/product/getBaseCategoryList
出现200即请求成功。
说明:
http://gmall-h5-api.atguigu.cn(这是服务器)
/api/product/getBaseCategoryList(这是接口)

2.4axios二次封装

向服务器发请求的方式有很多:XMLHttpRequest原生的构造函数、fecth、JQ、axios。
1.问:为什么需要二次封装axios?
答:为了请求拦截器和响应拦截器。请求拦截器可以在发送请求之前处理一些业务,响应拦截器可以在服务器返回数据后处理一些业务。
2.在项目中经常在src/api文件夹下放【axios】
接口中路径都带有/api,为避免重复书写,在axios中配置baseURL:"/api"。
3.如果不了解axios的基础知识,可以参考git|NPM中关于axios的文档。
下方为axios二次封装配置文件。
// src/api文件夹下的request.js文件

//对axios进行二次封装
import axios from 'axios'

//1.利用axios对象的方法create,去创建一个axios实例
//2.request就是axios,只是就行了一些配置
const requests = axios.create({
//配置对象
//基础路径,发请求的时候,路径中会出现api
baseURL: '/api',
// 请求超时的时间为5秒,超出5s停止请求
timeout: 5000
})

//请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些处理
requests.interceptors.request.use((config) => {
//config:配置对象,对象里面有一个属性很重要,headers请求头
return config;
})

//响应拦截器
requests.interceptors.response.use((res) => {
//响应成功的回调函数:服务器响应数据回来以后,响应拦截器可以检测到,可以做一些事情
return res.data
}, (error) => {
//响应失败的回调函数
return Promise.reject(new Error(error))
})

//对外暴露
export default requests

2.5接口统一管理

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

项目较大:axios.get('xxx')

// src/api/index.js文件

//当前模块将所有的API进行统一管理
import requests from "@/api/request";

// 三级联动接口 /api/product/getBaseCategoryList  get请求  无参数

// axios发请求返回结果是promise对象
// 下面是axios发送对象请求的方式(三级联动发送数据请求)
export const reqCategoryList = () => requests({ url: '/product/getBaseCategoryList', method: 'get' })
// vue.config.js文件
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
 transpileDependencies: true,
 lintOnSave: false,
 devServer: {
   //通过代理服务器解决跨域问题。
   proxy: {
     'api': {
       target: 'http://gmall-h5-api.atguigu.cn'
     }
   }
 }
})
//在mian.js文件中进行测试
//测试发送请求
import { reqCategoryList } from './api' //注意看看使用什么暴露,对应使用什么引入
reqCategoryList()
//会发现上面报404错误----跨域了----需要去配置代理服务器

2.6nprogress进度条的使用

安装nprogress插件:在vs终端输入npm i nprogress

// src/api文件夹下的request.js文件

//对axios进行二次封装
import axios from 'axios'
// 引入进度条插件
import nprogress from 'nprogress'
// start进度条开始 done进度条结束
// 引入进度条样式
import "nprogress/nprogress.css"

//1.利用axios对象的方法create,去创建一个axios实例
//2.request就是axios,只是就行了一些配置
const requests = axios.create({
//配置对象
//基础路径,发请求的时候,路径中会出现api
baseURL: '/api',
// 请求超时的时间为5秒,超出5s停止请求
timeout: 5000
})

//请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些处理
requests.interceptors.request.use((config) => {
//config:配置对象,对象里面有一个属性很重要,headers请求头
nprogress.start()
return config;
})

//响应拦截器
requests.interceptors.response.use((res) => {
//响应成功的回调函数:服务器响应数据回来以后,响应拦截器可以检测到,可以做一些事情
nprogress.done()
return res.data
}, (error) => {
//响应失败的回调函数
return Promise.reject(new Error(error))
})

//对外暴露
export default requests

2.7vuex状态管理库

安装vuex:在vs终端输入npm i vuex@3.6.2

vuex是官方提供的一个插件:状态管理库,集中管理项目中组件共有的数据,达到共享资源的目的。(简单理解就是它相当于一个仓库)
vuex的核心:state、 mutations、 actions、getters、modules
注意:
不是所有项目都需要vuex,小项目不需要,大项目需要。

建立store文件夹,在该文件夹下建立总的index.js文件,再在该文件夹下建立Home和Search两个子文件夹,在两个子文件夹下再分别建立index.js文件。

// main.js文件
import Vue from 'vue'
import App from './App.vue'
// 三级联动组件--全局组件
import TypeNav from '@/pages/Home/TypeNav'
// 第一个参数:全局组件的名字,第二个参数:哪个组件
Vue.component(TypeNav.name, TypeNav)
// 引入路由
import router from '@/router'
// 引入仓库
import store from '@/store'

Vue.config.productionTip = false

new Vue({
 render: h => h(App),
 // 注册路由:组件都会拥有$route,$router属性
 router,
 // 注册仓库:组件实例对象身上会多出一个$store属性
 store,
}).$mount('#app')

// store/index.js文件
import Vue from 'vue'
import Vuex from 'vuex'
//使用插件
Vue.use(Vuex)
//引入小仓库
import home from './home'
import search from './search'

/* //state:仓库存储数据的地方
const state = {}
//actions:响应组件中用户的需求,可以书写业务逻辑,也可以处理异步
const actions = {}
//mutations:处理state的唯一手段
const mutations = {}
//getters:相当于计算属性,简化仓库数据,让组件获取仓库中的数据更加方便
const getters = {} */

// 对外暴露Store的一个实例对象
export default new Vuex.Store({
 /* state,
 actions,
 mutations,
 getters, */

 // 注册小仓库 实现vuex仓库的模块式开发
 modules: {
   home,
   search
 }
})
// store/home/index.js
// home小仓库
const state = {}
const mutations = {}
const actions = {}
const getters = {}

export default {
 state,
 mutations,
 actions,
 getters
}
// store/search/index.js文件
//search小仓库
const state = {}
const mutations = {}
const actions = {}
const getters = {}

export default {
 state,
 mutations,
 actions,
 getters
}

2.8动态展示三级联动数据

这里把之前做的全局组件内容放到了components文件中(所有的全局组件都要放到这个文件中)。

// main.js文件
// 三级联动组件--全局组件
import TypeNav from '@/components/TypeNav'

注:采用命名空间的写法不会报错。

// store/home/index.js
// home模块的小仓库
import { reqCategoryList } from "@/api"
const home = {
 namespaced: true, // 开启命名空间
 state: {
   categoryList: []
 },
 mutations: {
   CATEGORYLIST(state, categoryList) {
     state.categoryList = categoryList
   }
 },
 actions: {
   // 通过api里面的接口函数调用,向服务器发送请求,获取服务器的数据
   async categoryList({ commit }) {
     let result = await reqCategoryList()
     if (result.code == 200) {
       commit("CATEGORYLIST", result.data)
     }
   }
 },
 getters: {}
}

export default home
<!-- components/TypeNav/index.js文件 -->
<template>
...
         <div
           class="item"
           v-for="c1 in categoryList.slice(0, 15)"
           :key="c1.categoryId"
         >
           <h3>
             <a href="">{{ c1.categoryName }}</a>
           </h3>
           <div class="item-list clearfix">
             <div
               class="subitem"
               v-for="c2 in c1.categoryChild"
               :key="c2.categoryId"
             >
               <dl class="fore">
                 <dt>
                   <a href="">{{ c2.categoryName }}</a>
                 </dt>
                 <dd>
                   <em v-for="c3 in c2.categoryChild" :key="c3.categoryId">
                     <a href="">{{ c3.categoryName }}</a>
                   </em>
                 </dd>
               </dl>
             </div>
           </div>
         </div>
...
</template>

<script>
import { mapState } from "vuex";
export default {
 name: "TypeNav",
 // 组件挂载完毕:可向服务器发送请求
 mounted() {
   // 通知vuex发请求,获取数据,存储于仓库中
   this.$store.dispatch("home/categoryList");
 },
 computed: {
   ...mapState("home", ["categoryList"]),
 },
};
</script>

3.Day03

3.1节流与防抖

节流:在规定的间隔事件范围内不会重复触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发。【可以给浏览器充裕的时间解析代码】

防抖:前面的所有触发都被取消,最后一次执行在规定的时间之后才会触发,也就是说如果连续快速触发,只会执行一次。

lodash插件:里面封装函数的防抖与节流的业务【闭包+延迟期】
会引入包的同时还要会手写
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- 引入lodash -->
  <script src="lodash.js"></script>
</head>

<body>
  <div>
    输入内容:<input type="text">
  </div>
  <script>
    let input = document.querySelector('input')
    // 文本发生变化立即执行
    input.oninput = _.debounce(function () {
      console.log('@')
    }, 1000)
    // lodash插件:里面封装函数的防抖与节流的业务【闭包+延迟期】
  </script>
</body>

</html>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="lodash.js"></script>
</head>

<body>
  <div>
    <h3>计时器<span>0</span></h3>
    <button>点击加一</button>
  </div>
  <script>
    let span = document.querySelector('span')
    let button = document.querySelector('button')
    let count = 0
    button.onclick = _.throttle(function () {
      count++
      span.innerHTML = count
      console.log('@')
    }, 2000)
  </script>
</body>

</html>

3.2三级联动的节流

<!-- components/TypeNav/index.js文件 -->
// 对lodash按需引入 默认暴露不用加大括号
// 使用时不要写箭头函数【this指向问题】 
// 这里由于我之前运用的是css样式所以没有使用
// import throttle from "lodash/throttle";

3.3三级联动组件的路由跳转与参数传递

三级联动用户可以点击:一级分类、二级分类、三级分类。
点击的时候Home模块跳转到Search模块,以及会把用户选中的产品(产品名字,产品的ID)在路由跳转的时候,进行传递。

路由跳转的方式:
声明式导航router-link
可以实现路由跳转与传递参数,但是需要注意,会出现卡顿现象。
router-link:是一个组件,当服务器的数据返回之后,循环出很多router-link组件(创建组件实例),需要大量内存,因此卡顿。

编程式导航push|replace
单纯的运用编程式导航,需要逐个添加click事件,导致事件处理函数还是很多。

最好的路由跳转方式是编程式导航+事件委派,只需给最外层添加click事件。
但事件委派存在着两个问题:
问题1:如何知道点击的一定是a标签?
问题2:如何知道点击的a标签属于哪级【一共三级】?
答:利用自定义属性解决上述两个问题。

4.Day04

4.1TypeNav菜单过渡动画效果

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

4.2三级列表优化

在App根组件中发送请求【根组件mounted】执行一次。

4.3mockjs模拟数据

安装mockjs:npm i mockjs

作用:生成随机数据,拦截ajax请求。

特点:前端mock数据不会和你的服务器进行任何通信。

4.4Banner轮播图

第一种解决方法是添加延时器。

setTimeout(() => {
   var mySwiper = new Swiper(".swiper-container", {
     slidesPerView: 1,
     spaceBetween: 30,
     loop: true,
     pagination: {
       el: ".swiper-pagination",
       clickable: true,
     },
     navigation: {
       nextEl: ".swiper-button-next",
       prevEl: ".swiper-button-prev",
     },
   });
 }, 500);

第二种解决方案是使用swiper。

第一步:引包(引入相应的js文件与css文件)
第二步:完善页面中的结构(必须要有)
第三步:new Swiper实例【轮播图添加动态效果】

4.6总结

在这里插入图片描述

5.Day05

请添加图片描述

请添加图片描述

在这里插入图片描述

6.Day06

设计组件通信

请添加图片描述

请添加图片描述

7.Day07

请添加图片描述

请添加图片描述

8.Day08

1)分页器业务
前端三大件:轮播图、分页、日历。这属于前端开发常见三种业务

1.1:为什么很多项目中都采用分页功能?
比如电商平台:搜索一个奶粉,奶粉的产品有10000+,一次渲染10000+条数据,可能慢。
数据多的时候,可以选择分页,比如每一次只是展示10

1.2拆分分页组件(静态组件),注册为全局组件,因为其他模块也在使用分页功能。

2)分页器封装业务分析
封装分页器组件的时候:需要知道哪些条件?
假如你知道条件1、条件2:知道一共多少页 100/3
1:分页器组件需要知道我一共展示多少条数据 ----total【100条数据】

2:每一个需要展示几条数据------pageSize【每一页3条数据】

3:需要知道当前在第几页-------pageNo[当前在第几页]

4:需要知道连续页码数【起始数字、结束数字:连续页码数市场当中一般5、7、9】奇数,对称好看 continues

已经条件: total=【99】 pageSize =【3】 pageNo=6 continues 5

4 5 6 7 8

已经条件: total=【99】 pageSize =【3】 pageNo= 1 continues 5

错误:-1 0 1 2 3
正确: 1 2 3 4 5

已经条件: total=【99】 pageSize =【3】 pageNo= 2 continues 5

错误: 0 1 2 3 4
正确:1 2 3 4 5

已经条件: total=【99】 pageSize =【3】 pageNo= 33 continues 5

错误: 31 32 33 34 35
正确:29 30 31 32 33

已经条件: total=【99】 pageSize =【3】 pageNo= 32 continues 5

错误:30 31 32 33 34
正确: 29 30 31 32 33

3)分页器封装
3.1进行单元测试

连续页码5: 8 [6,7,8,9,10]
连续页码7: 8 [5,6,7,8,9,10,11]

连续页码5: 8 [6,7,8,9,10]
连续页码7: 8 [5,6,7,8,9,10,11]

//正常情况:再回来因该还是第一页【遇见脑袋xxxx产品可能有这种操作】

总结
对于一个分页器:
1.需要知道数据总条数
2.每一个需要展示数据条数
3.知道当前是第几页
4.连续页码数字
5.自定义事件【子给父通信的】

4)数据解释

售卖产品属性的展示与选择,采用排他操作,在工作中经常使用。

{ attr:'颜色', attrValue:['红色','黑色','白色'] }

5)push与replace区别?
编程式导航:push 与 replace
能不能记录历史记录:push(能记住历史记录) replace(不能记住历史记录)
目前项目当中:进行路由跳转(编程式导航)基础都是push
push与replace是有区别的

6)项目当中控制台

vue-warn:对于你的代码提出一个警告;对于程序没有任何影响,俗称假报错。

9.Day09重要

请添加图片描述

请添加图片描述

在这里插入图片描述

10.Day10重要

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

token面试题:项目当中token过期、失效如何处理?

答:清除本地token(本地存储),让用户回到登录页,获取最新的token。

11.Day11

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

12.Day12

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

7)个人中心【二级路由搭建】

13.Day13

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

路由懒加载:

把不同路由对应的组件分成不同的代码块,当路由被访问时再加载对应的组件。

app\src\router.js文件
//注意:最上面最开始的引入要去掉
{
    path: "/home",
    component: ()=>import("@/views/Home"),
    meta: { show: true }
  },

在这里插入图片描述

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值