尚品汇电商项目

一. 项目介绍

1.vue前台项目

技术结构

技术架构:
vue + webpack + vuex + vue-router + axios + less. .
● 封装通用组件
● 登录注册
● token
● 守卫
● 购物车
● 支付
● 项目性能优化…

2.vue后台管理系统

技术结构

技术架构:
vue + webpack+ vuex + vue- router + axios + scss + elementUI…
● elementUI
● 菜单权限
● 按钮权限
● 数据可视化…

3.数据可视化

echarts数据可视化开源库
canvas画布.
svg矢量图

二. 项目初始化

在这里插入图片描述)

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: 说明性文件

1.项日的其他配置

  1. 项目运行起来的时候,让浏览器自动打开—package.json
    在这里插入图片描述
    vue.config.json
devServer: {
    host: "localhost",
    port:8080,
    }
  1. eslint校验功能关闭。
    在这里插入图片描述
  2. src文件夹简写方法,配置别名。
    jsconfig.json配置别名@提示[@代表的是src文件夹,这样将来文件过多,找的时候方便]

在这里插入图片描述

三.项目路由

1.项目路由的分析

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

  • 路由组件:
    Home首页路由组件、Search路由组件、login登 录路由、Refister注册路由
  • 非路由组件:
    Header [首页、搜索页]
    Footer [在首页、搜索页],但是在登录|注册页面是没有
    在这里插入图片描述

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

1:书写静态页面(HTML + CSS)
2:拆分组件
3:获取服务器的数据动态展示
4:完成相应的动态业务逻辑
注意1:创建组件的时候,组件结构+组件的样式+图片资源

在这里插入图片描述
在这里插入图片描述
index.vue里面写模板

<template>
  
</template>

<script>
export default {

}
</script>

<style>

</style>

在App.vue里配置

<template>
  <div id="app">
    <Header/>
  </div>
</template>

<script>
import Header from './components/Header'
export default {
  name: 'App',
  components: {
    Header
  }
}
</script>

3. 完成路由组件的搭建

路由history hash
npm i vue-router@3
在这里插入图片描述
配置路由
新建router文件
在这里插入图片描述
配置路由

// 配置路由的地方
import Vue from 'vue';
import VueRouter from 'vue-router';
// 使用插件
Vue.use(VueRouter);
// 引入路由组件
import Home from '@/pages/Home'
import Search from '@/pages/Search'
import Register from '@/pages/Register'
import Login from '@/pages/Login'
// 配置路由
export default new VueRouter({
    // 配置路由
    routes: [
        {
            path: "/home",
            component:Home
        },
        {
            path: "/search",
            component:Search
        },
        {
            path: "/register",
            component:Register
        },
        {
            path: "/login",
            component:Login
        }
    ]

})

到main.js里引入路由
在这里插入图片描述
在这里插入图片描述

总结
路由组件与非路由组件的区别?
1 :路由组件-般放 置在pages |views文件夹,非路由组件一般放置components文件夹中
2:路由组件一般需要在router文件夹中进行注册(使用的即为组件的名字),非路由组件在使用的时候,一般都是以标签的形式使用
3:注册完路由,不管路由路由组件、还是非路由组件身上都有$ route,$router 属性
$route:-般获取路由信息[路径、query、params等等]
$router:一般进行编程式导航进行路由跳转[push|replace]
路由的跳转?
路由的跳转有两种形式:
1.声明式导航router-link,可以进行路由的跳转

<router-link to="./login">登录</router-link>
<router-link  to="./register" class="register">免费注册</router-link>

2.编程式导航push|replace,可以进行路由跳转

<button class="sui-btn btn-xlarge btn-danger" type="button" 
@click="goSearch">搜索</button>

<script>
export default {
name:"",
methods:{
    // 搜索按钮的回调函数:需要向search路由进行跳转
    goSearch(){
        this.$router.push('./search')
    }
}
}
</script>

编程式导航:声明式导航能做的,编程式导航都能做,但是编程式导航除了可以进行路由跳转,还可以做一些其他的业务逻辑。

4. Footer组件显示与隐藏

显示或者隐藏组件:v-if|v-show
Footer组件:在Home、 Search显示Footer组件
Footer组件:在登录、注册时候隐藏的
1. 我们可以根据组件身上的$route获取当前路由的信息,通过路由路径判断Footer显示与隐藏。
2. 配置的路由的时候,可以给路由添加路由元信息[meta]

<Footer v-show="$route.meta.show"/>
    {
            path: "/home",
            component: Home,
            meta:{show:true}
        },

5.路由传参

search/index.vue

<h1>params{{$route.params.keyword}}</h1>
<h1>query{{$route.query.k}}</h1>
//路由传递参数:
//第一种:字符串形式
//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()}})
{
path :"/search/:keyword", //配置路由,声明接收params参数 ( 使用占位符声明接收params参数 )
component: Search,
meta:{show:true},
name :"search" //第三种需要配置
},

路由传参面试题

1:路由传递参数(对象写法)path是否可以结合params参数一起使用?
 //答:路由跳转传参的时候,对象的写法可以是name、path形式,但是需要注意的是,path这种写法不能与params参数一起使用
this.$router.push({path:'/search',params:{keyword:this.keyword},query:{k:this.keyword.toUpperCase()}})
2:如何指定params参数可传可不传?
//如果路由要求传递params参数,但是你就不传递params参数,发现一件事情,URL会有问题的
http://localhost:8080/#/?k=QWE   //实际错误
http://localhost:8080/#/search?k=QWE   //想象传递
//如何指定params参数可以传递、或者不传递,在配置路由的时候,在占位的后面加上一个问号params可以传递或者不传递【path :"/search/:keyword?",】
3:params参数可以传递也可以不传递,但是如果传递是空串,如何解决?
//使用undefined解决: params 参数可以传递、不传递(空的字符串)
this.$router.push({path:'/search',params:{keyword:''||undefined},query:{k:this.keyword.toUpperCase()}})

4:路由组件能不能传递props数据?
{
path: "/search/ : keyword?"component: Search,
meta : { show:true},
name: " search"//路由组件能不能传递props数据?
//布尔值写法:只能传递params参数
//props:true,
//对象写法:额外的给路由组件传递一些props
// props:{a:1,b:2},
//函数写法:可以params参数、query参数,通过props传递给路由组件  页面获取{{keyword}} {{k}}
props:($route)=>({keyword:$route.params.keyword,k:$route.query.k})
}

6.重写push和replace

1:编程式路由跳转到当前路由(参数不变),多次执行会抛出NavigationDuplicated的警告错误?
– 路由跳转有两种形式:声明式导航、 编程式导航
–声明式导航没有这类问题的,因为vue-router底层已经处理好了
1.1为什么编程式导航进行路由跳转的时候,就有这种警告错误那?
“vue-router”: “^3.5.3”: 最新的vue -router引入promise
function push(){
return new Promise( (resolve , reject)=>{
})
1.2通过给push方法传递相应的成功、失败的回调函数,可以捕获到当前错误,可以解决。
1.3通过底部的代码,可以实现解决错误
this . $router . push( {name :”search", params : {keyword: this. keyword} , query : {k:this . keyword . toUpperCase()}},()=>{},()=>{}); I
这种写法:治标不治本,将来在别的组件当中push|replace,编程式导航还是有类似错误。
1.4
this:当前组件实例(search)
this. $ router属性:当前的这个属性,属性值VueRouter类的一个实例,当在入口文件注册路由的时候,给组件实例添加 r o u t e r ∣ router | routerroute属性
push: VueRouter类的一个实例
function VueRouter(){
}
VueRouter . prototype. push = function(){
}
let $router = new VueRouter();

重写

在这里插入图片描述

四. Home首页模块

在这里插入图片描述

全局组件步骤

1. TypeNav: 3级分类导航

  • 三级联动组件完成:
    由于三级联动,在Home、Search、 Detail, 把三级联动注册为全局组件。
    好处:只需要注册一次,就可以在项目任意地方使用。

1.静态资源
2.main.js

// 三级联动组件----全局组件
import TypeNav from '@/pages/Home/TypeNav'
// 第一个参数:全局组件的名字 第二个参数:哪一个组件
Vue.component(TypeNav.name, TypeNav);

3.Home/index.vue

  <div>
    <!-- 三级联动已经注册为全局组件,不需要import -->
    <TypeNav/>
  </div>

其他静态组件

2. ListContainer: 包含轮播列表的容器

3. TodayRecommend: 今日推荐

4. Rank: 排行

5. Like: 猜你喜欢

6. Floor: 楼层

7. Brand: 品牌

五. 接口

1.postman测试接口

2.axios二次封装

a.安装axios

npm i --save axios

b.配置axios

api/request.js

// 对于axios进行二次封装
import axios from "axios";
// 1.利用axios对象的方法create,去创建一个axios实例
// 2.request就是axios,只是稍微配置一下
const requests = axios.create({
    // 配置对象
    // 基础路径,发请求的时候路径会出现api  /api/home/list  ---/home/list
    baseURL:"/api",
    // 代表请求超时的时间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("faile"))
 }
);
    
// 对外暴露
export default axios;

总结

6:axios二次封装
XMLHttpRequest、fetch、 JQ、axios 
6.1为什么需要进行二次封装axios?
请求拦截器、响应拦截器.请求拦截器,可以在发请求之前可以处理一些业务、响应拦截器,当服务器数据返回以后,可以处理一些事情
6.2在项目当中经常API文件夹[axios]
接口当中:路径都带有/api
baseURL :”/api"
6.3可以参考git |NPM关于axios文档

3.接口统一管理

a.接口统一管理

  • 项目很小:完全可以在组件的生命周期函数中发请求
  • 项目大: axios .get( ’ xxx’)

b.跨域问题

什么是跨域:协议、域名、端口号不同请求,称之为跨域
前端项目本地服务器:http://localhost:8080/#/home
后台服务器:http://gmall-h5-api.atguigu.cn
JSONP、CROS、代理
跨域问题
api/index.js

// 当前这个模块:API进行统一管理
import request from './request';
// 三级联动
// /api/product/getBaseCategoryList get请求 无参数
export const reqCategoryList = () => {
    // 发请求:axios发请求返回结果Promise对象
   return request({
        url: '/api/product/getBaseCategoryList',
        method:'get'
    })
}

vue.config.js解决跨域问题

devServer: {
    proxy: {
      // 浏览器有/api,前台服务器3000找 http://gmall-h5-api.atguigu.cn要数据
      // 没有/api,前台服务器不给转发
      '/api': {
        // 服务器与服务器之间没有跨域问题,前端浏览器有跨域问题
        // 后台服务器地址
        target: 'http://gmall-h5-api.atguigu.cn',
        // pathRewrite:{'^/api':''},
      },
    },
  },

nprogress进度条的使用

安装

npm i --save nprogress

main.js引入

六.vuex状态管理库

vuex相关总结

npm install --save vuex@3

1.vuex是什么?

vuex是官方提供一个插件,状态管理库,集中式管理项目中组件共用的数据。
切记,并不是全部项目都需要Vuex,如果项目很小,完全不需要Vuex,如果项目很大,组件很多、数据很多,数据维护很费劲,Vuex
state
mutations
actions
getters
modules

2.vuex基本使用

import Vue from "vue";
import Vuex from "vuex";
// 需要使用插件一次
Vue.use(Vuex);
// state:仓库存储数据的地方
const state = {};
// mutations:修改state的唯一手段
const mutations = {};
// action:处理action,可以书写自己的业务逻辑,也可以处理异步
const actions = {}
// getter:理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
const getters = {}
// 对外暴露Store类的一个实例
export default new Vuex.Store({
    state,
    mutations,
    actions,
    getters
})

3.vuex实现模块式开发

在这里插入图片描述
如果项目过大,组件过多,接口也很多,数据也很多,可以让Vuex实现模块式开发
模拟state存储数据
{
home:{},
search:{}
}
store/home/index.js

// ---home模块的小仓库
const state = {};
const mutations = {};
const actions = {}
const getters = {}
export default {
    state,
    mutations,
    actions,
    getters
}

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
    }
})

七.三级联动

1.动态获取数据

2.动态背景颜色

a.存储当前鼠标移动的值

data(){
return {
    // 存储用户鼠标移上哪一个一级分类 索引从0开始,-1表示谁都没有移上
    currentIndex:-1
}  },

b.添加鼠标经过事件,添加类名,

 <div class="item" v-for="(c1,index) in categoryList" :key="c1.categoryId"
 //鼠标移上谁谁才有cur类名
:class="{cur:currentIndex===index}">
//添加鼠标经过事件
<h3 @mouseenter="changeIndex(index)">
<a href="">{{c1.categoryName}}</a>
</h3>

c.添加鼠标离开事件,给大div加,事件委派

<div @mouseleave="leaveIndex">
  <h2 class="all">全部商品分类</h2>
  <div class="sort">···<div/>
</div>

d.事件

methods:{
    // 鼠标进入修改响应数据currentIndex属性
    changeIndex(index){
        // index:鼠标移上某一级分类的元素索引值
      this.currentIndex = index;
    },
    // 一级分类鼠标移出事件回调
    leaveIndex(){
        this.currentIndex = -1;
    }
},

2.二三级分类的显示与隐藏

 <div class="item-list clearfix" :style="{display:currentIndex==index?'block':'none'}">

3.卡顿现象—防抖和节流

在这里插入图片描述

//正常情况(用户慢慢的操作):鼠标进入,每一个一级分类h3,都会触发鼠标进入事件
//非正常情况(用户操作很快):本身全部的一级分类都应该触发鼠标进入事件,但是经过测试,只有部分h3触发了
//就是由于用户行为过快,导致浏览器反应不过来。如果当前回调函数中有一些大量业务,有可能出现卡顿现象。

  • 正常:事件触发非常频繁,而且每一次的触发,回调函数都要去执行(如果时间很短,而回调函数内部有计算,那么很可能出现浏览器卡顿)
  • 节流:在规定的间隔时间范围内不会重复触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发
  • 防抖:前面的所有的触发都被取消,最后一次执行在规定的时间之后才会触发,也就是说如果连续快速的触发只会执行一次

1.防抖:

  • 用户操作很频繁,但是只是执行一次
  • 例子:在这里插入图片描述

2.节流:

  • 用户操作很频繁,但是把频繁的操作变为少量操作【可以给浏览器有充裕的时间解析代码】
  • 例子:在这里插入图片描述

3.三级联动节流技术–lodash

component/TypeNav/index.vue

import throttle from 'lodash/throttle';
····
   // 节流函数用箭头函数可能会出现,上下文this情况
    changeIndex:throttle(function(index){
        // 节流
        // index:鼠标移上某一级分类的元素索引值
     this.currentIndex = index;

    },50),

4.三级联动路由跳转与传参

利用事件的委派+编程式导航实现路由跳转与传递参数

注意:
声明式导航(router-link)是组件
利用自定义属性区分a标签

在这里插入图片描述
路由跳转需要携带的参数:
路由中的query 和 params的传参方式区别和详解
在这里插入图片描述

  goSearch(event){
    //最好的解决方案: 编程式导航+事件委派
    //存在一些问题:事件委派,是把全部的子节点[h3、dt、dl、 em]的事件委派给父亲节点
    //点击a标签的时候,才会进行路由跳转[ 怎么能确定点击的一定是a标签]
    //存在另外一个问题:即使你能确定点击的是a标签,如何区分是-级、二级、三级分类的标签。
    //第一个问题:把子节点当中a标签,我加上自定义属性data-categoryName, 其余的子节点是没有的
        let element = event.target;
        //获取到 当前出发这个事件的节点[h3、a、dt、 dl],需要带有data-categoryname这样 节点[一定是a标签 ]
        //节点有一个属性dataset属性,可以获取节点的自定义属性与属性值
        let {categoryname,category1id,category2id,category3id} = element.dataset ;
        //如果标签身上拥有categoryname . 定是a标签
        if (categoryname){
            let location = {name:'search'};
            let query = {categoryName:categoryname};
        //一级分类、一级分类、三级分类的a标签;
        if(category1id){
            query.category1Id = category1id;
        }else if(category2id){
            query.category2Id = category2id;
        }
        else{
            query.category3Id = category3id;
        }
        // 整理完参数
        location.query = query
        // 路由跳转
        this.$router.push(location)
        }
    }

在这里插入图片描述
在这里插入图片描述

5.开发search中TypeNav

a.列表的显示与隐藏

b.过渡动画

前提:组件/元素必须要有要有v-show/v-if指令
在这里插入图片描述
name=“sort” 下方命令 .sort-enter
在这里插入图片描述

c.优化

组件只要用到TypeNav就会发请求
在这里插入图片描述
发请求的目的是获取数据,希望只发一次请求
不管路由怎么跳转,根组件App.vue里的mounted(){}只执行一次,将 this.$store.dispatch(‘categoryList’);放入app组件中
app组件最先执行,在typenav要数据的时候,仓库里已经存在

在这里插入图片描述

d.参数合并

八.

开发Home首页当中的ListContainer组件与Floor组件?
https://docschina. org/
但是这里需要知道一件事情: 服务器返回的数据(接口)只有商品分类菜单分类数据,对于ListContainer组件与Floor组件数据服务器没有提供的。
mock数据(模拟) :如果你想mock数据,需要用到一个插件mockjs

1.安装mock.js

npm install mockjs

使用步骤:
1)在项目当中src文件夹中创建mock文件夹
2)第二步准备JSON数据(mock文 件夹中创建相应的JSON文件) ----格式化-一下,别留有空格(跑不起来的)
3)把mock数据需要的图片放置到public文件夹中public文件夹在打包的时候,会把相应的资源原封不动打包到dist文件夹
4)创建mockSerer.js通过mockjs插件实现模拟数据

十.search组件:

1.静态
2.动态获取数据:
问题1:
多次向服务器发请求??
写成方法:可以多次调用
在服务器发请求之前,将参数变化beforeMount
// 发请求之前捞到参数,带给服务器地址栏会带上请求的参数

合并参数,将query和params参数获取的值一起传给searchParams
Object.assign(searchParams,this. r o u t e . q u e r y , t h i s . route.query,this. route.query,this.route.params)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值