文章目录
- 第一天
- 1)要求
- 2)脚手架使用
- 3)脚手架下载下来的项目稍微配置一下
- 1:浏览器自动打开
- 2关闭eslint校验工具
- 3 src文件夹的别名的设置
- 4)路由的配置
- 1路由的一个分析
- 2安装路由
- 3创建路由组件【一般放在views|pages文件夹】
- 4配置路由,配置完四个路由组件
- 5)创建非路由组件
- 6)路由的跳转
- 7)底部组件的显示和隐藏
- 8)路由传参
- 第二天
- 1)一个导航问题
- 2)将Home组件的静态组件拆分
- 3)测试接口
- 4)axios二次封装
- 5)完成三级联动
- 6)函数防抖与节流面试题
- 7)优化项目。
- 8)路由的跳转与传参
- 第三天
- 1)搜索模块中的三级联动与过渡动画
- 2)组件name属性的作用?
- 3)TypeNav组件业务分析?
- 4)过渡效果
- 5)TypeNav三级联动性能优化?
- 6)合并参数
- 7)mock.js 模拟数据
- 8)开发listContainer|Floor组件业务?
- 9)swiper基本的使用?
- swiper在Vue项目中使用
- 1.swiper安装到项目当中
- 2.在相应的组件引入swiper.js|swiper.css
- 3.初始化swiper实例在哪里书写?
- 4.直接初始化swiper动态效果为什么没有出来?
- 5.第一种解决方案,延迟器(不是完美的解决方案)
- 6.Swiper在Vue项目中使用完美解决方案
- 第四天
- 1)开发Floor组件
- 2)carousel全局组件
- 3)常用插件
- 第五天
- 1)完成search静态组件
- 第六天
- 1)分页器封装业务分析:
- 第七天
- 第八天
- 1)加入购物车成功组件的业务?
- 2)获取购物车的数据进行展示
- 3)**购物车数量的操作?**
- 4)删除购物车中的产品的操作
- 5)购物车产品选中与未选中业务
- 6)全选的业务
- 7)其他注意点
- 第九天
- 1)登录注册
- 2)注册的业务
- 注册业务
- 登录业务
- 第十天
- 1)交易业务
- 2)提交订单业务
- 3)获取支付信息进行展示
- 4)element-ui官方UI组件库(插件)?
- 5)支付业务【微信支付】
- qrCode字符串转换为加密的在线二维码
- js库推荐
- 判断支付状态
- 第十一天
- 1)个人中心路由搭建
- 2)未登录全局守卫的判断
- 3)图片懒加载
- 4)路由懒加载
- 步骤
- 5)表单验证
- 打包
- **遇到的问题**
第一天
1)要求
1:node + webpack + VScode + 谷歌浏览器 + git
2:数组的方法 + promise + await + async + 模块化…
2)脚手架使用
vue init webpack 项目的名字
vue create 项目名称
脚手架目录:public + assets文件夹区别
node_modules:放置项目依赖的地方
public:一般放置一些共用的静态资源,打包上线的时候,public文件夹里面资源原封不动打包到dist文件夹里面
src:程序员源代码文件夹
-----assets文件夹:经常放置一些静态资源(图片),assets文件夹里面资源webpack会进行打包为一个模块(js文件夹里面)
-----components文件夹:一般放置非路由组件(或者项目共用的组件)
App.vue 唯一的根组件
main.js 入口文件【程序最先执行的文件】
babel.config.js:babel配置文件
package.json:看到项目描述、项目依赖、项目运行指令
package-lock.json:缓存性文件
README.md:项目说明文件
3)脚手架下载下来的项目稍微配置一下
1:浏览器自动打开
在package.json文件中
//脚手架五有bug,建议不配置
"scripts": {
"serve": "vue-cli-service serve --open",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
2关闭eslint校验工具
创建vue.config.js文件:需要对外暴露
module.exports = {
lintOnSave:false,
}
现在脚手架生成该文件,直接添加配置
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false
})
3 src文件夹的别名的设置
因为项目大的时候src(源代码文件夹):里面目录会很多,找文件不方便,设置src文件夹的别名的好处,找文件会方便一些
创建jsconfig.json文件,脚手架已经生成改文件
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"exclude": [
"node_modules",
"dist"
]
}
4)路由的配置
vue-router
路由分为Key-Value
前端路由:
K即为URL(网络资源定位符)
V即为相应的路由组件
1路由的一个分析
- 确定项目结构顺序:上中下 -----只有中间部分的V在发生变化,中间部分应该使用的是路由组件
- 2个非路由组件|四个路由组件
- 两个非路由组件:Header 、Footer
- 路由组件:Home、Search(有底部的Footer组件,带有二维码的);
- Login、Register(没有底部的Footer组件,带二维码的)
2安装路由
npm i vue-router@3
vue2中使用vue-router的3版本
vue3中使用vue-router的4版本
3创建路由组件【一般放在views|pages文件夹】
4配置路由,配置完四个路由组件
router/index.js
//引入VueRouter
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'
//创建router实例对象,去管理一组一组的路由规则
export default new VueRouter({
routes: [{
path: '/search',
component: Search
},
{
path: '/home',
component: Home
},
{
path: '/login',
component: Login
},
{
path: '/register',
component: Register
},
]
})
main.js 添加程序
import router from '@/router';
new Vue({
render: h => h(App),
router
}).$mount('#app')
5)创建非路由组件
(2个:Header、Footer)
非路由组件使用分为几步:
第一步:定义
第二步:引入
第三步:注册
第四步:使用
项目采用的less样式,浏览器不识别less语法,需要一些loader进行处理,把less语法转换为CSS语法
1:安装less less-loader@5
npm i less less-loader@5
切记less-loader安装5版本的,不要安装在最新版本,安装最新版本less-loader会报错,报的错误setOption函数未定义
2022/3/23 可以安装最新版less-loader
"less": "^4.1.2",
"less-loader": "^10.2.0",
2:需要在style标签的身上加上lang="less"
,不添加样式不生效
6)路由的跳转
路由的跳转就两种形式:
- 声明式导航(router-link:务必要有to属性)
- 编程式导航push||replace
- 编程式导航更好用:因为可以书写自己的业务逻辑
给主页的a和搜索按钮分别换成声明式导航和编程式导航
<router-link to="/login">登录</router-link>
<router-link to="/register" class="register">免费注册</router-link>
<router-link class="logo" title="尚品汇" to="/home">
<button
class="sui-btn btn-xlarge btn-danger"
type="button"
@click="goSearch"
>
methods: {
goSearch() {
this.$router.push("./search");
},
},
7)底部组件的显示和隐藏
- 路由组件:Home、Search(有底部的Footer组件,带有二维码的);
- Login、Register(没有底部的Footer组件,带二维码的)
面试题:v-show与v-if区别?
v-show:通过样式display控制
v-if:会操作dom
面试题:开发项目的时候,优化手段有哪些?
1:v-show|v-if
2:按需加载
路由元信息meta
- 通过meta,设置一个属性,来控制是否显示底部组件
8)路由传参
- params参数:路由需要占位,属于URL当中一部分
- query参数:路由不需要占位,写法类似于ajax当中query参数
{
path: '/search/:keyword',
component: Search,
meta: {
footerShow: true
}
},
//传递字符串 ,也可以使用模板字符串
this.$router.push(
"/search/" + this.keyword + "?k=" + this.keyword.toUpperCase()
);
路由传递参数先关面试题
-
路由传递参数(对象写法)path是否可以结合params参数一起使用?
答:路由跳转传参,对象可以说name、path形式,但是path形式不可以和params结合使用 -
如何指定params参数可传可不传?
答:配置路由占位,必须传递参数,配置占位后面加上问号,那么这个参数可传可以不传
{ path: '/search/:keyword?', component: Search, meta: { footerShow: true } },
-
params参数可以传递也可以不传递,但是如果传递是空串,如何解决?
undefined解决:params:{keyword:''|undefined}
如果指定name与params配置, 但params中数据是一个"", 无法跳转,路径会出问题
-
路由组件能不能传递props数据?
{
name:'xiangqing',
path:'detail/:id',
component:Detail,
//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
// props:{a:900}
//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
// props:true
//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
props(route){
return {
id:route.query.id,
title:route.query.title
}
}
}
第二天
1)一个导航问题
编程式导航路由跳转到当前路由(参数不变), 多次执行会抛出NavigationDuplicated的警告错误?
注意:编程式导航(push|replace)才会有这种情况的异常,声明式导航是没有这种问题,因为声明式导航内部已经解决这种问题。
这种异常,对于程序没有任何影响的。
-
为什么会出现这种现象:
由于vue-router最新版本,引入了promise,当传递参数多次且重复,会抛出异常,因此出现上面现象,- 第一种解决方案:是给push函数,传入相应的成功的回调与失败的回调
this.$router.push( { name: "search", params: { keyword: this.keyword }, query: { k: this.keyword.toUpperCase() }, }, () => {}, () => {} ); //这种解决方案可以暂时解决当前问题,但是以后再用push|replace还是会出现类似现象,因此我们需要从‘根’治病;
- 第二种,重写push方法
//this.$router.push //this :当前组件实例 //this.$router属性:VueRouter的一个实例,当在入口文件注册路由的时候,给组件实例添加$router|$route属性 //push在实例$router的原型对象上 let originPush = VueRouter.prototype.push; let originReplace = VueRouter.prototype.replace; //重写VueRouter.prototype身上的push方法了 VueRouter.prototype.push = function(location, resolve, reject) { //第一个形参:路由跳转的配置对象(query|params) //第二个参数:undefined|箭头函数(成功的回调) //第三个参数:undefined|箭头函数(失败的回调) if (resolve && reject) { //push方法传递第二个参数|第三个参数(箭头函数) //originPush:利用call修改上下文,变为(路由组件.$router)这个对象,第二参数:配置对象、第三、第四个参数:成功和失败回调函数 originPush.call(this, location, resolve, reject); } else { //push方法没有产地第二个参数|第三个参数 originPush.call( this, location, () => {}, () => {} ); } }; //重写VueRouter.prototype身上的replace方法了 VueRouter.prototype.replace = function(location, resolve, reject) { if (resolve && reject) { originReplace.call(this, location, resolve, reject); } else { originReplace.call( this, location, () => {}, () => {} ); } };
2)将Home组件的静态组件拆分
开发步骤
1.完成静态页面(样式)
2.拆分静态组件
3.发请求获取服务器数据进行展示
4.开发动态业务
拆分组件:结构+样式+图片资源
3)测试接口
这里使用postman
- 三级分类的请求地址 http://39.98.123.211/api/product/getBaseCategoryList
- 如果服务器返回code字段200,代表服务器返回数据成功
- 整个项目,接口前缀都有/api字样
4)axios二次封装
-
写项目的时候发请求在哪里发
- mounted|created:都可以
- mounted:模板已经变为真是DOM【只不过没有数据,显示空白】,因为ajax是异步,需要时间的。
- created:稍微好那么一丢丢
-
AJAX:客户端可以’敲敲的’向服务器端发请求,在页面没有刷新的情况下,实现页面的局部更新。
-
Ajax的相关函数:XMLHttpRequest、$、fetch、axios
-
跨域:如果多次请求协议、域名、端口号有不同的地方,称之为跨域
- 解决:JSONP、CROS、代理
-
为什么需要二次封装axios?
- 工作的时候src目录下的API文件夹,一般关于axios二次封装的文件
- 为了实现 请求拦截器、响应拦截器:
- 请求拦截器:在发送请求前可以处理一些业务
- 响应拦截器:当服务器返回数据后,可以处理一些事情
-
安装axios
npm i axios
-
接口的统一管理
- 项目很小:完全可以在组件的生命周期函数中发请求
- 项目大:axios.get(‘xxx’)
- 大项目在API文件夹创建index.js 管理
- 如果后端接口换了便于更换
-
跨域问题
- 后端已经解决跨域问题
- 我们写url想省略’http://39.98.123.211’,需要配置代理服务器
-
进度条:nprogress模块实现进度条功能
npm i nprogress
- 使用nprogress,需要引入样式
- 工作的时候,修改进度条的颜色,修改源码样式.bar类名的
- nprogress是一个对象,start:进度条开始的方法,done:进度条结束
-
vuex
- vuex:Vue官方提供的一个插件,插件可以管理项目共用数据。
- 一般采用vuex模块化
vue2中使用vuex的3版本
vue3中使用vuex的4版本
-
vuex:书写任何项目都需要vuex?
项目大的时候,需要有一个地方‘统一管理数据’即为仓库store -
Vuex基本使用:
//对于axios进行二次封装
import axios from "axios";
import nprogress from "nprogress";
//在当前模块中引入store
import store from '@/store';
//如果出现进度条没有显示:一定是你忘记了引入样式了
import "nprogress/nprogress.css";
//底下的代码也是创建axios实例
let requests = axios.create({
//基础路径
baseURL: "/api",
//请求不能超过5S
timeout: 5000,
});
//请求拦截器----在项目中发请求(请求没有发出去)可以做一些事情
requests.interceptors.request.use((config) => {
//现在的问题是config是什么?配置对象:有个属性很重要,headers请求头
//可以让进度条开始动
if (store.state.detail.uuid_token) {
//请求头添加一个字段(userTempId):和后台老师商量好了
config.headers.userTempId = store.state.detail.uuid_token;
}
//需要携带token带给服务器
if (store.state.user.token) {
config.headers.token = store.state.user.token;
}
nprogress.start();
return config;
});
//响应拦截器----当服务器手动请求之后,做出响应(相应成功)会执行的
requests.interceptors.response.use(
(res) => {
//进度条结束
nprogress.done();
//响应成功做的事情
return res.data;
},
(err) => {
alert("服务器响应数据失败");
//return Promise.reject(new Error('faile'))
}
);
//最终需要对外暴露(不对外暴露外面模块没办法使用)
//这里的代码是暴露一个axios实例
export default requests;
5)完成三级联动
- v-for 生成dom
- 选中时的样式(一级分类的背景效果解决方法)
- 第一种:通过style解决
- 第二种:通过js解决
- 鼠标离开,事件委派
- 鼠标进入,修改进入了哪个一级分类的数据
:class="{ cur: currentIndex == index }
,动态添加样式
- 卡顿现象:如果时间很短,而回调函数内部有计算,那么很可能出现浏览器卡顿
6)函数防抖与节流面试题
触发: 回调函数都要去执行(如果时间很短,而回调函数内部有计算,那么很可能出现浏览器卡顿)
防抖: 前面的所有的触发都被取消,最后一次执行在规定的时间之后才会触发,也就是说如果连续快速的触发,只会执行最后一次
节流: 在规定的间隔时间范围内不会重复触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发
- 防抖与节流的原理,通过JS实现【闭包 + 延迟器】
7)优化项目。
- v-if|v-show
- 按需加载
- 函数防抖与节流
- 按需加载:对于loadsh插件,它里面封装的函数功能很多
- import _ from lodash 相当于把全部功能引入进来,但是我们只是需要节流。
_.throttle(func, [wait=0], [options=])
节流_.debounce(func, [wait=0], [options=])
防抖- 在这个项目中,上述函数传函数的参数时别用箭头函数,this指向会出现问题
- 请求次数优化【第三天5)有优化方案】
8)路由的跳转与传参
-
选择合适的路由导航
-
第一种声明式导航:为什么使用router-link组件的时候,会出现卡顿那?
router-link是一个组件:相当于VueComponent类的实例对象,一瞬间
new VueComponent很多实例(1000+),很消耗内存,因此导致卡顿。 -
第二种编程式导航:push|replace
- 三级分类由于使用router-link的时候,会出现卡顿现象,因此采用编程式导航。
- 路由跳转的时候【home->search】:需要进行路由传递参数【分类的名字、一、二、三级分类的id】
- 不需要给所有a加上点击事件,借助事件的委派
- 如何确定点击的是a标签,加上自定义属性:data-categoryName,
- 如何获得自定义属性,event.target.dateset
data-* 全局属性 是一类被称为自定义数据属性的属性,它赋予我们在所有 HTML 元素上嵌入自定义数据属性的能力,并可以通过脚本在 HTML 与 DOM 表现之间进行专有数据的交换。 data-categoryName ==>event.target.dataset.categoryname 转化为小写 data-category-name ==>event.target.dataset.categoryName 单词用-连接,第二个单词开始,首字母大写
- 不同的自定义属性区分不同级别的a【data-categoryId1,data-categoryId2,data-categoryId3】
this.$router.push() { name:'search', query:{ categoryName:'电子书', category2Id:4 } }
第三天
v-for在大项目中index索引值切记加上
1)搜索模块中的三级联动与过渡动画
- 在home模块当中,使用了一个功能三级联动功能---->[typeNav]
- 在search模块当中,也使用三级联动的功能------->[typeNav]
- 注意的事项
- 在开发项目的时候,如果发现某一个组件在项目当中多个地方出现频繁的使用经常把这类的组件注册为全局组件。
- 注册全局组件的好处是什么那:只需要注册一次,可以在程序任意地方使用
- 项目当中全局组件(共用的组件)一般放置于components文件夹中
- 全局组件只需要注册一次,就可以在项目当中任意的地方使用,注册全局组件一般是在入口文件注册。
2)组件name属性的作用?
- 开发者工具中可以看见组件的名字
- 注册全局组件的时候,可以通过组件实例获取相应组件的名字
3)TypeNav组件业务分析?
- 三级联动在home模块正常显示
- 三级联动在search一会显示、一会隐藏 —解决方案:通过一个响应式属性控制三级联动显示与隐藏
- 开发的时候的出现问题:在home模块下不应该出现显示与隐藏的效果
- 现在这个问题【三级联动:本身在search模块应该有显示与隐藏的业务】 ,但是在home模块下不应该出现显示与隐藏的业务
- 说白了:你需要让三级联动组件知道谁在用它。
- 通过 r o u t e 让 组 件 区 分 在 那 个 模 块 下 以 后 在 使 用 的 时 候 , 如 果 出 现 某 一 个 组 件 要 区 分 当 前 在 哪 一 个 模 块 中 【 h o m e 、 s e a r c h 】 , 通 过 route让组件区分在那个模块下 以后在使用的时候,如果出现某一个组件要区分当前在哪一个模块中【home、search】,通过 route让组件区分在那个模块下以后在使用的时候,如果出现某一个组件要区分当前在哪一个模块中【home、search】,通过route路由信息区分
- 路由跳转的时候,相应的组件会把重新销毁与创建,如何阻止销毁----【keep-alive】
4)过渡效果
- Vue过渡动画效果—transition内置组件完成
- 注意1,在Vue当中,你可以给 (某一个节点)|(某一个组件)添加过渡动画效果
但是需要注意,节点|组件务必出现v-if|v-show指令才可以使用。
5)TypeNav三级联动性能优化?
项目:home切换到search或者search切换到home,你会发现一件事情,组件在频繁的向服务器发请求,获取三级联动的数据进行展示。
- 路由跳转的时候,home到search ,home中的三级联动组件销毁,search的三级联动组件创建,会频繁的向服务器发请求获取三级联动的数据
- 项目中如果频繁的向服务器发请求,很消耗性能的,因此咱们需要进行优化。
- 之前在三级联动挂载完发送Ajax请求,转移到APP组件,只发送一次请求
6)合并参数
为什么需要合并参数(query|params):因为这些参数,对于search是有用的,因为search通过这些参数向服务器发请求,需要把这些参数携带给服务器,服务器就会返回相应的用户的搜索的数据,search就可以进行展示。
-
开发的三级联动业务,当你点击a标签的时候,会进行路由的跳转,将产品的名字与id传递给search模块----(query)
-
点击搜索按钮的时候,用户输入进来的关键字,点击按钮的时候会通过params参数传递给search模块-----(params)
-
路由跳转(home->search),两个地方,三级联动(typeNav)、Header组件(搜索按钮)
-
合并 params和query参数
-
点击搜索传递params参数
-
点击三级联动链接传递query参数
-
但是有了一个参数后,采用另外一种方式参数会消失
-
这里合并参数来进行搜索
goSearch() {
if (this.$route.query) {
let location = {
name: "search",
params: { keyword: this.keyword || undefined },
};
location.query = this.$route.query;
this.$router.push(location);
}
},
7)mock.js 模拟数据
mock数据【生成随机数据,拦截Ajax请求】。
- 如果后端接口没有搭建好,我们需要自己模拟数据
- 项目中mock数据,把他当成真实接口数据用就行。
- http://mockjs/ 官方地址
注意:mock(模拟数据)数据需要使用到mockjs模块,可以帮助我们模拟数据。
注意:mockjs【并非mock.js mock-js】
下载
npm i mockjs
生成随机数据,拦截 Ajax 请求的理解
- 模拟的数据一般:对象、数组
{
‘a|1-10’:‘我爱你’
} - 拦截ajax请求:请求发布出去【浏览器会进行拦截:笨想,因为服务器】,只是项目当中本地自己玩耍数据。
使用步骤
-
1.安装依赖包mockjs
-
2.在src文件夹下创建一个文件夹,文件夹mock文件夹。
-
3.准备模拟的数据
**把mock数据需要的图片放置于public文件夹中! **模拟数据JSON:没有空格,最好使用格式化插件进行格式化
listContainer中的轮播图的数据
[ { "id": "1", "imgUrl": "/images/banner1.jpg" }, { "id": "2", "imgUrl": "/images/banner2.jpg" }, { "id": "3", "imgUrl": "/images/banner3.jpg" }, { "id": "4", "imgUrl": "/images/banner4.jpg" } ]
istContainer中的轮播图的数据
[ { "id": "001", "name": "家用电器", "keywords": [ "节能补贴", "4K电视", "空气净化器", "IH电饭煲", "滚筒洗衣机", "电热水器" ], "imgUrl": "/images/floor-1-1.png", "navList": [ { "url": "#", "text": "热门" }, { "url": "#", "text": "大家电" }, { "url": "#", "text": "生活电器" }, { "url": "#", "text": "厨房电器" }, { "url": "#", "text": "应季电器" }, { "url": "#", "text": "空气/净水" }, { "url": "#", "text": "高端电器" } ], "carouselList": [ { "id": "0011", "imgUrl": "/images/floor-1-b01.png" }, { "id": "0012", "imgUrl": "/images/floor-1-b02.png" }, { "id": "0013", "imgUrl": "/images/floor-1-b03.png" } ], "recommendList": [ "/images/floor-1-2.png", "/images/floor-1-3.png", "/images/floor-1-5.png", "/images/floor-1-6.png" ], "bigImg": "/images/floor-1-4.png" }, { "id": "002", "name": "手机通讯", "keywords": [ "节能补贴2", "4K电视2", "空气净化器2", "IH电饭煲2", "滚筒洗衣机2", "电热水器2" ], "imgUrl": "/images/floor-1-1.png", "navList": [ { "url": "#", "text": "热门2" }, { "url": "#", "text": "大家电2" }, { "url": "#", "text": "生活电器2" }, { "url": "#", "text": "厨房电器2" }, { "url": "#", "text": "应季电器2" }, { "url": "#", "text": "空气/净水2" }, { "url": "#", "text": "高端电器2" } ], "carouselList": [ { "id": "0011", "imgUrl": "/images/floor-1-b01.png" }, { "id": "0012", "imgUrl": "/images/floor-1-b02.png" }, { "id": "0013", "imgUrl": "/images/floor-1-b03.png" } ], "recommendList": [ "/images/floor-1-2.png", "/images/floor-1-3.png", "/images/floor-1-5.png", "/images/floor-1-6.png" ], "bigImg": "/images/floor-1-4.png" } ]
-
4.在mock文件夹中创建一个server.js文件
注意:在server.js文件当中对于banner.json||floor.json的数据没有暴露,但是可以在server模块中使用。
对于webpack当中一些模块:图片、json,不需要对外暴露,因为默认就是对外暴露。 -
5.通过mock模块模拟出数据
- 通过Mock.mock方法进行模拟数据
//先引入mockjs模块 import Mock from 'mockjs'; //把JSON数据格式引入进来[JSON数据格式根本没有对外暴露,但是可以引入] //webpack默认对外暴露的:图片、JSON数据格式 import banner from './banner.json'; import floor from './floor.json'; //mock数据:第一个参数请求地址 第二个参数:请求数据 Mock.mock("/mock/banner",{code:200,data:banner});//模拟首页大的轮播图的数据 Mock.mock("/mock/floor",{code:200,data:floor});
-
6.回到入口文件,引入serve.js
mock需要的数据|相关mock代码页书写完毕,关于mock当中serve.js需要执行一次,
如果不执行,和你没有书写一样的。 -
7.在API文件夹中创建mockRequest【axios实例:baseURL:’/mock’】
专门获取模拟数据用的axios实例。
//对于axios进行二次封装
import axios from "axios";
import nprogress from "nprogress";
//如果出现进度条没有显示:一定是你忘记了引入样式了
import "nprogress/nprogress.css";
//底下的代码也是创建axios实例
let requests = axios.create({
//基础路径
baseURL: "/mock",
//请求不能超过5S
timeout: 5000,
});
//请求拦截器----在项目中发请求(请求没有发出去)可以做一些事情
requests.interceptors.request.use((config) => {
//现在的问题是config是什么?配置对象
//可以让进度条开始动
nprogress.start();
return config;
});
//响应拦截器----当服务器手动请求之后,做出响应(相应成功)会执行的
requests.interceptors.response.use(
(res) => {
//进度条结束
nprogress.done();
//相应成功做的事情
return res.data;
},
(err) => {
alert("服务器响应数据失败");
}
);
//最终需要对外暴露(不对外暴露外面模块没办法使用)
//这里的代码是暴露一个axios实例
export default requests;
在开发项目的时候:切记,单元测试,某一个功能完毕,一定要测试是否OK
8)开发listContainer|Floor组件业务?
- 开发listContainer组件与floor组件
- mock一些数据【前端程序员自己模拟的一些假的接口】,当中工作中项目上线,需要把mock
数据变为后台接口数据替换。 - 按照上述搭建模拟数据
- vuex请求数据的函数搭建
9)swiper基本的使用?
-
swiper移动端可以使用,pc端也可以使用。这个插件经常可以快速开发轮播图。
-
前端开发:轮播图、分页器、日历。
-
swiper常用于哪些场景?
- 常用的场景即为轮播图----【carousel:轮播图】
- swiper最新版本为7版本的,项目当中使用的是5版本
-
https://www.swiper/ 官网地址
-
swiper使用步骤:
- 第一步:引入依赖包【swiper.js|swiper.css】
- 第二步:静态页面中结构必须完整【container、wrap、slider】,类名不能瞎写
- 第三步:初始化swiper实例
swiper在Vue项目中使用
(开发ListContainer组件【首页banner图片】)
**提示:**卸载插件,你可以不用删除node_modules文件夹,可以使用npm uninstall xxxx进行卸载
1.swiper安装到项目当中
npm i swiper@5
2.在相应的组件引入swiper.js|swiper.css
但是需要注意,home模块很多组件都使用到swiper.css,没必要在每一个组件内部都引入样式一次,
只需要在入口文件引入一次即可。
//main.js
import "swiper/css/swiper.css";
//ListContainer/index.vue
import Swiper from "swiper";
3.初始化swiper实例在哪里书写?
- 初始化swiper实例之前,页面中的节点(结构)务必要有,对于Vue一个组件而言,mounted[组件挂载完毕:相应的结构不就有了吗
mounted–>组件挂载完毕
4.直接初始化swiper动态效果为什么没有出来?
Swiper需要获取到轮播图的节点DOM,才能给swiper轮播添加动态效果,因为没有获取到节点。
5.第一种解决方案,延迟器(不是完美的解决方案)
同学的想法:都不是完美的【错误的想法】
updated里面:如果组件有很多响应式(data),只要有一个属性值发生变化updated还会再次执行,再次初始化实例。不需要重复初始化swiper
**总结:**延迟器解决方案可以通过延迟器(异步)去解决问题,但是这种解决方案存在风险(无法确定用户请求到底需要多长时间),因此没办法确定延迟器时间。
6.Swiper在Vue项目中使用完美解决方案
v-for,在遍历来自于Vuex数据(数据:通过ajax向服务器发请求,存在异步)
watch:监听属性,watch可以检测到属性值的变化,当属性值发生变化的时候,可以出发一次。
Vuex当中的仓库数据bannerList(组件在使用):
-
bannerList仓库数据有没有发生过变化?
- 一定是有的:bannerList初始值空数组,当服务器的数据返回以后,它的bannerList存储的属性值会发生变化【变为服务器返回的数据】
- 组件实例在使用仓库中的bannerList,组件的这个属性bannerList一定是发生过变化,watch可以监听到。
组件实例的一个方法:$nextTick
this.$nextTick(()=>{
})
this.$nextTick(function () {
new Swiper(".swiper-container", {
//this.$refs.mySwiper,
loop: true, // 循环模式选项
// 如果需要分页器
pagination: {
el: ".swiper-pagination",
clickable: true,
},
// 如果需要前进后退按钮
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
// 如果需要滚动条
scrollbar: {
el: ".swiper-scrollbar",
},
});
});
nextTick官网解释:
在下次DOM更新, 循环结束之后,执行延迟回调。在 修改数据之后 立即使用这个方法,获取更新后的DOM。
注意:组件实例的$nextTick方法,在工作当中经常使用,经常结合第三方插件使用,获取更新后的DOM节点
第四天
1)开发Floor组件
开发Floor组件:Floor组件它被复用的(重复使用两次)
1:Floor组件获取mock数据,发请求的action书写在哪里?
派发action应该是在父组件的组件挂载完毕生命周期函数中书写,因为父组件需要通知Vuex发请求,父组件获取到mock数据,通过v-for遍历,生成多个floor组件,因此达到复用作用。
2.父组件派发action,通知Vuex发请求,Home父组件获取仓库的数据,通过v-for遍历出多个Floor组件
3.v-for|v-show|v-if|这些指令可以在自定义标签(组件)的身上使用
4组件间通信面试必问的东西
- props:父子
- 插槽:父子
- 自定义事件:子父
- 全局事件总线$bus:万能
- pubsub:万能
- Vuex:万能
- $ref:父子通信(绑定自定义事件)
5.为什么在Floor组件的mounted中初始化SWiper实例轮播图可以使用.
因为父组件的mounted发请求获取Floor组件,当父组件的mounted执行的时候。
Floor组件结构可能没有完整,但是服务器的数据回来以后Floor组件结构就一定是完成的了,因此v-for在遍历来自于服务器的数据,如果服务器的数据有了,Floor结构一定的完整的。
2)carousel全局组件
-
发现home多次使用相同结构 轮播图
-
如果项目当中出现类似的功能,且重复利用,封装为全局组件----【不封装也可以】
-
为了封装全局的轮播图组件:让Floor与listContainer组件中的代码一样,如果一样完全可以独立出来封装为一个全局组件。
3)常用插件
- swiper|lodash|moment插件工作的时候经常使用----【API:有时间翻看一下】
第五天
1)完成search静态组件
步骤:
1.书写静态页面【布局、样式】
2.拆分组件
3.获取服务器数据展示数据(发请求【API】,vuex,获得数据)
4.玩业务
- vuex:使用getter简化data数据
- 注意:搜索的接口,需要传递参数,至少是一个空对象(KV没有,但是至少给服务器一个对象)
//是搜索模块需要携带给接口的参数
{
"category1Id": "61",//一级分类的id
"category2Id": "61",//二级分类的id
"category3Id": "61",//三级分类的id
"categoryName": "手机",//产品的名字
"keyword": "小米",//关键字
"order": "1:desc",//排序
"pageNo": 1,//当前第几页
"pageSize": 10,//每一页需要展示多少条数据
"props": ["1:1700-2799:价格", "2:6.65-6.74英寸:屏幕尺寸"],//平台属性的选择参数
"trademark": "4:小米"//品牌参数
}
套路1:路由自己跳自己----修改路由
套路2:watch监听路由的变化发请求
- 展示商品列表数据
- 传参(路由器参数传给服务器)可以利用数组的合并object.assign()
- 面包屑处理:需要路由跳转,编程路由导航跳到自己
- 面包屑中关键词清除以后,需要让兄弟组件Header组件中的search框清除【全局时间总线】
- this. b u s . bus. bus.emit this. b u s . bus. bus.on
- 子组件的数据传给父组件向服务器发送品牌数据
@tradeMarkInfo= "tradeMarkInfo"
- 排序练习字体图标,在线字体,排序箭头阿里图标库https://www.iconfont/
请求的性能优化:
发一个请求,需要向服务器携带参数:参数多,消耗的带宽多,空值可以将其改为undefind
对于给服务器携带的参数:如果数值为undefind,向服务器发请求的时候,参数不携带给服务器的
-
什么是富文本,插件有哪些,如何使用【在Vue当中使用】
-
完成排序业务
-
综合与价格按钮,点击谁,谁的背景颜色变为红色。(类名:active)
-
谁有类这件事情,区分开综合与价格
-
将来点击综合||价格,还是需要给服务器发请求
【价格升序:把这个信息给服务器传递过去,服务器接收到信息,数据库自动把排序这件事情做了,把排序做好的数据返回给你,你展示即可】
-
第六天
-
前端三大件:轮播图、分页、日历。这属于前端开发常见三种业务
-
分页功能,两种方式
- 第三方插件:elementUI实现超级简单
- 这里为了练习自己实现
-
为什么很多项目中都采用分页功能?
比如电商平台:搜索一个奶粉,奶粉的产品有10000+,一次渲染10000+条数据,可能慢。数据多的时候,可以选择分页,比如每一次只是展示10 -
拆分分页组件(静态组件),注册为全局组件,因为其他模块也在使用分页功能。
-
面试当中:你自己封装过一个通用的组件吗?-----分页组件
1)分页器封装业务分析:
-
封装分页器组件的时候:需要知道哪些条件?
-
分页器组件需要知道我一共展示多少条数据 ----total【100条数据】
-
每一个(页)需要展示几条数据------pageSize【每一页3条数据】
-
需要知道当前在第几页-------pageNo[当前在第几页]
-
需要知道连续页码数【起始数字、结束数字:连续页码数市场当中一般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
************************************
进行单元测试
连续页码5: 8 [6,7,8,9,10]
连续页码7: 8 [5,6,7,8,9,10,11]
-
:disabled="pageNo == 1"
使上一页按键失效 -
经典面试题:v-for与v-if优先级? v-for优先级更高
-
不应该把’v-for’和’v-if’混在一起 ,可以给v-for设置一个计算属性遍历
-
正常情况:再回来因该还是第一页【遇见脑袋xxxx产品可能有这种操作】
- push与replace区别?
- 编程式导航:push 与 replace
- 能不能记录历史记录:push(能记住历史记录) replace(不能记住历史记录)
- 目前项目当中:进行路由跳转(编程式导航)基础都是push
-
需求:【正常说:没有这个需求的】
- 比如:2021年10月30日11:47:44 点击分页器 第四页 ->网站关闭了
- 但是2021年11月11日11:48:12 打开这个项目 第四页 -->本地存储
第七天
开发详情Detail业务步骤
- 熟悉静态页面、书写样式
- 拆分组件
- 获取服务器动态展示
- 完成动态业务
过程
- Detail组件
- 注册路由:
- params参数 /:skuid
- search的商品图品声明式导航
- 路由跳转带params参数
- vue-router 滚动行为
scrollBehavior(to) {
if (to.name == 'detail') {
console.log(1);
return { x: 0, y: 0 }
// vuex-router@3 x y
// vue3 : vuex-router@4 top bottom
}
}
-
路由模块化:router.js
-
数据获取:ajax(axios),vuex(getters 简化数据,未发请求vuex的state数据为空,getters数据若为undefined,就会警告,逻辑’||'解决),详情页派发dispatch
-
vue-warn:警告(不影响的你程序),对于你的代码提出一个警告。对于程序没有任何影响,俗称假报错。
-
vuex:时不时会有假报错现象
详情模块开发之商品属性的开发
- 排他操作:在工作中经常使用-----千万别忘记
{
attr:'颜色',
attrValue:['红色','黑色','白色']
}
- 将所有的属性选中清除,然后再把选中的属性添加样式
放大镜的功能
----插件:插件解决可以【巧劲】
- 放大镜的结构与样式
<template>
<div class="spec-preview">
<img :src="currentImage" />
<div class="event" @mousemove="hander" ref="eventEle"></div>
<div class="big">
<img :src="currentImage" ref="big" />
</div>
<div class="mask" ref="mask"></div>
</div>
</template>
<style lang="less">
.spec-preview {
position: relative;
width: 400px;
height: 400px;
border: 1px solid #ccc;
img {
width: 100%;
height: 100%;
}
.event {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 998;
}
.mask {
width: 50%;
height: 50%;
background-color: rgba(0, 255, 0, 0.3);
position: absolute;
left: 0;
top: 0;
display: none;
}
.big {
width: 100%;
height: 100%;
position: absolute;
top: -1px;
left: 100%;
border: 1px solid #aaa;
overflow: hidden;
z-index: 998;
display: none;
background: white;
img {
width: 200%;
max-width: 200%;
height: 200%;
position: absolute;
left: 0;
top: 0;
}
}
.event:hover ~ .mask,
.event:hover ~ .big {
display: block;
}
}
</style>
- 遮罩层为什么能动。
- 获取节点(DOM:必须要定位),通过JS动态修改left|top、定位元素才有left、top属性
产品个数业务
考虑小数,非数字,负数的输入
加入购物车的业务? 购物车项目第二个重要地方
购物车:每一个人都有属于自己的购物车,那为什么不同用户登录自己账号,可以看见属于自己产品一定是用户点击加入购物车,把你的产品信息提交给服务器进行保存,当你下次在进入购物车的时候,需要向服务器发请求,获取你购物车里面的信息展示
项目:点击加入购物车按钮的时候,以前经常进行路由跳转【调到另外一个路由】,但是你要注意,点击加入购物车这个按钮的时候,将用户选择产品,提交给服务器进行存储,如果服务器存储成功,之后在进行路由跳转
面试题:GET与POST
相同点:都是HTTP协议。
不同点:
1:GET请求携带参数是有上限的 post请求携带的参数是没有’上限的’
2:GET请求相对而言不安全,POST安全
面试题:H5新增那些特性?
CSS3、本地存储、多媒体、canvas
面试题:本地存储与会话存储区别?
本地存储可以长久保存,会话存储只在本次回话保存
第八天
前台项目三个重要地方:分页器、购物车、登录注册。
面试题:token相关的面试
- Vue项目,React尽可能别扔JSX。
情况:外包公司【Vue、React】
问题1:什么时候用router-link、什么时候用编程式导航。
- 如果一个按钮点击过后,如果只有路由跳转的业务【声明式导航、编程式导航】
- 如果点击一个按钮除了路由跳转,还有其他的业务,可以选择编程式导航。
问题2:promise问题。【基础问题】
1)加入购物车成功组件的业务?
- 让服务器存储加入购物车物品,和存储到本地存储
- 服务器存储成功:路由跳转
- 存储失败:提示
2)获取购物车的数据进行展示
举例子:用户是淘宝平台的用户。
-
为什么目前我们获取不到自己购物车的数据,你没有给我分配一个用户id
-
张三:奶粉、鞋子、手机
-
李四:羽绒服
-
-
问题1:用哪个技术可以生成用户id【身份】
- uuid
- 临时身份只需要执行一次
-
问题2:用户身份如何给后台专递过去?
requests.interceptors.request.use((config) => { nprogress.start(); config.headers.userTempId = localStorage.getItem("UUIDTOKEN"); return config; })
-
工作的时候不这么玩
- 会创建一个utils(工具)文件:把常用的代码片段放到这个文件夹里面
-
3.6配置一些文件[JS],不能操作仓库
- 配置文件不限执行,没办法运行项目【配置文件很少碰仓库】
设计购物车的数据
-
注意:获取购物车的数据的时候,读取的时候切记小心。后台老师写的数据格式有问题的。
-
张三:衣服、裤子、鞋子
[
{
cart:[ {name:'衣服'},{name:'裤子'},{name:'鞋子'}]
}
]
购物车静态结构需要注意
- 静态页面需要删除一些:把每一个产品的第三个li删除
- 需要修改每一个li的百分比:
- [con1 2 3 4 5 6 7]的百分比:15 35 10 17 10 13
3)购物车数量的操作?
修改购物车产品数量的时候,需要发请求的,通知服务器产品最新的个数【服务器需要保存】,
当你组件在获取购物车的数据时候,不就是最新的数值【用户刷新刷不掉】
-
产品个数变化接口参数:
-
skuID string Y 商品ID
-
skuNum:在修改产品个数的时候,需要给服务器传递的是【变化的数值】
-
-
比如:
- 佩奇 起始数量 4 用户在表单元素中输入 6 ----->给服务器参数是2
- 佩奇 起始数量4 用户在表单元素中输入1 ------>给服务器的参数-3
- 佩奇 起始的数量4 用户在表单元素中输入4 ------>给服务器的参数0
-
blur:失去焦点—>点击空白的地方
-
change:文本需要有变化,而且还需要点击空白的地方
-
input:只要文本发生变化立马执行【不许点击空白的地方】
数量操作的加减号节流优化
4)删除购物车中的产品的操作
- 熟练掌握 async await try catch
- 需要传递参数,产品的skuId
- 删除选中的购物车产品操作:利用Promise.all判断是否每个选中产品是否删除成功
5)购物车产品选中与未选中业务
-
购物车中产品的数据:isChecked属性,‘1’:代表这个产品勾选中 ‘0’:代表这个产品没有被选中
-
注意:以后工作的时候,最基本的基本功看API文档(在线文档),在开发后台管理系统项目的时候
一定要培养看在线文档能力
6)全选的业务
- 全选的复选框业务
- 目前而言:是没有这个接口,一次修改全部产品的选中状态接口【正常工作当中一定是有这样的接口:一次全部修改选中状态】
- 全选复选框:如果它勾上,顶上全部的产品的选中状态,勾上
- 全选复选框:如果它没勾上,顶上的全部产品的选装中台,没勾上
7)其他注意点
- 注意:函数防抖与节流【面试经常出现】
- 注意:用户有两个身份【临时游客、用户】
第九天
assets文件夹:经常放置一些静态资源(图片),assets文件夹里面资源webpack会进行打包为一个模块(js文件夹里面)
1)登录注册
对于企业当中,一般项目都有登录注册功能【这个业务很重要】
当然有一些项目不需要注册,后台管理系统项目,一般不需要注册。
-
登录与注册的静态组件(图片问题会报错)
-
assets【放置静态资源文件的地方】
- 一般放置所有组件共用的静态资源
- assets文件夹:经常放置一些静态资源(图片),assets文件夹里面资源webpack会进行打包为一个模块(js文件夹里面)
- 在样式当中也可以使用@,在样式当中使用@,前面加上~
background: url(~@/assets/images/icons.png) no-repeat -10px -201px;
也可以
background: url("@/assets/images/icons.png") no-repeat -10px -201px;
- 注册页面修改发送验证码的按钮
<button style="width: 100px; height: 38px">获取验证码</button>
2)注册的业务
注册业务
-
现在在做注册、登录业务的时候,先不处理表单的验证功能,在项目最后一天,在把表单如何验证,哪些插件解决【最后去处理】
- 正则
- 手机号:11
- 验证码:4-6
- 登录密码|确认密码:首字母大写、包含英文、数字、特殊字符等等。
-
获取验证码【api文档最后,其中15. 获取注册验证码 不可用 】
- /api/user/passport/sendCode/{phone}
- get
- 返回验证码,而不是发到手机上
-
token面试题:项目当中token过期、失效如何处理?
- 答:清除本地token(本地存储),让用户回到登录页,获取最新的token
-
注册业务【手机号、验证码、登录密码】,点击注册按钮的时候,需要把这些信息给服务器传递过去
- 手机号:11位
- 验证码:4-6
- 登录密码:英文字母、数字、首字母大写等等
登录业务
当你点击登录按钮的时候,需要把手机号、密码需要携带给服务器,服务器需要判断,你是不是我的用户【注册过的】
如果是用户登录成功,进行登录,如果用户登录失败给一个提示即可。
- token【令牌:字符串,服务器下发给用户的身份凭证】
举例子:古代大战,兵符
一、用户登录以后获取用户信息进行展示
-
企业项目:登录成功以后,服务器会返回token【存储于vuex当中】,如果想获取用户信息
-
还需要再发请求【用户信息】,携带token给服务器。
-
api/user/passport/auth/getUserInfo 获取用户信息的接口
-
为什么刷新页面,用户信息就消失
- 用户刷新页面,用户信息消失没了获取不到,因为token没有携带给服务器。
- Vuex存储数据是否持持久化的?并非持久化
- 本地存储持久化存储token
-
为什么去别的模块【非home模块】获取用户信息失败?
-
因为你去别的模块根本没有发请求获取用户信息,没办法展示用户信息
-
怎么解决:
- 每一个组件都在mounted里面发起获取用户信息,进行展示(可以太麻烦)
- 残留的问题:用户在home模块刷新的时候,用户信息一直在展示(mounted执行的时候在向服务器发请求、获取用户信息展示)
-
- 登陆成功后不可以进入登录页面
二、退出登录
- 发请求,需要通知服务器,把现在用户身份token【销毁】
- 清除仓库(vuex)数据+本地存储数据【都需要清理】
三、导航守卫
- 全局守卫:
- 项目当中任何路由变化都可以检测到,通过条件判断可不可以进行路由跳转。
- 前置守卫:路由跳转之前可以做一些事情。
- 后置守卫:路由跳转已经完成在执行。
//全局守卫:[后置守卫:在路由跳转完毕之后才会执行一次]
router.afterEach(()=>{
console.log('守卫:路由跳转完毕才会执行一次')
})
用户已经登录了,不应该在访问login?【通过什么条件能判断用户登录、未登录】
-
路由独享守卫:
- 针对某一个路由的守卫
-
组件内守卫:
- 也是负责某一个路由守卫
登录页面的登录按钮点击取消默认行为,否则有bug
-
身份凭证
-
TOKEN身份为大
-
UUID生成的临时省份
-
用户(注册与登录)token【正式身份】
-
第十天
不要再生命周期中使用async
1)交易业务
获取用户地址信息,需要下面账号,要不就自己模拟数据
- 账号:13700000000
- 密码:111111
获取用户地址信息、获取用户购物车清单信息
//用户地址信息
/api/user/userAddress/auth/findUserAddressList
//商品清单接口
/api/order/auth/trade
展示购物车清单数据
2)提交订单业务
- 练习不使用vuex发送数据
//引入所有API
import * as API from "@/api"
new Vue({
render: h => h(App),
router,
store,
beforeCreate() {
Vue.prototype.$bus = this; //安装全局事件总线,$bus就是当前应用的vm
Vue.prototype.$API = API;
},
}).$mount('#app')
-
当用户点击提交订单按钮的时候,需要发请求的
-
提交订单的请求地址:/api/order/auth/submitOrder?tradeNo={tradeNo}
-
前台:需要告诉服务器:谁买的、买的啥、买几个、 支付多少钱、留言信息…
-
后台:订单号,这笔交易的一个标识符【支付的】
-
axios({url:‘xxx’,methods:‘post’,data:{a:1}})
微信支付、支付宝支付等等
- 交易编码(服务器:字符串hash)
- 收件人名字
- 收件人手机号
- 收件的地址
- 买家留言信息
- 支付产品
3)获取支付信息进行展示
export const reqPayment = (orderId) => requests({ url: `/payment/weixin/createNative/${orderId}`, method: "get" })
- 支付二维码弹出使用element-ui
4)element-ui官方UI组件库(插件)?
vscode插件:vue-helper:拓展element-ui组件库
-
react框架:
- UI组件库antd【蚂蚁金服旗下PC端UI组件库,也有vue】
- antd-mobile【蚂蚁金服旗下的移动端UI组件库】
-
Vue框架:
- element-UI【饿了吗旗下的UI组件库,官方承认的PC组件库插件】
- vant【Vue官方提供移动端UI组件库】
- 官网地址: https://element.eleme/#/zh-CN
- 官网地址: https://youzan.github.io/vant/#/zh-CN/
Element UI基本使用
- 项目中安装element-ui组件库 [2.15.6版本:Vue2]
npm i element-ui -S
- 在入口文件引入elementUI组件库
完整引入
在 main.js 中写入以下内容:
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
});
按需引入
按需引入
借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。
首先,安装 babel-plugin-component:
npm install babel-plugin-component -D
然后,将 .babelrc(.babel.config.js) 修改为:
- 文档中说的.babelrc文件,即为babel.config.js文件
- 修改完babel.config.js配置文件以后,项目重启
{
presets: [
'@vue/cli-plugin-babel/preset'
],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
接下来,如果你只希望引入部分组件,那么需要在 main.js 中写入以下内容:
按照需求引入相应的组件即可
Vueponent();
Vue.prototype.$xxx = xxx;
import Vue from 'vue';
import { Button, Select } from 'element-ui';
import App from './App.vue';
//饿了么ui组件
import { Button, MessageBox } from "element-ui"
Vue.component(Button.name, Button)
// Vue.prototype.$msgbox = MessageBox;
Vue.prototype.$alert = MessageBox.alert;
new Vue({
el: '#app',
render: h => h(App)
});
5)支付业务【微信支付】
弹窗MessageBox:使用 HTML 片段
this.$alert(`<img src=${url} />`, "请你微信支付", {
dangerouslyUseHTMLString: true,
//中间布局
center: true,
//是否显示取消按钮
showCancelButton: true,
//取消按钮的文本内容
cancelButtonText: "支付遇见问题",
//确定按钮的文本
confirmButtonText: "已支付成功",
//右上角的叉子没了
showClose: false,
//关闭弹出框的配置值
beforeClose: (type, instance, done) => {
//type:区分取消|确定按钮
//instance:当前组件实例
//done:关闭弹出框的方法
if (type == "cancel") {
alert("请联系管理员豪哥");
//清除定时器
clearInterval(this.timer);
this.timer = null;
//关闭弹出框
done();
} else {
//判断是否真的支付了
//开发人员:为了自己方便,这里判断先不要了
// if (this.code == 200) {
clearInterval(this.timer);
this.timer = null;
done();
this.$router.push("/paysuccess");
// }
}
},
});
- 根据官方给的属性再稍加配置
codeUrl:"weixin://wxpay/bizpayurl?pr=A6XYgvyzz" //是一个字符串
qrCode字符串转换为加密的在线二维码
- npm官网:搜qrCode
通过qrCode.toDataUrl方法,将字符串转换为加密的在线二维码链接,通过图片进行展示。
1.安装
npm i qrcode
2.引入
import QRCode from 'qrcode'
3.使用
const url = await QRCode.toDataURL(this.payInfo.codeUrl);
js库推荐
- moment.js 时间格式化
- swiper.js 轮播图
- nprogress.js 进度条
- qrcode.js 字符串转换为加密的在线二维码
判断支付状态
GET|POST:短轮询,请求发一次,服务器响应一次,完事。
-
第一种做法:前端开启定时器,一直找服务器要用户支付信息【定时器】
-
第二种做法:项目务必要上线 + 和后台紧密配合
当用户支付成功以后,需要后台重定向到项目某一个路由中,将支付情况通过URL参数形式传给前端,
前端获取到服务器返回的参数,就可以判断了。
第十一天
1)个人中心路由搭建
- 当年学习路由的时候:一级路由、二级路由、三级路由 【二级路由搭建】
- 完成个人中心数据的展示【分页】
2)未登录全局守卫的判断
-
前置守卫:在路由跳转之前,进行判断
-
后置守卫:路由都已经跳转完毕才执行。
-
全局守卫:只要的项目当中任何某一个路由发生变化,就会出发。
-
组件内守卫有三个,进入时beforeRouteEnter,更新时(动态路径)beforeRouteUpdate (2.2 新增),离开时beforeRouteLeave
-
组件内守卫:也是专门负责某一个路由【并非负责全部路由】,写法和路由独享守卫有区别?
- 路由独享守卫:需要在配置路由的地方使用
- 组件内守卫需要书写在组件内部
未登录的情况:
用户未登录:
- 点击购物车的结算按钮->交易页面【没有登录:去不了】
- 未登录不能调到支付页面
- 未登录不能调到支付成功页面
- 未登录不能去个人中心【都不知道你是谁:展示谁的个人中心啊】
所以到这写页面直接到登录页面,登陆完需要回到这些页面
-
去交易页面:从购物车才能跳转到交易页面。
-
next():你本来想去哪里,我就放行,你就去完事了。
-
next(’/login’):执行守卫放行到执行的路由。
-
next(false):路由跳转的时候,从哪里来回那里去。
3)图片懒加载
vue-lazyload:图片懒加载
图片:用户网络不好,服务器的数据没有回来,总不可能让用户看白色,至少有一个默认图片在展示。
// 安装 npm i vue-lazyload
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
// or with options
Vue.use(VueLazyload, {
preLoad: 1.3,
error: 'dist/error.png',
loading: 'dist/loading.gif', //懒加载图片
attempt: 1
})
//多了一个指令 v-lazy <img v-lazy="img.src" >
// 用v-lazy代替:src
4)路由懒加载
复习路由知识点
- 路由守卫
- 路由元信息 meta
- 滚动行为
- 路由懒加载
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。
如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
步骤
- 首先,可以将异步组件定义为返回一个 Promise 的工厂函数 (该函数返回的 Promise 应该 resolve 组件本身):
const Foo = () =>
Promise.resolve({
/* 组件定义对象 */
})
- 第二,在 Webpack 2 中,我们可以使用
动态 import
语法来定义代码分块点 (split point):
import('./Foo.vue') // 返回 Promise //我们不需要做第一步了
- 引入组件
const Foo = () => import('./Foo.vue')
- 在路由配置中什么都不需要改变,只需要像往常一样使用
Foo
const router = new VueRouter({
routes: [{ path: '/foo', component: Foo }]
})
面试【高频的面试】:项目的性能优化手段有哪些?
- v-if|v-show:尽可能采用v-show
- 按需引入【lodash、elementUI】
- 防抖与节流
- 路由懒加载:当用户访问的时候,加载对应组件进行展示。
5)表单验证
- 以后工作的时候经常会进行表单验证【element-ui】进行表单验证,so 简单。
- 项目当中表单验证功能比较常见的。
vee-validate插件
- vee-validate插件:Vue官方提供的一个表单验证的插件
- 这个插件很难用:如果你翻看它的文档(看一个月:不保证能看懂),依赖文件很多(文档书写的很难理解)花大量时间学习,很难搞懂。
使用步骤:
1:安装vee-validate,别安装最新版本@2
npm i vee-validate@2
2:在plugins文件夹中创建一个validate.js[专门注册vee-valadite]
3: 注册插件
插件安装与引入
import Vue from 'vue'
import VeeValidate from 'vee-validate'
import zh_CN from 'vee-validate/dist/locale/zh_CN' // 引入中文 message
Vue.use(VeeValidate)
提示信息:注册插件的时候,用中文,以及需要验证的字段【用中文显示提示形式】
VeeValidate.Validator.localize('zh_CN', {
messages: {
...zh_CN.messages,
is: (field) => `${field}必须与密码相同` // 修改内置规则的 message,让确认密码和密码相同
},
attributes: { // 给校验的 field 属性名映射中文名称
phone: '手机号',
code: '验证码',
password: '密码',
password1: '确认密码',
agree: '协议'
}
})
//自定义校验规则
//定义协议必须打勾同意
VeeValidate.Validator.extend('agree', {
validate: value => {
return value
},
getMessage: field => field + '必须同意'
})
4:在入口文件需要引入执行一次
import "@/plugins/validate.js"
5: 使用vee-valadiate插件
<input
placeholder="请输入你的手机号"
v-model="phone"
name="phone"
v-validate="{ required: true, regex: /^1\d{10}$/ }"
:class="{ invalid: errors.has('phone') }"
/>
<span class="error-msg">{{ errors.first("phone") }}</span>
//确认密码写法
//v-validate="{ required: true, is:password }"
const success = await this.$validator.validateAll(); //全部表单验证 返回true 或 false
打包
npm run build
-
项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错。
-
有了
.map文件
就可以像未加密的代码一样,准确的输出是哪一行哪一列有错。 -
所以该文件如果项目
.map文件
不需要是可以去除掉- vue.config.js配置
- productionSourceMap:false
本地部署node.js
// npm init -y
// npm i express
// npm i connect-history-api-fallback //解决history模式刷新404的问题//也可以用nginx解决
//服务器
const express = require('express')
const app = express()
app.use(express.static(__dirname + '/static'))
app.get('/person', (req, res) => {
res.send({
name: 'tom',
age: 18
})
})
app.listen(5005, (err) => {
if (!err) console.log('服务器启动成功');
})
购买服务器
- 腾讯云服务器
- 设置安全组,让服务器的一些端口号打开,我们远程登录需要22端口
- 控制台搜索安全组
- Xshell 登录服务器
- 需要了解一下linux 命令
- cd 跳转目录 ls 查看 mkdir创建目录
nginx反向代理
- 到
/etc
目录中
location / {
root /lightofd/www/shangpinhui;
index index.html;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://39.98.123.211;
}
这里我配置失败,配置一天找到一个方便的配置方式
-
首先我们需要在腾讯云买一个服务器
-
到控制台
-
搜索轻量
-
重装系统
-
选择宝塔
-
点击空白进入服务器
-
找到这个面板,点击管理应用
-
点击防火墙里的添加规则,端口位置输入 20,21,888,8888 然后确定,老师讲的安全组也要操作一下
-
然后就可以去这里完成登录注册操作,
-
直接点击默认安装
-
点击网站栏的添加站点
-
*
-
上一步操作完是这样
- 回到网站栏看我们新加网站右侧有一个设置符号,我们进行设置代理
- 提交后点击配置文件
- 这一步很重要,要不然请求不到尚硅谷的数据
遇到的问题
try 捕捉返回promis对象函数错误,一般要在前加上 await进行捕捉 否则无法进入catch
更多推荐
尚品汇项目听课总结
发布评论