支付实现的流程
支付宝:
- 用户点击购买,向后端发送请求
- 后端接收请求,根据商品信息和金额等参数,生成订单,返回给前端
- 用户确认订单信息,点击支付
- 后端收到前端发送的支付请求,向支付宝后台发送预支付请求
- 支付宝收到请求,核对订单信息,返回后台支付链接
- 后台收到支付链接,返回给前端
- 前端收到链接,直接跳转到支付页面,进行支付。
小程序: - 用户在小程序中点击支付,向后台发送支付接口
- 后台收到请求,向微信服务器发送小程序登录API请求,微信后台收到请求,返回给后台一个 Openid()
- 在后台生成商户订单后,调用支付统一下单API,微信服务器处理后返回给后台预付单的信息
- 后台接收到了返回的预付单的信息对这些信息进行再次加密返回给前端,前端这时候监听到了后端返回的数据后,利用这些数据调用(包括:时间戳、随机字符串、package(prepay_id)、签名等),wx.pay()的方法,然后在用户页面弹出确认支付的弹框
- 用户确认支付,直接在微信后台进行鉴权,微信后台直接返回给前端支付的结果,前端收到返回数据后对支付结果进行展示。
小程序授权
用户信息授权
- 新版授权:每次点击按钮,不管是否授权过,都会弹出窗口
wx.getUserProfile({
desc: "获取微信头像昵称用于权限调用",
success: (data) => {
// 用户允许时触发
console.log(data);
this.setData({
useInfo: data.userInfo,
});
},
fail: (res) => {
// 用户拒绝时触发
console.log(res);
wx.showToast({
icon: "none",
title: "需要授权请重新点击",
});
},
});
- 旧版授权:使用固定格式的 button 弹起授权窗口,如果拒绝,下次点击还可以弹起窗口;若已授权,再次点击就不再弹出授权窗口了;可以通过清理授权数据将之前的授权信息清除掉。
<button open-type="getUserInfo" bindgetuserinfo="oldState">旧版本 getUserInfo API</button>
// 先判断用户是否授权
wx.getSetting({
success(res) {
if (res.authSetting["scope.userInfo"]) {
wx.getUserInfo({
success(data) {
console.log(data);
},
fail(err) {
console.log("--", err);
},
});
} else {
wx.showToast({
icon: "none",
title: "请先授权",
});
}
},
fail() {},
});
普通授权:定位、录音、定位等。
// 在调用 wx.authorize() 之前,会先通过 getSetting()获取当前授权状态,再决定是否进行授权。
// wx.getSetting() 获取用户权限设置列表,返回值中只包含用户已经向小程序请求过的权限和一些默认的权限信息,比如:通讯地址,发票抬头,发票等不需要 wx.authorize() 进行授权。
wx.getSetting({
success(res) {
if (!res.authSetting["scope.record"]) {
// 发现没有授权过,就可以弹出授权窗口了。
// wx.authorize() 会弹起授权窗口,用户 拒绝/同意 之后,再次调用不会弹出授权窗口了,需要使用 openSetting()引导用户进行设置页面,对已经请求过的权限进行打开或关闭。
wx.authorize({
scope: "scope.record", // scope表示权限范围,你要申请什么权限
success(res) {
// console.log("授权结果: ", res);
// 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问
// wx.startRecord()
},
fail(res) {
wx.showToast({
icon: "none",
title: '想重新授权,请在"设置-权限"中修改',
});
},
});
}
},
});
授权状态会一致保存在小程序后台,直到用户删除小程序,状态才会丢失
redux 基本使用(什么样的数据需要放在Redux中;项目中哪些地方使用了Redux)
- Redux 一般用于对公共状态的管理。
- Redux 三大核心:单一数据源、state 是只读的、使用纯函数来执行修改
- store 负责串联 React 和 Redux 之间的工作,当用户在组件中需要修改 Redux 的公共数据,需要触发 action,store 对象就会将这个 action 转发给 reducer,让 reducer 根据用户触发的 action,使用 dispatch 修改对应的 state,store 再将这个最新的 state 渲染到组件中。
- reducer:本质是一个函数,它是负责定义 Redux 中的初始 state 数据,以及后续根据 action 更新 state。总之她负责维护 Redux 中的公共数据 state。
- dispatch(action):分发 action 到 store
- 当文件规模过大时,使用单独文件 type.js 存放 action
项目中使用方法:
yarn add redux react-redux;
src 下创建 store 文件夹,用于存放 redux 相关内容;
store 文件夹里创建store.js、action.js、reducer.js;
在 App.js 组件中导入 react-redux ,使用<Provider store={store}></Provider>
包裹根组件;
目标组件导入 connect(高阶组件,用于建立组件和 Redux 之间的联系)包裹目标组件,返回值中的属性会合并到当前组件的 props 中。
- 什么样的数据需要放在Redux中
当某个组件的状态,需要共享
某个状态需要在任何地方都可以拿到
一个组件需要改变全局状态
一个组件需要改变另一个组件的状态
token 的使用流程及作用
- token,即令牌,是服务器产生的,具有随机性和不可预测性,它主要有两个作用:防止表单重复提交(token 不一致,则为重复提交)、用来作身份验证
- 使用流程
- 前端向后端传递用户名和密码;
- 后端将接收到的用户名和密码进行核实;
- 后端核实成功后,返回给前端一个 token(或者直接将 token 保存在 cookie 中);
- 前端得到 token,并将其保存;
- 如果前端请求隐私的接口(比如需要登陆后才能查看购物车),则需要传递保存的 token(进行 ajax 请求时,将信息放在请求头中);
- 后端对其进行验证,如果 token 正确,则获取相应数据,并返回给前端;若不正确,则请求不到数据,返回给前端相应的提示。
注意:用户每进行一次登录,登录成功后服务器都会更新一个 token 新值返回给客户端。
在后端接口没有出来之前,前端写完静态页面之后,如何生成模拟数据(mock.js模拟虚拟数据)
- mock.js :生成随机数据,拦截 Ajax 请求
只能使用 axios,fetch 请求无法拦截
- react mock 数据方式:
第一种方式:在
create-react-app
项目中直接 mock,无需 node
第二种方式:在 node 中 mock,需要会一点 node 知识,需要解决跨域
-
第一种方式:在
create-react-app
项目中直接 mock,无需 node步骤: 1. 安装mockjs,yarn add mockjs -D 或 npm i mockjs -D 2. 创建文件夹 src -> mock 3. 在mock文件夹创建文件 user.js,在 user.js引入mockjs,并写上mock数据 4. 在app或者入口文件中引入,发起请求会自动拦截对应的请求,如果不用,注释即可
-
第二种方式:在 node 中 mock
步骤: 1. 选择 node 框架 koa 或 express,安装相关依赖 2. 安装 mockjs,并引入 3. 配置路由(接口地址),并且编写 mock 数据 4. 解决跨域,可在前端解决,也可使用 node 解决
购物车功能如何实现
1.首先在前端那边设置一个加入购物车的按钮
2.点击按钮之后会通过ajax请求后台接口
3.后台接口会先判断用户是否登录
4.如果没登录,则提示登陆
5.如果登录了,根据商品 id,先查购物车,看该商品是否已经存在购物车
6.如果在则数量+1,如果不在则新增进购物车。
项目中防抖和节流使用哪一种方案?两者的区别
- 防抖:连续触发事件,一定时间内没有再触发事件,才执行一次函数,如果设定的时间到来之前,又一次触发了事件,就重新开始计时。常用于模糊查找、频繁操作点赞和取消点赞等。
//用定时器实现防抖
function debounce(func,wait) {
var timer=null;
return function() {
//保存当前调用的dom对象
var _this=this;
//保存事件对象
var args=arguments;
clearTimeout(timer)
timer=setTimeout(function() {
func.apply(_this,args)
},wait)
}
}
- 节流:连续触发事件,每隔一定时间就执行一次函数。常用于列表触底触底加载,窗口大小变化等。
//时间戳版本实现节流
function throttle(func,wait) {
//定义初始时间
var oldTime=0;
return function() {
var _this=this;
var args=arguments;
//当前时间戳
var newTime=+new Date();
//判断用当前时间减去旧的时间,如果大于wait指定的时间就会触发
if(newTime-oldTime>wait) {
//执行触发的函数
func.apply(_this,args)
//将旧时间更新
oldTime=newTime;
}
}
}
//时间戳版本实现节流
function throttle(func,wait) {
var timer=null;
return function() {
var _this=this;
var args=arguments;
if(!timer) {
timer=setTimeout(function() {
timer=null;
func.apply(_this,args)
},wait)
}
}
}
路由组件和普通组件的区别是什么
1.写法不同:
一般组件:<Demo/>
路由组件:<Route path="/demo" component={Demo}/>
2.存放位置不同:
一般组件:components
路由组件:pages
3.接收到的props不同:
一般组件:写组件标签时传递了什么,就能收到什么
路由组件:接收到三个固定的属性
history:
go: ƒ go(n)
goBack: ƒ goBack()
goForward: ƒ goForward()
push: ƒ push(path, state)
replace: ƒ replace(path, state)
location:
pathname: "/about"
search: ""
state: undefined
match:
params: {}
path: "/about"
url: "/about"
需要跳转到其他页面,使用路由组件;不需要跳转时,就使用普通组件。
路由懒加载和组件懒加载如何实现?好处是什么
- 使用方法:
- 导入 Suspense 组件,import React, { Suspense } from “react”;;
- 修改组件导入语句,例如:import Test from “./pages/Test”;,改为:const Test = React.lazy(() => import("./pages/Test "));;
- App.js 中,使用 Suspense 包裹全部路由组件,另外,Suspense 需要加 fallback 属性,提供加载时的过渡画面,如
<Router>
<Suspense
fallback={
<div className="centered">
<LoadingSpinner />
</div>
}
>
路由组件
</Suspense>
</Router>
- 优势:使网页首次加载速度变快,使用懒加载后,用户访问页面,根据访问到的路径实时按需加载相应的代码。这样,用户不需要一开始就下载大量的代码,因为其中一些代码可能不需要用到。
如何解决白屏问题?(骨架屏、全局loading加载器)
如何解决首屏加载过慢的问题
- 路由懒加载
- 静态资源本地缓存
- 图片压缩
- 减少重复请求
- UI 框架按需加载
- 开启 GZip 压缩
- 代码优化
移动端适配方案,说出具体思路
- 根据设计稿大小,直接具体宽度/设计稿宽度,得出 rem 值。
.box{
width:200/375rem;
height:200/375rem;
}
- 借助 media 实现 rem 适配:rem 只与根元素字体大小有关,即 html 根元素。大部分浏览器的默认字体大小都是16px,所以1rem = 16px。
长度单位都是用 rem 设置;
当屏幕尺寸改变时,只需要修改 html 元素的 font-size 即可实现等比适配;
我们在制作页面的时候,只考虑跟设计稿相同的屏幕尺寸即可,其他尺寸屏幕自动适配。
//对屏幕大小划分了html不同的font-size
@media screen and (min-width: 320px) {html{font-size:50px;}}
@media screen and (min-width: 360px) {html{font-size:56.25px;}}
@media screen and (min-width: 375px) {html{font-size:58.59375px;}}
@media screen and (min-width: 400px) {html{font-size:62.5px;}}
@media screen and (min-width: 414px) {html{font-size:64.6875px;}}
@media screen and (min-width: 440px) {html{font-size:68.75px;}}
@media screen and (min-width: 480px) {html{font-size:75px;}}
@media screen and (min-width: 520px) {html{font-size:81.25px;}}
@media screen and (min-width: 560px) {html{font-size:87.5px;}}
@media screen and (min-width: 600px) {html{font-size:93.75px;}}
@media screen and (min-width: 640px) {html{font-size:100px;}}
@media screen and (min-width: 680px) {html{font-size:106.25px;}}
@media screen and (min-width: 720px) {html{font-size:112.5px;}}
@media screen and (min-width: 760px) {html{font-size:118.75px;}}
@media screen and (min-width: 800px) {html{font-size:125px;}}
@media screen and (min-width: 960px) {html{font-size:150px;}}
- viewport 适配:通过设置 initial-scale , 将所有设备布局视口的宽度调整为设计图的宽度。
//获取meta节点
var metaNode = document.querySelector('meta[name=viewport]');
//定义设计稿宽度为375
var designWidth = 375;
//计算当前屏幕的宽度与设计稿比例
var scale = document.documentElement.clientWidth/designWidth;
//通过设置meta元素中content的initial-scale值达到移动端适配
meta.content="initial-scale="+scale+",minimum-scale="+scale+",maximum-scale="+scale+",user-scalable=no";
递归的实现思路
-
递归:在一个函数内部,自己调用自己的过程,被称为递归。
-
构成递归需具备的条件:
1. 自身调用:原问题可以分解为子问题,子问题和原问题的求解方法是一致的,即都是调用自身的同一个函数。 2. 终止条件:递归必须有一个终止的条件,即不能无限循环地调用本身。
React中引起页面渲染的几种情况
- 初次加载组件的时候,会 render 一次
- 当数据(props、state)更新时,会 render
- 调用
this.forceUpdate()
强制更新时,会 render
state中的数组和对象,如果发生了元素或者属性值的修改,是否会引起页面渲染?为什么?
不会,必须生成新数组或对象,因为React对于引用类型的数据对象是浅层对比,只观察对象本身是否变化,无法监测对象内部的数据变化,可以使用展开运算符生成新对象或使用immutable
更多推荐
项目中的问题
发布评论