1.设置@为src文件,便于在之后引入时方便操作。
在根目录下建立jsconfig.json文件,将如下代码放进去。
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}
2.拆解页面结构
将Header和Footer这种始终非路由组件,放在components文件夹下,建立相应文件夹,内部装有Header.vue文件。
至于路由组件,在src文件夹下建立pages文件夹,将对应路由组件放在此文件夹下。
3.搭建组件的注意点
1.在移动代码时,要注意样式和图片。关于样式,因为本项目利用less书写样式,在引入时,加上lang="less"。对于图片,在相应文件夹下建立images文件夹。
2.不要忘记将reset.css,移动到public文件夹下,并引入,才能此样式生效。
4.实现Footer组件只在Home和Search组件下显示
<Footer v-show="$route.meta.show"/> //利用route中的meat属性
{
path:'/home',
component:Home,
meta:{show:true}
}
5.编程式路由导航
定义一个方法,使用push,如果需要传参,在后面加相应参数即可(params记得占位)
this.$router.push({
name:'search',
params:{keyword:'你好啊'}
query:{k:this.keyword} // query传参是键值对的形式
})
6.如何指定params参数可传可不传,如果传递空串如何解决?
在配置路由时,在占位的后面加上一个问号即可实现。
path:'/search/:keyword?'
传递空串的时候,用undefined解决问题。
this.$router.push({
name:'search',
params:{keyword:'' || undefined}
})
7.多次点击按钮传参会报错,如何解决?
重写push方法,如果resolve或者reject没有回调函数,则添加一个回调即可。
import VueRouter from 'vue-router'
//重写push方法
let originPush = VueRouter.prototype.push
VueRouter.prototype.push = function(location,resolve,reject){
if(resolve && reject){
originPush.call(this,location,resolve,reject)
} else{
originPush.call(this,location,()=>{},()=>{})
}
}
8.三级联动组件声明为全局组件
//全局注册组建
import TypeNav from '@/components/TypeNav'
// 传递两个参数(组件的名字,哪一个组件)
Vue.component(TypeNav.name,TypeNav)
全局组件注册完成后,在引入时不需要import和声明components
9.对于axios进行二次封装
在src文件夹下建立api文件夹,创建request.js文件。
1.设置baseURL和timeout
import axios from "axios";
const requests = axios.create({
baseURL:'/api',
timeout:5000 //访问大于5s取消
})
2.设置请求拦截器和响应拦截器。
//引入nprogress
import nprogress from "nprogress";
//引入nprogress样式
import 'nprogress/nprogress.css'
//设置请求拦截器,并且加上进度条。
requests.interceptors.request.use(function (config) {
nprogress.start()
return config;
}, function (error) {
return Promise.reject(error);
});
// 设置响应拦截器
requests.interceptors.response.use(function (response) {
nprogress.done()
return response.data;
}, function (error) {
return Promise.reject(error);
});
10.API接口统一管理
在api文件夹下建立index.js
import requests from './request'
//三级联动axios发请求
export const reqCategoryList = () =>
requests({ url: 'product/getBaseCategoryList', method: 'get' })
设置访问接口函数后,在main.js中引入
// 引入reqCategoryList
import {reqCategoryList} from '@/api'
进行跨域代理操作,实现本地接口与目标接口连接
//配置代理跨域
devServer: {
proxy: {
"/api": {
target: "http://39.98.123.211",
},
},
},
11.使用vuex完成三级联动
1.如果项目过大,state内数据过多不便查看,可以在store文件夹下设置小库再引入。引入时不再引入state,而是引入modules:{home,search}
//创建action,mutation,state,getter对象
const state = {
a:1
}
const actions = {}
const mutations = {}
const getters = {}
export default {
actions,
mutations,
state,
getters
}
import Vue from 'vue'
import Vuex from 'vuex'
//引入小仓库
import home from './home'
import search from './search'
Vue.use(Vuex)
export default new Vuex.Store({
actions,
mutations,
modules: {
home,
search,
},
getters
})
2.配置vuex,在home.js中完成请求数据。
//引入请求数据的函数,分别暴露一定要记得加{}
import {reqCategoryList} from '@/api'
//创建action,mutation,state,getter对象
const state = {
categoryList:[]
}
const actions = {
//reqCategoryList()请求回来是一个Promise函数,所以用async和await
async categoryList({commit}){
let result = await reqCategoryList()
if(result.code == 200){ //如果请求成功,result.code就是200
commit('CATEGORYLIST',result.data)
}
}
}
const mutations = {
CATEGORYLIST(state,categoryList){
state.categoryList = categoryList //将数据交给state
}
}
const getters = {
}
export default {
actions,
mutations,
state,
getters
}
3.在TypeNav中配置计算属性,再在页面中使用。
import { mapState } from "vuex"; //引入mapState要记得加{}!烦死了
computed: {
...mapState({
categoryList: (state) => state.home.categoryList,
}), //vuex会传递state到函数中,得到下面小库中的内容即可
},
4.对于1级、2级、3级标题进行遍历,得到所有标题
v-for="(c1, index) in categoryList" :key="c1.categoryId"
v-for="(c2, index) in c1.categoryChild" :key="c2.categoryId"
v-for="(c3, index) in c2.categoryChild" :key="c3.categoryId"
5.利用js设置hover效果:对于h标题添加@mouseenter和@mouseleave事件传递参数(index),设置this.currentIndex = index;(记得设置初始currentIndex = -1)
为父盒子div设置动态类:class="{ cur: currentIndex == index }"
最后设置cur的backgroudcolor,即可实现hover效果。
6.利用js实现2、3级标题的显示与隐藏:为2级标题设置动态style。
:style="{display:currentIndex == index? 'block' : 'none'}"
12.点击商品分类,给search传递参数
难点:需要知道到底是点的是不是a标签(如果不是就不传),是哪个a标签。
1.首先将每个a标签上都添加一个统一的自定义属性名,便于我们判断是否点击的是a标签。
:data-categoryName="c2.categoryName"
2.将每个a标签上也添加一个各自的id属性,便于我们判断点击的是几级标签。
:data-category2Id = "c2.categoryId"
3.给div设置一个goSearch方法,配置方法。
goSearch(event) {
// 得到点击事件的标签,比如点了h1标签a就是h1标签。
let a = event.target;
// 通过解构赋值得到自定义属性值,属性值都是小写的,这里要注意。
let {categoryname,category1id,category2id,category3id} = a.dataset
//因为点击的a标签上都有categoryname,所以做if判断
if(categoryname){
// 准备需要传参的数据
let location = {name:'search'}
let query = {categoryName:categoryname}
// 如果是点击1级标题就带一级id,之后同理
if(category1id){
query.category1Id = category1id
} else if(category2id){
query.category2Id = category2id
}else if(category3id){
query.category3Id = category3id
}
location.query = query
//判断一下有没有params参数,如果有也放在location里
if(this.$route.params){
location.params = this.$route.params
}
// 路由跳转
this.$router.push(location)
}
},