目录
项目初始化
1.vue-cli脚手架初始化项目
2.项目的其他配置
3.项目路由分析
5.完成路由组件搭建
7.路由传参
7.3?路由传参面试题
Home模块组件拆分
1.三级联动组件
2.?完成其余静态组件
3.postman测试接口
4.axios二次封装
5.接口统一管理
6.nprogress进度条的使用
6. vuex状态管理库
8.卡顿现象
8.1 节流
8.2 防抖
9.三级联动组件的路由跳转与传递参数
Home模块收尾
3.合并params和query参数
4.开发Home首页中的ListContainer组件与Floor组件
4.1?mockjs使用步骤
5.?swiper
6.ListContainer组件开发
7.Floor组件的开发
7.3?组件通信的方式
8.将轮播图拆分成公用的全局组件
Search模块开发
1.Object.assign()
2.面包屑问题
3.分页器
Detial模块开发
1.1?路由设置
登录与注册业务
1. 静态组件
2.注册业务
3.登录业务
4.token令牌
5.?登录【已token】
6.?退出登录
7.支付订单页面
8.提交订单
9.图片懒加载
9.2自定义插件
10.表单验证
11.路由懒加载
12.打包上线
12.1?nginx
项目初始化
1.vue-cli脚手架初始化项目
node + webpack + 淘宝镜像
node_modules文件夹:项目依赖文件夹
public文件夹:一般放置一些静态资源(图片),需要注意,放在public文件夹中的静态资源,webpack进行打包的时候会原封不动的打包到dist文件夹中
src文件夹(程序员源代码文件夹): ? ? -assets文件夹:一般也是放置静态资源(一般放置多个组件共用的静态资源),需要注意,放置在assets文件夹里面的静态资源,在webpack打包的时候,webpack会把静态资源当做一个模块,打包JS文件夹里 ? ? -components文件夹:一般放置非路由文件(全剧组件) ? ? -App.vue:项目中唯一的根组件,Vue当中的组件(.vue) ? ? main.js:程序入口文件,整个程序的中最先执行的文件
babel.config.js:配置文件(babel相关)
package.json:记录项目信息(项目身份证)
package-lock.json:缓存性文件
README.md:说明文件
2.项目的其他配置
2.1 项目运行起来的时候让浏览器自动打开
---package.json文件中更改
"scripts": {
"serve": "vue-cli-service serve --open",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
2.2 eslint校验功能关闭
---在根目录下创建vue.config.js文件
modules.exports = {
//关闭eslint
lintOnSave:false,
}
比如:声明变量但是没有使用,eslint校验工具报错
2.3?src文件夹简写方式,配置别名 @
---在根目录下创建jsconfig.json文件,配置别名@,@代表的是src文件夹,这样将来文件过多找的时候方便很多。
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*" :[
"src/*"
]
}
},
"exclude": [
"node_modules",
"dist"
],
}
3.项目路由分析
vue-router
前端所谓路由:KV键值对
key:URL(地址栏中的路径)
value:响应的路由组件
目前的路由组件:Home、Search、Login、Register
非路由组件:Header、Footer(Login、Register页面没有Footer)
4.完成非路由组件Header和Footer业务
开发项目时
- 书写静态页面(HTML + CSS)
- 拆分组件
- 获取服务器的数据动态展示
- 完成相应的动态业务逻辑
注意1:创建组件的时候,组件结构 +?组建形式 +?图片资源 注意2:项目采用less样式,浏览器不识别less样式,需要通过less、less-loader(5版本)进行处理,变成css样式,浏览器才可以识别 注意3:如果想让浏览器认识less样式,需要在style标签加 lang = "less"?
4.1?使用组件的步骤(非路由组件)
-创建或定义
-引入
-注册
-使用
5.完成路由组件搭建
vue-router
路由组件:Home、Search、Login、Register
-components一般放置非路由组件
-pages |?view文件夹一般放置路由组件
5.1?配置路由
项目当中配置的路由一般放置router文件夹中
router中index.js
//配置路由地址
import Vue from 'vue';
import VueRouter from 'vue-router'
//使用插件
Vue.use(VueRouter);
//引入路由组件
import Home from '@/pages/Home'
import Search from '@/pages/Search'
import Login from '@/pages/Login'
import Register from '@/pages/Register'
//配置路由
export default new VueRouter ({
routes:[
{
path:"/home",
component:Home
},
{
path:"/search",
component:Search
},
{
path:"/login",
component:Login
},
{
path:"/register",
component:Register
},
//重定向:在项目拍起来的时候,访问/,立刻让他定向到首页
{
path:"*",
redirect:"/home"
}
]
})
main.js注册路由
import Vue from 'vue'
import App from './App.vue'
//引入路由
import router from '@/router'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
//注册路由:写法是KV一致省略V,而且router是小写的
//注册路由信息:当这里书写router的时候,组件身上都拥有$route $router属性
router
}).$mount('#app')
5.2?小结
路由组件与非路由组件的区别
1.路由组件一般放在pages |?view文件夹 ? ?非路由组件一般放置component
2.路由组件一般需要router文件夹中进行注册(使用的即为组件的名字),不需要在componen里再注册了,使用时用
3.注册完路由,不管是路由组件还是非路由组件,身上都有$route和$router属性
$route:一般获取路由信息(路径、query、params等)
$router:一般进行编程式导航路由跳转(push、replace)
5.3?路由跳转
路由跳转有两种形式
声明式导航router-link,可以进行路由的跳转
编程式导航push、replace,可以进行路由跳转
编程式导航:声明式导航能做的,编程式导航都能做
编程式导航除了进行路由跳转,还可以有其他业务逻辑
6. Footer组件显示与隐藏
显示或隐藏组件:v-if 、v-show
Footer组件:在Home、Search显示;在Login、Register隐藏
6.1?可以根据组件身上的$route.path?获取路由信息,判断显示与隐藏
6.2?配置路由的时候,可以给路由添加原信息(meta),路由需要配置对象
{
path:"/home",
component:Home,
meta:{show:true}
},
7.路由传参
7.1 路由跳转的几种方式
声明式导航:router-link(一定要有to属性),实现路由跳转
编程式导航:利用的是组件实例的$router.push / replace方法,可以实现路由跳转(可以书写自己的业务)
7.2?路由传参,参数有几种写法
params参数:属于路径中的一部分,在配置路由的时候需要在占位
query参数:不属于路径中的一部分,类似于ajax中的queryString? (/home?k=v&k=v)
//methods里放gosearch
goSearch() {
//路由传参
//第一种:字符串形式
// this.$router.push('/search/' + this.keyword +'?k='+this.keyword.toUpperCase());
//第二种:模板字符串
// this.$router.push(`/search/${this.keyword}?k=${this.keyword.toUpperCase()}`);
//第三种:对象写法
this.$router.push({name:"search",params:{keyword:this.keyword},query:{k:this.keyword.toUpperCase()}})
}
7.3?路由传参面试题
1.路由传递参数(对象写法)path是都可以结合params参数一起使用?
不可以,使用params参数一定要给路由设置name
2.如何指定params参数可传可不传?
比如:配置路由时已经占位了(params参数),但是路由跳转的时候就不传递
路径会出现问题?
http://localhost:8080/#/?k=QWE,按理来说他应该是 http://localhost:8080/#/search?k=QWE
如果想让params参数可传可不传,可以在配置路由的时候在参数后边加个问号
3.params参数可以传递也可以不传递,但是如果传递是空串如何解决?
传递空串路径还是会出问题
这时使用undefined解决:params参数可以传递也可以不传递(空字符串) =>??'? ' ||undefinded
this.$router.push({name:"search",params:{keyword:''||undefinded},query:{k:this.keyword.toUpperCase()}})
4.路由组件能不能传递props数据?
可以,有三种写法
1.在配置路由时配置 props:true?,但是这种方法只能传递params参数
router?index.js
{
path:"/search/:keyword?",
component:Search,
meta:{show:true},
name:"search",
//7.3路由组件能不能传递props数据
//布尔值写法:只能传递params参数
//props:true,
},
search?index.vue?接收props参数
params参数 {
{$route.params.keyword}}
query参数 {
{$route.query.k}}
props{
{keyword}}
2.对象写法:额外的给路由组件传递的一些props
props:{a:1,b:2}
3.函数写法(常用):可以params参数、query参数、通过props参数传递
props:($route) => {
return {keyword:$route.params.keyword,k:$route.query.k}
}
7.4?注意
1.编程式路由跳转到当前路由(参数不变),多次执行会抛出NavigationDuplicated的警告错误
--路由跳转有编程式导航和声明式导航
--声明式导航没有上述警告,因为vue-router底层已经处理好了
1.1 为什么编程式导航有这种问题?
--"vue-router": "3.5.3"引入了promise,push方法执行返回的而是promise,新的一轮promise没有接收到成功or失败的值,所以会有警告
1.2 解决:在push方法传参的时候加两个() => {},目的是为了传递响应的成功、失败的回调函数,可以捕获当前错误
this.$router.push({name:"search",params:{keyword:''||undefinded},query:{k:this.keyword.toUpperCase()}},() => {} ,()=> {})
但是治标不治本
1.3
this:当前组件实例(search)
this.$router属性:当前的这个属性,属性值是VueRouter类的一个实例,当在入口文件注册路由的时候,给组件实例添加的$router $route这个属性
push方法:VueRouter类的一个实例
1.4?重写push方法
//先把VueRouter原型对象的push,保存一份
let originPush = VueRouter.prototype.push;
let originReplace = VueRouter.prototype.replace;
//重写push replace方法
//第一个参数:告诉原来的push方法往哪里跳转(传递哪些参数)
//第二个参数:成功的回调 第三个参数:失败的回调
VueRouter.prototype.push = function(location,resolve,reject){
if(resolve && reject) {
//call apply区别
//相同点:都可以调用函数一次,都可以篡改函数的上下文一次
//不同点:call与apply传递参数,call传参用逗号隔开,apply传参用数组
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模块组件拆分
--完成静态页面
--拆分出静态组件
--获取服务器的数据进行展示
--动态业务
1.三级联动组件
--由于三级联动在Home、Search、Detail都使用到了,所以把三级联动注册为全局组件
好处:只需要注册一次,就可以在项目任意地方使用
main.js
import TypeNav from '@/pages/Home/TypeNav'
//第一个参数:全局组件的名字 第二个参数:哪一个组件
Vue.component(TypeNav.name,TypeNav)
2.?完成其余静态组件
HTML+CSS+资源
3.postman测试接口
经过postman工具测试,接口是没问题的
如果服务器返回的数据code字段200,代表服务器返回数据成功
整个项目,接口前缀都有api?
4.axios二次封装
XMLHttpRequest、fetch、JQ、axios
4.1 为什么要二次封装axios
请求拦截器:可以在发请求之前可以处理一些业务
响应拦截器:当服务器数据返回之后可以处理一些业务
4.2?项目中的API文件夹
一般用来放axios的
接口当中:路径都带有api
baseURL:“/api”? //基础路径,发请求的时候路径当中都会出现api,就不用自己写了
4.3?如果axios基础不好,可以参考npm和axios文档
5.接口统一管理
如果项目很小:完全可以在组件的盛行周期函数中发请求
如果项目很大:接口统一管理
5.1?跨域问题
跨域:协议、域名、端口号有一个不同
http://localhost:8080/? ? ?---前端本地服务器
http://39.98.123.211? ? ? ?---后台服务器
解决:JSONP、CORS、代理
代理跨域
vue.config.js
module.exports = {
//关闭eslint
lintOnSave:false,
devServer: {
//代理跨域
proxy: {
'/api':{
target:'http://39.98.123.211',
//pathRewrite:{'^/api':''},
},
},
},
}
6.nprogress进度条的使用
一有请求,进度条就开始使用
安装nprogress插件再引入
request.js
//对于axios进行二次封装
import axios from "axios";
//引入进度条
//start:进度条开始 done:进度条结束
import nprogress from 'nprogress'
//引入进度条样式
import "nprogress/nprogress.css"
//1.利用axios对象方法create,去创建一个axios实例
//2.request就是axios,只不过可以稍微配置一下
const requests = axios.create({
//配置对象
//基础路径,发请求的时候路径当中都会出现api,就不用自己写了
baseURL:'/api',
//代表请求超时的时间为5s
timeout:5000,
});
//请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config) => {
//config:配置对象,对象里面有一个属性很重要,header请求头
//进度条开始动
nprogress.start();
return config;
});
//响应拦截器
requests.interceptors.response.use((res) => {
//服务器成功的回调函数:服务器响应数据回来以后,响应拦截器可以检测到,可以做一些事情
//进度条结束
nprogress.done();
return res.data;
},(error) => {
//响应失败的回调函数
//终结promise链
return Promise.reject(new Error('false'));
});
//对外暴露
export default requests;
6. vuex状态管理库
6.1?vuex是什么
vuex官方插件,状态管理库,集中式管理项目中组件共用的数据
并不是全部的项目都需要vuex,如果项目很小,完全不需要vuex;如果项目很大,组建很多数据很多维护费劲,就需要
vuex核心概念:state、mutations、actions、getters、modules
6.2?vuex的基本使用
store/search/index.js
//search模块的小仓库
//state:仓库存储数据的地方
const state = {};
//mutations:修改state的唯一手段
const mutations = {};
//actions:处理action,可以书写自己的业务逻辑,也可以处理异步
const actions = {};
//getters:理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
const getters = {};
export default {
state,
mutations,
actions,
getters
}
6.3?vuex实现模块开发
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
//需要使用插件
Vue.use(Vuex)
//引入小仓库
import home from './home'
import search from './search'
//对外暴露store类的一个实例
export default new Vuex.Store({
//实现vuex模块化
modules:{
home,
search,
}
})
7.完成TypeNav三级联动展示数据业务
获取服务器真实的数据进行展示
store/home/index.js
//home模块的小仓库
import { reqCategoryList } from "@/api";
const state = {
//state中的数据默认初始值别乱写,服务器返回的是对象就是对象,服务器返回的是数组就是数组
categoryList:[],
};
const mutations = {
CATEGORYLIST(state, categoryList) {
state.categoryList = categoryList
}
};
const actions = {
//通过api里面的接口函数调用,向服务器发请求获取服务器数据
async categoryList({ commit }) {
let result = await reqCategoryList();
if (result.code ==