1. 如何理解 HTML 语义化?
让人更容易读懂(增加代码可读性)。比如video、audio、header(头部)、footor(底部)
2. script 标签中 defer 和 async 的区别?
defer是“渲染完再执行”,async是“下载完就执行”。
举例: 上课期间老师一直讲课,上课中提了一个问题,
defer 的方式是下课后再和同学交流这个问题
async 是有同学想出来了,上课暂时中断,交流提出的问题
3. 从浏览器地址栏输入 url 到请求返回发生了什么
1.解析URL,构建一个请求
2.DNS域名解析
3.TCP连接(三次握手)
4.请求处理
5.浏览器拿到数据后做相应的操作
6.TCP断开(四次挥手)
5. 盒模型 (指的是宽、高属性依据)
1 标准盒模型 (默认使用)
设置宽高属性后只包含 content
2.IE盒模型
设置宽高属性后包含 content + padding + border
6. css 选择器和优先级
内联 > ID选择器 > 类选择器 > 标签选择器。
重排(reflow)和重绘(repaint)的理解
- 发生重排一定会发生重绘
- 如何减少重排和重绘?
脱离文档流、虚拟DOM
对 BFC(块级格式上下文) 的理解
- 是指当前元素的一个矩形区域
创建 BFC 的方式:
绝对定位元素(position 为 absolute 或 fixed )。
行内块元素,即 display 为 inline-block 。
overflow 的值为 hidden (比较推荐这种方式) 。
可以解决的布局问题
- 避免 margin 重叠问题。
- 避免高度塌陷。
水平垂直居中多种实现方式
- 不定宽高:
利用绝对定位,设置 left: 50% 和 top: 50% 现将子元素左上角移到父元素中心位置,然后再通过 translate 来调整子元素的中心点到父元素的中心。
.father {
position: relative;
}
.son {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
- 定宽高:
利用绝对定位,子元素所有方向都为 0 ,将 margin 设置为 auto ,由于宽高固定,对应方向实现平分。
.father {
position: relative;
}
.son {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0px;
margin: auto;
height: 100px;
width: 100px;
}
利用绝对定位,设置 left: 50% 和 top: 50% 现将子元素左上角移到父元素中心位置,然后再通过 margin-left 和 margin-top 以子元素自己的一半宽高进行负值赋值。
.father {
position: relative;
}
.son {
position: absolute;
left: 50%;
top: 50%;
width: 200px;
height: 200px;
margin-left: -100px;
margin-top: -100px;
}
- 定不定宽高无所谓
利用 flex ,最经典最方便的一种
.father {
display: flex;
justify-content: center;
align-items: center;
}
flex 布局
单词读熟悉 详细请看这里
flex-direction
justify-content
align-items
align-content
flex-wrap
flex-flow
怎么理解flex:1 ? 可以说是弹性比例的权重,如果有两个元素都设置flex:1, 相当于平分父的宽或高
深拷贝与浅拷贝
深拷贝:增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存
浅拷贝:只是增加了一个指针指向已存在的内存地址
对比举例:
const a={
name: "wang",
age:18
}
const b = a;
b.age = 20;
console.log(a); // {name:"wang",age:20}
console.log(b);//{name:"wang",age:20}
实质:如果A拷贝B,修改A中的值,观察B是否变化,如果B变化则是浅拷贝,如果不变化则是深拷贝
浅拷贝实现:
- Object.assign() 或者 展开运算符号(...)
var obj = { a: {a: "kobe", b: 39} };
var initalObj = Object.assign({}, obj);
initalObj.a.a = "wade";
console.log(obj.a.a); //wade
当object只有一层的时候,是深拷贝
let obj = {
username: 'kobe'
};
let obj2 = Object.assign({},obj);
obj2.username = 'wade';
console.log(obj); //{username: "kobe"}
- 深拷贝实现
- 方式1: 递归+Object.assign() 或者 ...(展开运算符)
把浅拷贝 通过递归的方式处理一遍就可以实现深拷贝,因为对象只有一层的时候是深拷贝。
function checkedType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
//实现深度克隆---对象/数组
function clone(target) {
//判断拷贝的数据类型
//初始化变量result 成为最终克隆的数据
let result, targetType = checkedType(target)
if (targetType === 'Object') {
result = {}
} else if (targetType === 'Array') {
result = []
} else {
return target
}
//遍历目标数据
for (let i in target) {
//获取遍历数据结构的每一项值。
let value = target[i]
//判断目标结构里的每一值是否存在对象/数组
if (checkedType(value) === 'Object' ||
checkedType(value) === 'Array') { //对象/数组里嵌套了对象/数组
//继续遍历获取到value值
result[i] = clone(value)
} else { //获取到value值是基本的数据类型或者是函数。
result[i] = value;
}
}
return result
}
- 方式2:如果数据是json格式 通过 JSON.parse(JSON.stringify())
- 方式3:函数库lodash
0.1+0.2 ! == 0.3 如何做到让其相等呢?
使用 Number.EPSILON 误差范围。
function isEqual(a, b) {
return Math.abs(a - b) < Number.EPSILON;
}
console.log(isEqual(0.1 + 0.2, 0.3)); // true
理解 原型与原型链
原型:每一个 JavaScript 对象(null 除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性,其实就是 prototype 对象。
原型链:由相互关联的原型组成的链状结构就是原型链。
我们声明了一个Person函数,既然函数是对象,那么我们就可以使用“.”来查看它的属性,可以看到有一个prototype属性,这个是每一个函数都有的。
我们在代码里面打印出来看看,理解原型示例代码如下:
<script>
function Person() { }
console.log(Person.prototype)
</script>
输出结果:
image.png理解原型链示例代码:
<script>
function Person(name) {
this.name = name;
}
// 在函数的原型上添加变量和方法
Person.prototype.name = "信思智学";
Person.prototype.say = function () {
console.log("你好信思智学");
}
let obj = new Person("张三");
console.log(obj.name); // 张三
obj.say(); // 你好信思智学
console.log(obj)
</script>
image.png
可通过打印的日志,辅助理解原型链
执行上下文
回答和this相关,可以提到箭头函数
以下代码辅助理解 this
var obj = {
foo: function () { console.log(this.bar) },
bar: 1
};
var foo = obj.foo;
var bar = 2;
obj.foo() // 1
foo() // 2
闭包理解
用途或者说使用场景:封装私有变量
不会引起内存泄漏!!! IE9之前是有问题的,现在的浏览器都没问题
var person = function(){
//变量作用域为函数内部,外部无法访问
var name = "default";
return {
getName : function(){
return name;
},
setName : function(newName){
name = newName;
}
}
}();
console.log(person.name);//直接访问,结果为undefined
console.log(person)
console.log(person.getName()); //default
person.setName("abruzzi");
console.log(person.getName()); //abruzzi
Promise
面试ES6 开始使用的异步编程解决方式,主要用来解决回调地狱的问题,可以有效的减少回调嵌套, 更符合编码思维
在哪用到过呢?
uni-app中关于 request 请求的封装
image.pngreact 中配合async await,实现数据的同步调用
垃圾回收机制
深入了解这里看这篇文章即可:「硬核 JS」你真的了解垃圾回收机制吗。
总结一下:
有两种垃圾回收策略:
- 标记清除:标记阶段即为所有活动对象做上标记,清除阶段则把没有标记(也就是非活动对象)销毁。
function test(){
let A = new Object() // 有标记
let B = new Object() // 有标记
}
test() // 执行完毕后 标记为清除对象
- 引用计数:它把对象是否不再需要简化定义为对象有没有其他对象引用到它。如果没有引用指向该对象(引用计数为 0),对象将被垃圾回收机制回收。
let a = new Object() // 此对象的引用计数为 1(a引用)
let b = a // 此对象的引用计数是 2(a,b引用)
a = null // 此对象的引用计数为 1(b引用)
b = null // 此对象的引用计数为 0(无引用)
... // GC 回收此对象
这种方式是不是很简单?确实很简单,不过在引用计数这种算法出现没多久,就遇到了一个很严重的问题——循环引用,即对象 A 有一个指针指向对象 B,而对象 B 也引用了对象 A ,如下面这个例子
function test(){
let A = new Object()
let B = new Object()
A.b = B
B.a = A
}
对象 A 和 B 通过各自的属性相互引用着,按照上文的引用计数策略,它们的引用数量都是 2,但是,在函数 test 执行完成之后,对象 A 和 B 是要被清理的,但使用引用计数则不会被清理,因为它们的引用数量不会变成 0,假如此函数在程序中被多次调用,那么就会造成大量的内存不会被释放
防抖与节流
-
1.debounce(防抖)和throttle(节流)的定义
口语版: 小胖减肥
防抖就是只有当小胖连续10天做运动,卡路里消耗达标。如果在这10天内小胖有一天偷懒,运动时长不达标,减肥没有效果,直到满足了10天连续运动,一个月下来只能达标2次
节流就是无论小胖运动量与否达标,每隔10天就记录一次达标。一个月下来能达标3次。
防抖是有条件的周期动作,而节流是没有条件的周期动作。
书面版:
防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。
节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。 -
2.防抖和节流解决的都是短时间高频次的调用问题
在进行resize、scroll、keyup、keydown、mousedown、mousemove等事件操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,容易导致页面卡顿等影响用户的体验;这时就可以通过debounce(防抖)和throttle(节流)函数来限制事件处理函数的调用频率,提升用户的体验,同时又不影响实际的效果。 -
3.防抖和节流的应用场景
防抖
1.登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖。
2.文本编辑器实时保存,当无任何更改操作一秒后进行保存。
3.DOM 元素的拖拽功能实现。
节流
1.scroll 事件,每隔一秒计算一次位置信息等。
2.浏览器播放事件,播放音频、视频、每隔一秒计算一次进度信息等。
3.input框实时搜索并发送请求展示下拉列表,每隔一秒发送一次请求 (也可做防抖)。
如何避免内存泄漏
- 减少不必要的全局变量,使用严格模式避免意外创建全局变量。
例如:无意义的变量提升
- 在你使用完数据后,及时解除引用(闭包中的变量,dom引用,定时器清除)。
例如: 轮播图的定时器,setTimeOut /setInterval 要根据ID及时清除
- 组织好你的逻辑,避免死循环等造成浏览器卡顿,崩溃的问题。
例如:递归的方法要有终止递归进行的条件判断
React 面试相关
React 16.8 加入的新特性
必须在函数数式组件中使用(类组件可以不用看了,简单了解就行)
-
hooks优势是什么?
不会造成浏览器阻塞
不用考虑this的指向性问题
更容易复用代码
函数式编程,每个功能都包裹在函数中,整体风格更清爽,更优雅 -
useEffect、useLayoutEffect区别:
useEffect是异步执行,而useLayoutEffect是同步执行的。useEffect是在页面渲染完毕之后执行hooks,uselayoutEffect是在页面渲染之前执行hooks,所以uselayoutEffect会导致页面渲染堵塞,而useEffect有可能会导致页面闪动,99的情况下都用useeffect。 -
说对React的理解?有哪些特性?
React,用于构建用户界面的 JavaScript 库,使用虚拟DOM来有效地操作DOM,遵循从高阶组件到低阶组件的单向数据流,帮助我们将界面成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,构成整体页面.
特性和优势- JSX语法
- 单向数据绑定
- 虚拟DOM
- Component(组件化)
- 高效灵活
- 组件式开发,提高代码复用率
- 单向响应的数据流会比双向绑定的更安全,速度更快
-
类组件和函数组件之间有什么区别
- 类组件:
无论是使用函数或是类来声明一个组件,它决不能修改它自己的 props。
所有 React 组件都必须是纯函数,并禁止修改其自身 props。
React是单项数据流,父组件改变了属性,那么子组件视图会更新。
属性 props是外界传递过来的,状态 state是组件本身的,状态可以在组件中任意修改
组件的属性和状态改变都会更新视图。 - 函数组件:
函数组件接收一个单一的 props 对象并返回了一个React元素
函数组件的性能比类组件的性能要高,为了提高性能,尽量使用函数组件。
- 类组件:
-
React.memo() 和 React.useMemo() 的区别
memo 是一个高阶组件,默认情况下会对 props 进行浅比较,如果相等不会重新渲染。多数情况下我们比较的都是引用类型,浅比较就会失效,所以我们可以传入第二个参数手动控制。
useMemo 返回的是一个缓存值,只有依赖发生变化时才会去重新执行作为第一个参数的函数,需要记住的是,useMemo 是在 render 阶段执行的,所以不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴
-
React.useCallback() 和 React.useMemo() 的区别
useCallback 可缓存函数,其实就是避免每次重新渲染后都去重新执行一个新的函数。
useMemo 可缓存值。
-
React 性能优化手段
使用 React.memo 来缓存组件。
使用 React.useMemo 缓存大量的计算
避免使用匿名函数。
使用 React.Fragment 避免添加额外的 DOM。
-
React key 是干嘛用的,同级复用标签的时候为什么要加? key 主要是解决哪一类问题的
Keys 是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。在开发过程中,我们需要保证某个元素的 key 在其同级元素中具有唯一性。
-
对React中Fragment的理解,它的使用场景是什么?
在React中,组件返回的元素只能有一个根元素。为了不添加多余的DOM节点,我们可以使用Fragment标签来包裹所有的元素,Fragment标签不会渲染出任何元素。React官方对Fragment的解释:
React 中的一个常见模式是一个组件返回多个元素。Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。
import React, { Component, Fragment } from 'react'
// 一般形式
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
// 也可以写成以下形式
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
-
说说对React refs 的理解?应用场景?
Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。
创建ref的形式有四种:
- 传入字符串,使用时通过 this.refs.传入的字符串的格式获取对应的元素
只需要在对应元素或组件中ref属性
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref="myref" />;
}
}
访问当前节点的方式如下:
this.refs.myref.innerHTML = "hello";
- 传入对象,对象是通过 React.createRef() 方式创建出来,使用时获取到创建的对象中存在 current 属性就是对应的元素
refs通过React.createRef()创建,然后将ref属性添加到React元素中,如下:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
当 ref 被传递给 render 中的元素时,对该节点的引用可以在 ref 的 current 属性中访问
const node = this.myRef.current;
- 传入函数,该函数会在 DOM 被挂载时进行回调,这个函数会传入一个 元素对象,可以自己保存,使用时,直接拿到之前保存的元素对象即可
当ref传入为一个函数的时候,在渲染过程中,回调函数参数会传入一个元素对象,然后通过实例将对象进行保存
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={element => this.myref = element} />;
}
}
获取ref对象只需要通过先前存储的对象即可
const node = this.myref
- 传入hook,hook是通过 useRef() 方式创建,使用时通过生成hook对象的 current 属性就是对应的元素
通过useRef创建一个ref,整体使用方式与React.createRef一致
function App(props) {
const myref = useRef()
return (
<>
<div ref={myref}></div>
</>
)
}
获取ref属性也是通过hook对象的current属性
const node = myref.current;
应用场景
- 对Dom元素的焦点控制、内容选择、控制
- 对Dom元素的内容设置及媒体播放
- 对Dom元素的操作和对组件实例的操作
( antdpro 中 ProTable使用ref 来进行表格数据的重载)- 集成第三方 DOM 库
-
React中组件之间如何通信?
可以说整体用的UmiJS 中的model,作为数据共享的基础
以函数式组件为主:
- 单纯的父子通信用 props
- 子父通信 用 props 和 callback 方式
react 路由怎么配置
可以说在 umijs中,使用 .umirc.ts 中配置
import { defineConfig } from '@umijs/max';
export default defineConfig({
antd: {},
access: {},
model: {},
initialState: {},
request: {},
layout: {
title: '@umijs/max',
},
routes: [
{
path: '/',
redirect: '/login',
},
{
name: '首页',
path: '/home',
component: './Home',
},
{
name: '权限演示',
path: '/access',
component: './Access',
},
{
name: '系统管理',
path: '/system',
routes:[
{
name:'用户管理',
path:'/system/user',
component: '@/pages/System/User'
}
]
},
{
name: '登录',
path: '/login',
component: './Login',
layout: false // 不使用默认布局,左侧菜单不显示
},
],
// 配置代理解决跨域问题
proxy: {
'/api': {
'target': 'https://www.efss.cn/cms',
'changeOrigin': true,
'pathRewrite': { '^/api' : '/api' },
},
'/auth': {
'target': 'https://www.efss.cn/cms',
'changeOrigin': true,
'pathRewrite': { '^/auth' : '/auth' },
}
},
npmClient: 'yarn',
});
Hooks: React为我们提供很多钩子
最常用的
useState()
useEffect()
其他
不同的钩子为函数引入不同的外部功能,我们发现上面钩子都带有use前缀,React约定,钩子一律使用 use前缀命名。所以,你自己定义的钩子都要命名为useXXX。
- userState():状态钩子 - 函数组件局部的状态
import React, {useState} from 'react'
const AddCount = () => {
const [ count, setCount ] = useState(0)
const addcount = () => {
let newCount = count
setCount(newCount+=1)
}
return (
<>
<p>{count}</p>
<button onClick={addcount}>count++</button>
</>
)
}
export default AddCount
- useEffect():副作用钩子
- 第一个参数必须传入函数
- 第二个参数
情况1 没有第二个参数,随时(任何状态的变化)都会触发
情况2 传入空数组[],只在组件初始化(组件渲染完成)的时候触发
情况3 数组中加入 state,建立一个一一对应的关系。
import React, { useEffect, useState } from "react";
const TownAmount: React.FC = (props:any)=>{
// useState 是 hook中的一个钩子, 怎么使用:
// const [状态名字, set状态名字] = useState(状态默认值);
// ownerAmount 是一个状态,可以是任何数据类型 setOwnerAmount 是一个方法
const [ownerAmount, setOwnerAmount] = useState(10);
const [peoples, setPeoples] = useState(5); // 常住农业人口
/**
* 第一个参数必须传入函数
* 第二个参数
* 情况1 没有第二个参数,随时(任何状态的变化)都会触发
* 情况2 传入空数组[],只在组件初始化(组件渲染完成)的时候触发
* 情况3 数组中加入 state,建立一个一一对应的关系。
*
*/
useEffect(()=>{
console.log('副作用发生了')
// 这里写关联的逻辑
return ()=>{
console.log('卸载副作用,类似于clearInterval')
}
},[peoples,ownerAmount]);
const PayAmount = ()=>{
setOwnerAmount((ownerAmount-2));
}
/**
* 外出1万人
*/
const OutPeople = ()=>{
setPeoples(peoples-1);
}
return (
<>
<button onClick={PayAmount}>
支出2万
</button>
<button onClick={OutPeople}>
进城务工 1 万人
</button>
<h4>乡镇收到拨款:{props.amount} 目前余额:{ownerAmount} 剩余人口:{peoples}万人</h4>
</>
)
}
export default TownAmount;
- useContext():共享状态钩子 - 函数组件之间全局的状态
import React,{useContext, useState, createContext} from 'react';
import {Button} from 'antd';
import '../../App.css';
const CountContext = createContext();
const TestContext = () =>{
const [count, setCount] = useState(0);
console.log(CountContext);
console.log(useContext(CountContext));
return(
<div>
<p>父组件点击次数:{count}</p>
<Button type={"primary"} onClick={()=>setCount(count+1)}>点击+1</Button>
<CountContext.Provider value={count}>
<Counter/>
</CountContext.Provider>
</div>
)
};
const Counter = () => {
const count = useContext(CountContext);
console.log(CountContext);
// console.log(count);
// console.log(useContext(CountContext));
return (
<div>
<p>子组件获得的点击数量:{count}</p>
</div>
);
};
- useReducer(): 处理复杂的状态,计算一个新的state. setState钩子的底层实现用到了它
const reducer = (state, action) => {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
const Counter = () => {
const initialState = {count: 0}
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</>
);
}
小程序相关
微信登录
image.png首先在前端调用login()方法获取 code
拿到 code后请求我们自己的后端,登录操作由我们自己的后端完成。
后端接收到 code ,携带 code 、appid 和 appSecret后向微信的服务器发送请求,索取该用户的openid。
返回 openid 后,与我们的数据库进行对比,寻找绑定该微信的用户,进而实现自定义登录功能。
直接登录获取openId
uni.login({
provider: 'weixin',
onlyAuthorize:true,
success: function(loginRes) {
uni.request({
url: "http://127.0.0.1/login/wechat/" + loginRes.code, //后台地址,将code传递给后端
success: (res) => {
// 处理登录成功
}
})
}
});
uni-app 中的跳转方式
- navigateTo 保留当前页面,跳转到应用内的某个页面,使用 navigateBack 可以返回到原页
- redirectTo 关闭当前页面,跳转到应用内的某个页面
- switchTab 跳转到 tabBar 页面,同时关闭其他非 tabBar 页面
- navigateBack 返回上一页面
- reLanch 关闭所有页面,打开到应用内的某个页面
生命周期
image.png执行过程
应⽤的⽣命周期执行过程:
-
⽤户⾸次打开⼩程序,触发 onLaunch(全局只触发⼀次)
-
⼩程序初始化完成后,触发onShow⽅法,监听⼩程序显示
-
⼩程序从前台进⼊后台,触发 onHide⽅法
-
⼩程序从后台进⼊前台显示,触发 onShow⽅法
-
⼩程序后台运⾏⼀定时间,或系统资源占⽤过⾼,会被销毁
⻚⾯⽣命周期的执行过程:
- ⼩程序注册完成后,加载⻚⾯,触发onLoad⽅法
- ⻚⾯载⼊后触发onShow⽅法,显示⻚⾯
- ⾸次显示⻚⾯,会触发onReady⽅法,渲染⻚⾯元素和样式,⼀个⻚⾯只会调⽤⼀次
- 当⼩程序后台运⾏或跳转到其他⻚⾯时,触发onHide⽅法
- 当⼩程序有后台进⼊到前台运⾏或重新进⼊⻚⾯时,触发onShow⽅法
- 当使⽤重定向⽅法 wx.redirectTo() 或关闭当前⻚返回上⼀⻚wx.navigateBack(),触发onUnload
微信支付
打开某小程序,点击直接下单
- wx.login获取用户临时登录凭证code,发送到后端服务器换取openId
在下单时,小程序需要将购买的商品Id,商品数量,以及用户的openId传送到服务器 - 服务器在接收到商品Id、商品数量、openId后,生成服务期订单数据,同时经过一定的签名算法,向微信支付发送请求,获取预付单信息(prepay_id),同时将获取的数据再次进行相应规则的签名,向小程序端响应必要的信息
- 小程序端在获取对应的参数后,调用wx.requestPayment()发起微信支付,唤醒支付工作台,进行支付
- 接下来的一些列操作都是由用户来操作的包括了微信支付密码,指纹等验证,确认支付之后执行鉴权调起支付
- 鉴权调起支付:在微信后台进行鉴权,微信后台直接返回给前端支付的结果,前端收到返回数据后对支付结果进行展示
- 推送支付结果:微信后台在给前端返回支付的结果后,也会向后台也返回一个支付结果,后台通过这个支付结果来更新订单的状态
以下是uni-app 调起微信支付的核心代码
网友评论