项目开发流程:
1、书写静态页面
2、拆分组件
3、获取服务器的数据动态展示
4、完成相应的动态业务逻辑
一、项目文件夹
node_modules:项目依赖文件夹
public:放置一些静态资源(图片),webpack打包的时候会原封不动打包到dist中
assests:放置静态资源,多个组件共用的,webpack打包的时候,会把里面的静态资源当做你一个模块,打包到JS文件里面。
babel-config.js:配置文件(babel相关) 可以吧es6语法翻译成es5,兼容
package.json:项目身份证,记录项目信息,有哪些依赖、怎么运行
package-lock.json:缓存性文件,记录你安装过的依赖
二、项目配置
2.1项目运行自动打开浏览器
"scripts": {
"serve": "vue-cli-service serve --open",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
在package.json文件中这段代码的serve后面加上 --open
2.2eslint校验工具关闭
eslint:检测语法是否正确
在根目录下创建vue.config.js
作用:避免不规范时浏览器报错,不然继续执行
module.exports = {
//关闭eslint(不按规范会报错)
lintOnSave: false
}
2.3src文件夹简写方法,配置别名 @
根目录下创建jsconfig.json ,用@/代替src/, ,xclude表示不可以使用该别名的文件
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*":[
"src/*"
]
}
},
"exclude": [
"node_modules",
"dist"
]
}
2.4安装依赖
–save:将保存配置信息到package.json。默认为dependencies节点中。
–dev:将保存配置信息devDependencies节点中。
dependencies:运行时的依赖,发布后,即生产环境下还需要用的模块
devDependencies:开发时的依赖。里面的模块是开发时用的,发布时用不到它。
less依赖
浏览器不会识别less样式,需要通过less、less-loader进行处理,将less样式转换成css样式
注意:版本过高会报错=>不要安装最新版本,后边加上版本号@5
npm install --save less less-loader@5
2.5项目静态资源
前端 https://gitee.com/jch1011/shangpinhui_0415.git 后台 https://gitee.com/jch1011/guigu.git
2.6清除页面默认的样式
<link rel="stylesheet" href="<%= BASE_URL %>reset.css">
三、项目路由
3.1安装路由插件vue-router
1、进入到项目文件夹,cmd
2、npm install --save vue-router
3、安装好后可以在package.json配置文件的dependencies中查看到已经有vue-router了

4、在main.js中注册,创建index.js文件进行路由配置
//1、引入vue vue-router
import Vue from 'vue'
import VueRouter from 'vue-router'
//2、使用插件
Vue.use(VueRouter)
//3、开始配置路由
//new一个vue-router对象
export default new VueRouter({
//配置路由表
routes:[]
})
错误记录:

原因:在main.js中注册路由时,先加载了router

修改:在App.vue渲染后再进行router的注册

3.2路由组件views/pages与非路由组件components
1、非路由(全局)组件放在components中,路由(页面级)组件放在pages或views中
2、在main.js注册完路由,所有的路由和非路由组件身上都会拥有$router $route属性
3.3组件路由注册的两种方式
第一种:
这种方式引入是在整个项目运行的一开始时,相关代码就会被加载进入;当项目比较大时,会加入很多与路由无关的代码
import Main from '@/Main.vue'
components: {
Main
}
第二种:
按需载入,当切换到该路由时,才进行加载
component:()=>import{'url'}
3.3组件路由跳转和传参的方式
- 跳转(两种):
(1)声明式:router-link
(2)编程式:$router.push/replace - 传参(三种):
详情:https://www.cnblogs.com/tzwbk/p/12462879.html
(1)params参数:属于路径当中的一部分,在配置路由的时候需要占位;

(2)query:不属于路径中的一部分,不需要占位;
(3)考虑页面刷新数据是否丢失!!
- 相关面试题:
(1)路由传递参数(对象写法)path是否可以结合params参数一起使用?
答:不能,常用是name与params、path与query
(2)如何指定params参数可传可不传?
答:路由配置使用了占位,但是在传递的时候没有传递params,那么url会出现问题;
可以通过在占位后面加上?(/search/:keyword?)实现params参数可传可不传。
如果路由path要求传递params参数,但是没有传递,会发现地址栏URL有问题,详情如下:
Search路由项的path已经指定要传一个keyword的params参数,如下所示:
path: "/search/:keyword",
执行下面进行路由跳转的代码:
this.$router.push({name:"Search",query:{keyword:this.keyword}})
当前跳转代码没有传递params参数
地址栏信息:http://localhost:8080/#/?keyword=asd
此时的地址信息少了/search
正常的地址栏信息: http://localhost:8080/#/search?keyword=asd
解决方法:可以通过改变path来指定params参数可传可不传
path: "/search/:keyword?",?表示该参数可传可不传
(3)params参数可传可不传,但是如果传递的是空串,如何解决?
答:
this.$router.push({name:"Search",query:{keyword:this.keyword},params:{keyword:''}})
出现的问题和1中的问题相同,地址信息少了/search
解决方法: 加入||undefined,当我们传递的参数为空串时地址栏url也可以保持正常
this.$router.push({name:"Search",query:{keyword:this.keyword},params:{keyword:''||undefined}})
(4)路由组件能不能传递props数据?
答:可以,通过在路由表的路由项中加props属性,有三种方式。
{
name: 'search',
path: '/search',
component: Search,
//路由组件能不能传递props数据?
//第一种:布尔值法,只能用params传递
//props:true,
//第二种:对象写法, 相当于额外给路由传递一组props
//props:{a:1,b:2},
//第三种:函数写法, params/query都可以传递
// props:($route)=>{
// return {keyword:$route.params.keyword}
// }
// 在跳转后的组件使用props接收使用:
// props:['keyword','a','b']
// {{keyword}}
},
(5)重复跳转路由(Avoided redundant navigation to current location)
当路由跳转到目标组件后,如果再次点击跳转,会出现如下警告,但对程序没有影响(常见面试题):
//只发生在编程式跳转中,使用导航是router-link不会出现,因为其vue-router底层已经处理好了

分析:
1、在"vue-router": "^3.5.3"版本中,引入了promise
2、push方法的理解:
push方法返回的是一个promise实例,promise需要传递resolve和reject两个参数(回调函数);但是我们在使用this.$router.push调用push方法时,这个push方法其实是VueRouter.prototype的一个方法,没有给push方法传递这两个参数,所以我们需要对它进行重写。
function push(){
return new Promise((resolve,reject)=>{
});
}
Promise知识:
https://www.cnblogs.com/lvdabao/p/es6-promise-1.html
解决:
第一种:
this.$router.push({name:‘Search’,params:{keyword:"…"||undefined}},()=>{},()=>{})
//this->VueComponent对象
//this.$router->VueRouter对象
//此时的push方法就是VueRouter实例下prototype的一个方法
//this.$router、this.$route是在组件注册时入口文件就引入的
给push方法传递相应的成功resolve、失败reject的回调函数,可以捕获到当前错误。但是这种方式解决治标不治本。
第二种:
在router的index.js文件下进行对push方法的重写
//重写push、replace方法
// 1、保存原先的push方法,此时orginPush函数上下文是window
let orginPush=VueRouter.prototype.push;
// 2、重写
VueRouter.prototype.push=function(loaction,resolve,reject){
// 函数的上下文为VueRouter类的一个实例
if(resolve&&reject){
orginPush.call(this,loaction,resolve,reject);
}else{
orginPush.call(this,loaction,()=>{},()=>{});
}
}
// 或者使用catch
// VueRouter.prototype.push = function push(location) {
// return originalPush.call(this, location).catch(err => err)
// }
// 3、重写replace
VueRouter.prototype.replace = function(loaction, resolve, reject) {
// 函数的上下文为VueRouter类的一个实例
if (resolve && reject) {
orginReplace.call(this, loaction, resolve, reject);
} else {
orginReplace.call(this, loaction, () => {}, () => {});
}
}
//区分router和$route
$router(路由器):一般进行编程式导航进行路由跳转
$route(路由): 一般获取路由信息(name path params等)
3.2路由路径不存在时
当路由的路径不匹配的时候,跳转到默认的某一路由
{
path: '/*',
redirect: '/main'
}
四、chrome装vue调试工具
https://www.cnblogs.com/feiyu159/p/8666865.html
注意:如果在执行npm install时出错,可以尝试一下方式
1、创建一个新的空文件夹,进入空文件夹中执行cmd
2、在终端输入npm install vue-devtools
3、下载完成后,会出现一个node_modules文件夹,进入此文件夹,找到其中的vue-devtools文件夹,将其中的vender文件夹拖入谷歌扩展程序中(进入谷歌浏览器,在更多工具中有个扩展程序,点击扩展程序,将右边的开发者模式打开,将文件拖进去,就会出现一个vue.js devtools扩展程序)
4、再打开verder文件夹下的manife.json文件,将persistent修改为true,保存文件,刷新谷歌浏览器。
五、Footer组件的显示与隐藏
5.1v-if与v-show的区别
5.2路由元meta的使用
六、Home主页
6.1三级联动组件(全局组件)
全局组件在main.js中注册
七、接口测试 POSTMAN
如果服务器返回的数据中code字段为200,表示服务器返回数据成功。
整个项目,接口的前缀都有/api

八、api请求
- axios的二次封装
- axios:向服务器发送请求
- 那么为什么要进行二次封装呢?
->请求拦截器:可以在发送请求之前处理一些业务;
->响应拦截器: 服务器数据返回以后,处理一些业务;
- axios安装
npm i --save axios
在src目录下新建api文件夹->request.js进行二次封装
axios文档 http://www.axios-js.com/zh-cn/docs/index.html
import axios from "axios";
const request = axios.create({
//請求配置
baseURL: '/api',
timeout: 5000
});
// 请求拦截器
request.interceptors.request.use((config) => {
// config:配置对象,包括header请求头
return config;
});
// 响应拦截器
request.interceptors.response.use((res) => {
return res.data;
}, (error) => {
return Promise.reject(new Error('faile'));
});
export default request;
- 封装
- api统一管理
将每个请求封装为一个函数,并暴露出去,组件只需要调用相应函数即可,这样当我们的接口比较多时,如果需要修改只需要修改该文件即可。
api文件夹->index.js:
import requests from "./request";
// 三级联动接口
export const reqCategoryList = () => {
//发送请求 axios发请求 返回的是promise对象
return requests({ url: '/product/getBaseCategoryList', method: 'get' });
}
在组件中导入、调用函数进行数据请求:
import {reqCateGoryList} from './api'
//发起请求
reqCateGoryList();
- 跨域问题
常见形式:JSONP、CROS、代理;
服务器之间没有跨域问题,在浏览器之间才存在这个问题;
这里使用代理来解决:
浏览器发送请求给代理服务器,服务器看到某一字段后,向target服务器请求数据
在vue.config.js中配置proxy为通过代理解决跨域问题。
我们在封装axios的时候已经设置了baseURL为api,所以所有的请求都会携带/api,这里我们就将/api进行了转换。如果你的项目没有封装axios,或者没有配置baseURL,建议进行配置。要保证baseURL和这里的代理映射相同,此处都为’/api’。
webpack中文文档 https://webpack.docschina.org/configuration/dev-server/#devserverproxy
vue.config.js->webpack.config.js
module.exports = {
//关闭eslint(不按规范会报错)
lintOnSave: false,
//代理跨域
devServer: {
proxy: {
'/api': {
target: 'http://39.98.123.211',
},
},
},
}
nprogress插件->进度条
在发送请求时,进度条往前走,服务器受理成功后,就会结束
npm i --save nprogress
nprogress对象中包含了start(),done()方法,及进度开始和进度结束;我们只要在请求拦截器和响应拦截器中调用就行;调用前需要先引入nprogress
request.js中使用:
在node_modules文件夹下的nprogress文件夹的css样式文件中可以修改进度条(bar)样式:
vuex模块化
1.引入小仓库 import xxx from ‘xxx’
2.modules:{
home,search
}

三级联动笔记还没补
js动态改变三级联动样式
事件委托
Main模块开发
-
1.三级联动 typeNav.vue
补 -
2.轮播图 listContainer.vue
2.1 mock.js模拟数据
使用步骤:
(1)npm install -s mockjs
(2)在项目当中src文件夹中创建mock文件夹
(3)准备JSON数据(相应的.json文件)注意:代码记得格式化、JSON文件和图片是默认暴露的,不需要export
(4)将mock数据中需要使用到的图片资源放在public文件夹中
(5)在mock文件夹中创建mockServe.js文件模拟数据
(6)在main.js中引入mockServe.js文件
2.2 获取banner轮播图数据
(1)在api中创建mockAjax.js,修改baseUrl为/mock
(2)在api/index.js中引入mock,并暴露请求方法
(3)在mounted()时分发,获取数据
(4)在home仓库中请求、保存数据
(5)在组件中获取仓库数组
2.3 swiper插件的使用
(1)下载swiper5 npm install --save swiper@5
(2)在组件中import swiper,在入口文件main.js引入swiper的样式,这样如果在其他地方使用到swiper就不用重复引入css文件了
(3)初始化swiper实例
2.4 banner轮播图实现
(1)使用延时器 延迟初始化swiper实例,在仓库有数据后再创建
(2)watch+nextTick
监听bannerList数据变化:由空数组–>数组里有元素。此时只是能使得仓库中数组有数据,但是因为v-for循环遍历也是需要时间的,页面结构还是没有加载出来,不能操作DOM。
这时,需要使用到$nextTick,在DOM更新完毕后调用其回调函数进行swiper实例的初始化,这样就可以保证页面中v-for循环的结构是已经存在的了。
$nextTick:将回调推迟到下一个 DOM 更新周期之后执行。在更改了一些数据以等待 DOM 更新后立即使用它。
- 3.尾部floor.vue
Search模块
- 商品分类与过度动画
添加鼠标移入移除事件;
改变v-show中表达式的值;
判断this.$route.path来源于哪里(判断条件:是否来源于Home页面);
过渡动画:前提是组件|元素必须有v-if或v-show指令才可以进行过渡


- typeNav 下拉菜单优化
问题:在主页面和search页面来回切换时(路由跳转时,旧的组件会销毁),每一次都会发送请求。
优化:在项目入口 根组件(App.vue)挂载时,发送请求。
export default {
name: "App",
components: {
Header,
Footer,
},
mounted(){
//优化:在项目入口发送一次请求,后续组件的切换不会重复请求数据
// 分发给actions,发送请求,获取三级联动数据
this.$store.dispatch("home/categoryList");
}
};
- 合并参数
为什么要?
搜索栏传递params参数、菜单栏传递query参数,当其中一个触发,携带参数跳转,而另一个也触发时,后面的触发跳转会刷新route中query与params属性。
如何合并?
提前判断query、params是否有参数,如果有的话,用一个对象将两个参数封装在一起,再进行路由跳转传参。
goSearch: function () {
let rjp = { name: "search", params: { keyword: this.searchTxt } };
if (this.$route.query) {
rjp.query=this.$route.query;
}
this.$router.push(rjp);
},

773

被折叠的 条评论
为什么被折叠?



