【vue】vue+avue+elementui项目问题汇总-持续更新ing
这里是目录标题鸭!
-
一、报错
-
- 1. 🍧报错不提示,只提示
400
- 1. 🍧报错不提示,只提示
-
二、滚轮
-
- 1.🍦竖轴显示 横轴不显示
- 2.avue表格增加竖列滚轮
- 3.【自定义弹窗·带全屏】横轮
-
三、avue
-
- 1. 🎂新增按钮+弹窗事件
- 2. ⛄️编辑弹窗内某输入框禁用,新增的该框不禁用
- 3. 🫐删除操作栏图标
- 4. 搜索框 放最右侧
-
四、css
-
- 1. 🌈其他界面样式被该界面影响
-
五、小程序 vs PC(引入后端数据)
-
- 1.🍕 小程序
- 2. 🍥 PC(该项目)
-
六、菜单
-
- 1. 🍿点击某分组 其他分组关闭 就该分组打开 + 菜单项写法
-
七、下拉框
-
- 1. 【elementui】el-select 反显
- 2. 【elementui】其他api方法拿到下拉框选到的值
- 3.【avue】下拉框接后端数据+传参
- 4.【avue】下拉框联动
-
八、api
-
- 1.【api格式转换】formdata转换
- 2.【post、get】api
- 3.api 简化
-
九、JSON
-
- 1.JSON
-
十、搜索框
-
- 1. avue 搜索框和列表同一个参数
- 2. 【hide、showColumn】搜索框存在,列表和显隐都不存在(改变 框 长度)
- 3.【filters、sortable】列表项箭头
-
十一、异步
-
- 【重要】async/await
-
十二、问题判断
-
- 1. 【js方法】好像没调用一样 就打出参数看看拿到参数没
- 2.有问题
-
十三、后端传num or 英文,前端改中文
-
- 1.【列表】后端传num 前端中文显示
- 2.【列表】后端给英文,前端显示中文
-
十四、VScode
-
- 1.格式化
-
十五、表格
-
- 1.elementui 表格表头变灰+边框+居中
- 2.表格项数据
一、报错
1. 🍧报错不提示,只提示400
前提须知:
- utils里先写全局方法,再在界面写你自己的判断
- ∴ 自己界面写不写error都会报错(先走全局再走界面)

- 先找到 然后打印 找到 后端提示 的中文提示位置
- 更换
message内容,别忘了[0]
二、滚轮
1.🍦竖轴显示 横轴不显示
style="height:460px"👇
一定要给定高度,这个高度就是>= 460px就开始出现滚轮
<el-scrollbar style="height:460px">
</el-scrollbar>
.el-scrollbar__wrap {
overflow-x: hidden !important;
overflow-y: visible;
}
.el-scrollbar__bar.is-vertical {
opacity: 1;
}
🥨 注意:
css样式可以写到app.vue里,全局变量
2.avue表格增加竖列滚轮
style="max-height: 300px;overflow-y: auto;"
🥑 光写max-height没用 ,得带overflow-y
<avue-crud
:option="detailOption"
:data="detailData"
style="max-height: 300px;overflow-y: auto;"
ref="detailCrud">
</avue-crud>

3.【自定义弹窗·带全屏】横轮
- elementui * :visible.sync=“detailDrawer”
👉detailDrawer: 是自定义 确定 弹窗关闭和开启 的 标识 * width=“50%”
👉50%: 控制弹窗 宽度 通过控制弹窗宽度 如果avue表格 超过此宽 自动带 横轮 * :before-close=“handleClose”
👉handleClose: 关闭的方法,关闭弹窗和全屏
<!-- 自定义弹窗 -->
<el-dialog :visible.sync="detailDrawer" width="50%" top="50px" :before-close="handleClose" append-to-body size="85%"
:wrapperClosable="false" :fullscreen="dialogFullScreen"
:class="[dialogFullScreen ? 'fullscreen' : 'no_fullscreen']">
<template slot="title">
<div class="custom_dialog_header">
<span class="el_dialog_title">配送单详情</span>
<div class="custom_dialog_menu" @click="dialogFullScreen = !dialogFullScreen">
<i class="el-icon-full-screen"></i>
</div>
</div>
</template>
<!-- 内容 -->
<!-- index【补】+ :model="'入库作业详情'"【改】 -->
<div class="billOperationDetailDrawer">
<detail-form :data="detailForm" :model="'配送单详情'" v-if="JSON.stringify(detailForm) !== '{}'"
style="margin-left: 40px"></detail-form>
<!-- 模拟page -->
<!-- style="max-height: 320px;overflow-y: auto;"=>超过一定高度加滚轮 -->
<avue-crud :option="detailOption" :data="detailData" style="max-height: 300px;overflow-y: auto;" ref="detailCrud"></avue-crud>
</div>
</el-dialog>
- js
data() {
return {
//弹窗不弹出
detailDrawer: false,
//全屏
dialogFullScreen: false,
}
},
methods: {
// 弹窗关闭
handleClose() {
// this.detailForm = {};
// this.detailData = [];
this.dialogFullScreen = false;
this.detailDrawer = false;
},
}
- css
<style scoped>
.fullscreen {
.el-dialog {
width: 100%;
}
}
.no_fullscreen {
.el-dialog {
width: 40%;
}
}
// 全屏
.custom_dialog_header {
display: flex;
justify-content: space-between;
}
.custom_dialog_menu {
padding: 1px 30px 0 0;
}
.custom_dialog_menu i {
color: #909399;
font-size: 15px;
}
.el-icon-full-screen {
cursor: pointer;
}
</style>

css全局(app)
弹窗下的横杠
<style lang="scss">
.material-avatar {
width: 100px;
height: 100px;
line-height: 110px;
border: 1px solid #ccc;
text-align: center;
}
.material-avatar i {
font-size: 32px;
line-height: 32px;
}
</style>

三、avue
1. 🎂新增按钮+弹窗事件
- 自定义新增按钮,获取到点击“新增”的事件
- 用
avue官网的MethodsrowAdd打开表单新增窗口
- 自定义新增按钮,获取到点击“新增”的事件
- 用
avue官网的MethodsrowAdd打开表单新增窗口
🔔代码:
- 自己写点击事件,而不是直接用
$refs.crud.rowAdd()
$refs.crud.rowAdd()只是个打开新增弹窗的方法罢了、
- 写完点击事件,做拿到点击事件之后要做的事件,然后再调用打开弹窗
$refs.crud.rowAdd()
<template slot="menuLeft">
<!-- 左菜单左上角-新增 -->
<el-button type="primary" icon="el-icon-plus" size="small" @click="rowAdd()">新增</el-button>
<!-- 左菜单左上角-删除 -->
<el-button type="danger" size="small" icon="el-icon-delete" plain @click="handleDelete">
删 除
</el-button>
</template>
// 点击新增按钮
rowAdd() {
//不禁用
this.option.column[0].disabled = false;
console.log("我被点击啦!!!", this.option.column);
// this.$forceUpdate();
//调用打开弹窗的方法
this.$refs.crud.rowAdd()
},
2. ⛄️编辑弹窗内某输入框禁用,新增的该框不禁用
前提:
- 编辑是用的
avue内置方法 =>editBtn: true,=>所以拿不到点击“编辑”的这个事件- 新增也是
avue内置方法 =>addBtn: true,=>同理
步骤:
- 编辑自己写不好改,得引用后端数据
- 改新增,拿到点击“新增”的方法
👆🏻上面两步见 1. 🎂新增按钮+弹窗事件
column该项填好禁用开启disabled: true,
{
label: "任务模板编号",
prop: "code",
// 禁用
disabled: true,
}
- 新增的点击事件找到 把禁用打开
// 点击新增按钮
rowAdd() {
//不禁用
this.option.column[0].disabled = false;
},
- 拿到所有的关闭弹窗事件,让所有禁用在这时重新被禁用
(不然就点击 新增之后 禁用按钮一直被打开了)avue-crud里添加:before-close="handleCrudClose"
(handleCrudClose是自己随便写的方法名)
<avue-crud :table-loading="loading" :data="tableData" :option="option"
:before-close="handleCrudClose">
- 要引入
done+done(),让事件继续done()下去 ,不然关闭功能不实现
// 关闭所有窗口的时候
handleCrudClose(done) {
this.option.column[0].disabled = true;
done();
},
3. 🫐删除操作栏图标
目标:
代码:
editBtnIcon: ' ',
delBtnIcon: ' ',
updateBtnIcon: ' ',
cancelBtnIcon: ' ',
⭐️注意: 跟我写的 一样 该 空格空格 不然 不 管用
4. 搜索框 放最右侧


avue 文档
- JS
//搜索 按钮位置
searchMenuPosition: 'right',
searchMenuSpan: 17,
- 先靠右,再调距离(最大24)
四、css
1. 🌈其他界面样式被该界面影响
- 查看影响其他界面的那页代码
- 把所有style 改成
<style scoped>- ⭐️⭐️注意: 特别是这个界面所有引用的
import界面全部改成<style scoped>
五、小程序 vs PC(引入后端数据)
1.🍕 小程序
2. 🍥 PC(该项目)
六、菜单
1. 🍿点击某分组 其他分组关闭 就该分组打开 + 菜单项写法
<el-submenu index="1">的index要设置不同名,随便取,不同就行
el-menu-item index="/base/warehouse"的index写路径
- 🍡一组 + 单个🥚 + 一组内多个🍡🍡🍡
<el-menu
:default-active="$route.path"
class="el-menu-vertical-demo"
background-color="#112f50"
text-color="#fff"
active-text-color="#ffd04b"
router
:collapse="isCollapse"
>
<!-- 一组-->
<el-submenu index="1">
<template slot="title">
<i class="el-icon-menu"></i>
<span>导航一</span>
</template>
<el-menu-item-group>
<el-menu-item index="/base/warehouse">
<i class="el-icon-s-grid"></i>
<span slot="title">111</span>
</el-menu-item>
<el-menu-item index="/base/cargo">
<i class="el-icon-receiving"></i>
<span slot="title">222</span>
</el-menu-item>
...
</el-menu-item-group>
</el-submenu>
<!-- 单个-->
<el-menu-item index="/base/map">
<i class="el-icon-video-camera"></i>
<span slot="title">333</span>
</el-menu-item>
<el-menu-item index="/base/callCargo">
<i class="el-icon-microphone"></i>
<span slot="title">444</span>
</el-menu-item>
<!-- 一组内多组-->
<el-submenu index="2">
<template slot="title">
<i class="el-icon-location"></i>
<span>导航二</span>
</template>
<el-menu-item-group>
<template slot="title">分组一</template>
<el-menu-item index="/base/task">选项1</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="分组2">
<el-menu-item index="/base/childTask">选项3</el-menu-item>
</el-menu-item-group>
...
</el-submenu>
</el-menu>
七、下拉框
1. 【elementui】el-select 反显

在Vue.js中使用Element UI的el-select组件时,如果需要实现选中项的返显,可以通过v-model指令绑定一个局部变量来控制选择的值。
以下是一个简单的例子:
<template>
<el-select v-model="selectedValue" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
<script>
export default {
data() {
return {
selectedValue: '', // 用于双向绑定选中的值
options: [
{ label: '选项1', value: 'option1' },
{ label: '选项2', value: 'option2' },
{ label: '选项3', value: 'option3' },
]
};
}
};
</script>
在这个例子中,selectedValue是绑定到el-select的v-model上的变量,它会保存选中选项的值。当用户选择一个选项后,selectedValue的值会更新为所选择的item的value。
如果需要在页面加载时设置默认选中的值,只需要在data函数中初始化selectedValue为对应的选项值即可。例如:
data() {
return {
selectedValue: 'option2', // 默认选中值为选项2
options: [
// ...
]
};
}
这样,当页面加载时,el-select将会显示默认选中的值。
2. 【elementui】其他api方法拿到下拉框选到的值
-
localStorage :
localStorage是用于 持久化 的 本地存储,除非 主动删除 数据,否则数据是 永远 不会过期的。在HTML5中新加入了localStorage的特性,它主要是用来作为本地存储,解决了cookie的缺陷问题,用来 替代cookie -
下次刷新 直接 读取缓存数据,显示之前选择的选项
-
存 :
localStorage.setItem(key, value):将value存储到key字段,如果key存在时,就更新value。
取 :
localStorage.getItem(key):获取指定key本地存储的值,如果key不存在就返回null。
代码:
- :model=“sortingDropList” :
el-form-item的model写列表List - v-model=“addrId” :
el-select的model是选中的数据,非List,写具体项 - @change=“onAddrIdChange” :
@change是选中事件 - :value=“item.addrId” :
selectedValue是绑定到el-select的v-model上的变量,它会保存选中选项的值。当用户选择一个选项后,selectedValue的值会更新为所选择的item的value。(见上一条) - v-model=“addrId” 的值更新为
:value="item.addrId"
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="分拣站" :model="sortingDropList">
<el-select v-model="addrId" placeholder="请选择" @change="onAddrIdChange">
<el-option v-for="item in sortingDropList" :key="item.addrId" :label="item.addrName"
:value="item.addrId">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="分拣员" :model="sorterDropList">
<el-select v-model="userId" placeholder="请选择" @change="onUserIdChange">
<el-option v-for="item in sorterDropList" :key="item.userId" :label="item.userName"
:value="item.userId">
</el-option>
</el-select>
</el-form-item>
</el-form>
- 定义
id、name
data() {
return {
// 定义下拉框的id、name
addrId: null,
addrName: null,
userId: null,
userName: null,
}
id可以直接拿到,name要通过idfind到- localStorage.setItem(‘addrId’, this.addrId) :
key和value不是addrid和addrname的关系,而是addrid和this.addrid的关系,需注意
- localStorage.setItem(‘addrId’, this.addrId) :
// 分拣台下拉框被选项
onAddrIdChange() {
// 根据选中的addrId在sortingDropList中查找对应的addrName
const selectedItem = this.sortingDropList.find(item => item.addrId === this.addrId);
if (selectedItem) {
this.addrName = selectedItem.addrName;
// 将addrId和addrName保存到localStorage
localStorage.setItem('addrId', this.addrId)
localStorage.setItem('addrName', this.addrName);
}
this.getList()
},
- this.addrId = ~~localStorage.getItem(‘addrId’) || ‘’ : 在
JavaScript中,~~ 是一个 双位非操作符 的连续应用,它实际上执行了一个“双位取反 ”操作。这种操作经常用作一个快速的方式来将 一个浮点数转换为整数,或者将非数字值转换为0(如果它是假值的话)。- 当
localStorage.getItem('addrId')返回一个值时,~~ 会尝试将其转换为一个整数。如果localStorage.getItem('addrId')返回一个 字符串 形式的数字,例如 “123”,~~ 会将其转换为整数 123。如果它返回一个 非数字字符串或null(当localStorage中没有'addrId'这个键时),~~ 会将其转换为0。 || ''是一个逻辑或操作,如果前面的表达式(即 ~~localStorage.getItem(‘addrId’))的结果是一个假值(例如0、null、undefined、NaN、false、空字符串等),则整个表达式的值将是后面的值,即空字符串 ‘’。
- 当
//加载表格数据
onLoad(page, params = {}) {
this.loading = true;
// 【1】分拣站下拉框
getFjzList().then(res => {
this.sortingDropList = res.data.data;
this.addrId = ~~localStorage.getItem('addrId') || ''
this.getList()
})
// 【2】拣货员下拉框
getJhyList().then(res => {
this.sorterDropList = res.data.data;
this.userId = ~~localStorage.getItem('userId') || ''
})
},
{ sortId: this.addrId }: 其他api调用的时候 直接{参数:this.addrId }找到addrid就行了
// 获取详情列表数据
getList() {
sortingDetail(
{ sortId: this.addrId }
).then(res => {
//注意:别直接=res,自己找找内容到底放到哪层
this.deliveryList = res.data.data;
this.materialList = res.data.data.binInfoVo;
this.tableData = res.data.data.sortingWallVoList;
console.log("列表被打印啦:", res);
this.loading = false;
})
},
3.【avue】下拉框接后端数据+传参
- get
dicUrl: ‘/api/sortingTable/getFjzList’,
//label: ‘addrName’ => 列表显示值
//value:‘addrId’ => 传参值
props: {
label: ‘addrName’,
value: ‘addrId’
},
代码:
{
label: '工作台',
prop: 'workBench',
type: 'select',
search: true,
searchSpan: 5,
searchPlaceholder: '--请选择--',
viewDisplay: false,
addDisabled: true,
screen: true,
hide: true,
showColumn: false,
dicUrl: '/api/sortingTable/getFjzList',
//label: 'addrName' => 列表显示值
//value:'addrId' => 传参值
props: {
label: 'addrName',
value: 'addrId'
},
},
- post
// {{key}}自动取到跟startName绑定的父的key(value) ,不一定这么写 ,看接口F12
dicUrl: ‘/api/orderTask/getCkOrGwList?addrType={{key}}’,
//label: ‘name’ => 列表显示值
//value:‘addrName’ => 传参值
props: {
label: ‘name’,
value: ‘addrName’
},
代码:
{
label: '起点',
prop: 'startName',
type: 'select',
search: true,
searchslot: true,
placeholder: '请先选择起点类型',
searchSpan: 6,
slot: true,
sortable: true,
// 【avue2】: Form组件-数据字典-字典联动
cascaderIndex: 1,
cell: true,
// {{key}}自动取到跟startName绑定的父的key(value)
dicUrl: '/api/orderTask/getCkOrGwList?addrType={{key}}',
//label: 'name' => 列表显示值
//value:'addrName' => 传参值
props: {
label: 'name',
value: 'addrName'
},
},
4.【avue】下拉框联动
网址: 【avue2】: Form组件-数据字典-字典联动
https://v2.avuejs.com/form/form-dic/#字典联动
- 目的:选择不同“终点类型”,终点显示不同内容和下拉框

- 父:
cascader为需要联动的子选择框prop值,填写多个就会形成 一对多 的关系cascaderIndex设置默认选择 第几项
- 代码:
{
label: '终点类型',
prop: 'endType',
type: 'select',
search: true,
searchslot: true,
placeholder: '请选择',
searchSpan: 6,
slot: true,
sortable: true,
// avue2-Form组件-数据字典-字典联动
cascader: ['endName'],
cascaderIndex: 1,
dicData: [
{
label: '仓库',
value: 'CK',
},
{
label: '工位',
value: 'GW',
}
],
},
{
label: '终点',
prop: 'endName',
type: 'select',
search: true,
searchslot: true,
placeholder: '请先选择终点类型',
searchSpan: 6,
slot: true,
sortable: true,
// 【avue2】: Form组件-数据字典-字典联动
cascaderIndex: 1,
cell: true,
// {{key}}自动取到跟startName绑定的父的key(value)
dicUrl: '/api/orderTask/getCkOrGwList?addrType={{key}}',
//label: 'name' => 列表显示值
//value:'addrName' => 传参值
props: {
label: 'name',
value: 'addrName'
},
},
八、api
1.【api格式转换】formdata转换
- 参数格式转换(
axios FormData):- 表单格式(
post+请求参数格式是x-www-form-urlencoded)
- 表单格式(
代码:
- import { axiosFormData } from ‘@/util/util’;
- data: axiosFormData(data)
//api js
import request from '@/router/axios';
import { axiosFormData } from '@/util/util';
export const sortingDetail = (data) => {
return request({
url: '/api/sortingTable/sortingDetail',
method: 'post',
data: axiosFormData(data)
})
}
- 工具封装
// @/util/util
export function axiosFormData(json) {
const data = new FormData();
Object.keys(json).forEach(key => {
data.append(key, json[key]);
})
return data
}
2.【post、get】api
- get
/** * 查询详情列表.
* @param {*} data
* @returns 返参
*/
export const queryList = (params) => {
return request({
url: '/api/orderTask/getOrderTaskDetail',
method: 'get',
params
})
}
- post
/** * 查询all列表 + 单个查询.
* @param {*} data
* @returns 返参
*/
export const getList = (page, pageSize, data) => {
// 合并page、pageSize和data对象
const requestData = {
page,
pageSize,
...data, // 将data对象的属性合并到requestData中
};
return request({
url: '/api/orderTask/getOrderTaskPage',
method: 'post',
data: requestData, // 传递合并后的对象作为请求数据
})
}
/** * 任务完成或取消.
* @param {*} data
* @returns 返参
*/
export const taskStatus = (data) => {
return request({
url: '/api/orderTask/taskManualOrCancel',
method: 'post',
data
})
}
3.api 简化


- 使用
getListcircuitApi.getPathConfig(
page.currentPage, // 第一个参数:page
page.pageSize, // 第二个参数:pageSize
params // 第三个参数:data
).then(res => {
//总页数
this.page.total = res.data.data.total;
//注意:别直接=res,自己找找内容到底放到哪层
this.tableData = res.data.data.records;
console.log("res被打印啦:", res);
console.log("列表被打印啦:", this.tableData);
})
九、JSON
1.JSON
JSON.parse(JSON.stringify(this.warehouseDetailData))
十、搜索框
1. avue 搜索框和列表同一个参数

繁琐写法:
- JS:
column: [
{
label: '单据日期',
prop: 'documentDate',
// width: 130,
span: 8,
showColumn: true,
search: false,
slot: true,
sortable: true,
},
//搜索 专项
{
label: '单据日期',
prop: 'date',//???????
viewDisplay: false,
sortable: true, //箭头排序-可以实现以该列为基准的排序(简单的升降序)
search: true,
hide: true,
searchslot: true,
searchSpan: 9,
showColumn: false,
minWidth: '100',
span: 9,
},
]
简便写法:
- HTML:
<avue-crud
:data="tableData"
:option="tableOption"
:page.sync="tablePage"
:table-loading="tableLoading"
@on-load="onLoad"
@selection-change="selectionChange"
@search-change="tableSearchChange"
@search-reset="tableResetChange"
@row-click="openDetailDrawer"
ref="crud"
@current-change="currentChange"
@size-change="sizeChange"
@refresh-change="refreshChange"
>
<!-- 日期 -->
<template slot="createTimeSearch">
<el-date-picker
v-model="tableSearch.day"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']"
@input="datetimeChange"
></el-date-picker>
</template>
</avue-crud>
column: [
{
label: '生成时间',
prop: 'createTime',
sortable: true,//上下三角可排序
search: true,//可搜索
searchSpan: 8,//输入框所占用的列数
searchLabel: '作业生成时间',//搜索项label
searchLabelWidth: 100,//搜索标题label的宽度
slot: true,//是否使用自定义的插槽来渲染表头
minWidth: '100',
},
]
// 查询项
tableSearch: {},
created() {
this.constOptionData = customConstant;
if (getStore({ name: 'billOperation' })) {
let data = getStore({ name: 'billOperation' });
data.forEach((item) => {
this.tableOption.column.forEach((chileItem) => {
if (item.prop === chileItem.prop) {
chileItem.hide = item.hide;
}
});
});
}
const column = this.findObject(this.tableOption.column, 'type');
// column.dicData = jobStyle();
if (this.$route.params.id) {
this.tableSearch.billCode = this.$route.params.id;
this.tableSearch.day = '';
this.onLoad(this.tablePage, this.tableSearch);
} else {
this.tableSearch.day = dateDay();
}
},
- methods:
datetimeChange() {
//强制刷新
this.$forceUpdate();
},

2. 【hide、showColumn】搜索框存在,列表和显隐都不存在(改变 框 长度)
- JS:
//→搜索项
{
label: '物资',
prop: 'materialCodeOrName',
search: true,
searchPlaceholder: '编号或名称',
hide: true,//列表中隐藏
showColumn: false,//在列显隐中不出现
searchSpan: 6,//调整 框 的长度
},
//←


3.【filters、sortable】列表项箭头

{
label: '拣货台',
prop: 'pickAddressName',
slot: true,
filters: true,//下箭头-》筛序、重置
sortable: true,//上下箭头-》排序
},
-
filters:

- sortable:

- sortable:
十一、异步
- 异步是指在进行某个操作时,不需要等待该操作完成才能进行下一步操作。相反,可以继续执行其他任务,而在操作完成后再处理它。
- 异步编程可以通过多种方式实现,常见的方式包括回调函数、Promise对象和async/await语法。
- 当处理异步操作时,常见的方式是使用回调函数。回调函数是一种在异步操作完成后被调用的函数。例如,可以使用Node.js的setTimeout函数来模拟一个异步操作,并在操作完成后调用回调函数:
function asyncOperation(callback) {
setTimeout(() => {
// 模拟一个异步操作
const result = 10;
callback(result);
}, 1000);
}
asyncOperation((result) => {
console.log(result); // 输出:10
});
- 另一种常见的方式是使用Promise对象。Promise是JavaScript中处理异步操作的标准方式之一。Promise对象表示一个异步操作的最终结果,并提供了处理成功或失败的回调函数。
- Promise对象是一种更为现代的方式,它提供了一种更结构化的方式来处理异步操作。我们可以将异步操作封装到一个Promise对象中,并使用then()方法来处理操作的结果。此外,Promise还提供了catch()方法来处理操作中可能出现的错误。以下是一个使用Promise的例子:
function asyncOperation() {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟一个异步操作
const result = 10;
resolve(result);
}, 1000);
});
}
asyncOperation().then((result) => {
console.log(result); // 输出:10
}).catch((error) => {
console.error(error);
});
- 最后,可以使用ES7引入的async/await语法来编写更清晰、易读的异步代码。async函数返回一个Promise对象,await关键字可以暂停代码的执行,直到异步操作完成。以下是使用async/await的例子:
function asyncOperation() {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟一个异步操作
const result = 10;
resolve(result);
}, 1000);
});
}
async function example() {
try {
const result = await asyncOperation();
console.log(result); // 输出:10
} catch (error) {
console.error(error);
}
}
example();
所以:
.then 为异步 可跳过,跟他同级的会跳过异步直接执行 所以需要放在里面(如果需要先调用异步再拿数据的话)
getList() {
// 初始化列表数据
this.deliveryList = [];
// 调用接口
sortingDetail(
{ sortId: this.addrId }
).then(res => {
//注意:别直接=res,自己找找内容到底放到哪层
this.deliveryList = res.data.data;
this.materialList = res.data.data.binInfoVo;
this.tableData = res.data.data.sortingWallVoList;
console.log("列表被打印啦:", res);
console.log("this.deliveryList——", this.deliveryList);
this.loading = false;
this.judgeNextOrder()//正确的(√)
})
//总结 .then 为异步 可跳过,跟他同级的会跳过异步直接执行 所以需要放在里面(如果需要先调用异步再拿数据的话)
//this.judgeNextOrder()【!!!与sortingDetail同级 大错特错 直接跳过sortingDetail执行该方法 拿不到deliveryList的数据就undefined】
},
this.judgeNextOrder() 要拿到 deliveryList的数据后才能执行 就必须放在.then 里面 不能跟sortingDetail同级
【重要】async/await
- 代码:
// strategyBtn() {
// this.strategyDrawer = true;
// queryStrategy().then((res) => {
// console.log('列表被打印啦:', res);
// this.strategyList = res.data;
// this.setSelectedStrategy();
// });
// },
// 拿到被选项
setSelectedStrategy() {
// 使用 find 方法在 strategyList 中查找 canChoose 属性为 true 的{}
const selected = this.strategyList.find((strategy) => strategy.canChoose);
// 如果{}存在,则将其 id 给 selectedStrategy
if (selected) {
this.selectedStrategy = selected.id;
}
},
// 确定
strategySave() {
// 没找到
console.log('this.selectedStrategy', this.selectedStrategy);
saveStrategy(this.selectedStrategy).then((res) => {
if (res.code === 0) {
this.$message({
type: 'error',
message: res.msg,
});
} else {
this.$message({
type: 'success',
message: res.msg,
});
this.onLoad(this.page, this.query);
// 关闭弹窗
this.strategyClose();
}
});
},
strategyBtn()写成这样,strategySave()就拿不到this.selectedStrategystrategyBtn()写成async/await,this.selectedStrategy就能拿到
async strategyBtn() {
this.strategyDrawer = true;
const res = await queryStrategy();
console.log('列表被打印啦:', res);
this.strategyList = res.data;
this.setSelectedStrategy();
},
- 解释:
Promise 链式写法
- 使用
Promise链式写法时,我们通过.then()方法逐步链接异步操作:
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('Data');
}, 1000);
});
}
fetchData().then((data) => {
console.log(data); // 打印 'Data'
return processData(data);
}).then((processedData) => {
console.log(processedData); // 打印处理后的数据
}).catch((error) => {
console.error('Error:', error);
});
- 虽然这种写法能按顺序执行异步操作,但当链条变长时,代码的可读性和可维护性会下降。
async/await 写法
- 使用
async/await可以使代码看起来像同步代码,更直观地表达 顺序执行 :
async function fetchData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('Data');
}, 1000);
});
}
async function main() {
try {
const data = await fetchData();
console.log(data); // 打印 'Data'
const processedData = await processData(data);
console.log(processedData); // 打印处理后的数据
} catch (error) {
console.error('Error:', error);
}
}
main();
- 在
async/await中,await 关键字会暂停函数的执行,直到Promise解析完成。这样可以确保在await之后的代码只有在前面的异步操作完成后才会执行。
确保顺序执行的具体应用
- 在 Vue.js 组件方法中,使用
async/await 可以确保组件状态的更新和异步数据获取按预期顺序进行。例如:
async strategyBtn() {
this.strategyDrawer = true; // 打开抽屉
try {
const res = await queryStrategy(); // 等待策略数据的获取
console.log('列表被打印啦:', res);
this.strategyList = res.data; // 更新策略列表
this.setSelectedStrategy(); // 设置选中的策略
} catch (error) {
console.error('Failed to fetch strategies:', error);
}
}
- 这样写可以确保
this.setSelectedStrategy()在queryStrategy()完成后再执行,从而避免未完成异步操作导致的错误。
总结
- 用
async/await,await queryStrategy()之后方法调完了就是调完了,后面跟这个方法有关的数据都可以用 promise的.then写法,queryStrategy()里面的数据必须在.then里面才能 顺序执行,放在外面就没用了- 比如:
正确的 :
strategyBtn() {
this.strategyDrawer = true;
queryStrategy().then((res) => {
console.log('列表被打印啦:', res);
this.strategyList = res.data;
this.setSelectedStrategy();
});
},
setSelectedStrategy() {
// 使用 find 方法在 strategyList 中查找 canChoose 属性为 true 的{}
const selected = this.strategyList.find((strategy) => strategy.canChoose);
// 如果{}存在,则将其 id 给 selectedStrategy
if (selected) {
this.selectedStrategy = selected.id;
}
},
this.setSelectedStrategy();必须在.then里面调用才能拿到strategyList的数据、
错误的 :
strategyBtn() {
this.strategyDrawer = true;
queryStrategy().then((res) => {
console.log('列表被打印啦:', res);
this.strategyList = res.data;
});
this.setSelectedStrategy();//放外面
},
- 像这样放外面就没用了,因为
queryStrategy().then((res) => { });是异步 ,可以 跳过 它执行下面的,确保这个不会影响别的内容执行(有好有坏吧 )
十二、问题判断
1. 【js方法】好像没调用一样 就打出参数看看拿到参数没
//判断是上一单还是下一单
judgeNextOrder() {
//【总结】好像没调用一样 就打出参数看看拿到参数没
if (this.deliveryList.nextId === -1) {
this.isNextOrder = false
}
if (this.deliveryList.upperId === -1 ) {
this.isNextOrder = true
}
console.log(this.deliveryList.upperId,this.isNextOrder);
},
别打印别的乱七八糟的 其他地方调用该接口 该接口就打印接口里面的参数 看看参数到底出没出问题 拿没拿到
console.log(this.deliveryList.upperId,this.isNextOrder);
2.有问题
- 先看F12是否报错
- 查看接口数据,看数据传没传过来等其他问题
- 判断是前端问题还是后端问题
- 遇到问题就 看接口 看接口 看接口 看参数
十三、后端传num or 英文,前端改中文
1.【列表】后端传num 前端中文显示
<el-form-item label="单位:">
{{ cargoSpaceInfoForm.detail.unit }}
</el-form-item>

- 现在 前端显示0或1或空
- 当为0或空时,显示‘件’;当为1时,显示‘KG’
代码:
- HTML:
<el-form-item label="单位:">
<!-- {{ cargoSpaceInfoForm.detail.unit }} -->
{{ cargoSpaceInfoForm.detail.unit === '0' || !cargoSpaceInfoForm.detail.unit ? '件' : 'KG' }}
</el-form-item>
讲解:
- 三元,如果cargoSpaceInfoForm.detail.unit的值是0或者是一个 假值 (如null、undefined、false、空字符串等),则显示“件”,否则显示“KG”。
- 请注意 假值这个概念
问题:
- 后端确实传过来的是数字0,但你的页面上显示的是“KG”
1.数据未正确更新 :确保cargoSpaceInfoForm.detail.unit的值在模板渲染之前已经被后端数据正确更新了。如果你的组件在数据到达之前就渲染了,那么模板中可能会显示旧的值或者默认值。
2.响应式问题 :如果cargoSpaceInfoForm对象或其子属性不是Vue实例的响应式数据(即不是在data函数中定义的,或者通过this.$set等方法动态添加的),Vue可能无法检测到其变化,并因此不会触发视图的更新。
3.后端数据格式问题 :检查后端返回的数据是否真的是数字0,而不是字符串"0"。在JavaScript中,字符串"0"和数字0在严格比较时(===)是不相等的。如果后端返回的是字符串"0",那么cargoSpaceInfoForm.detail.unit === 0将返回false,因此会显示"KG"。
4.计算属性或方法干扰 :如果在其他地方有计算属性或方法也影响到了cargoSpaceInfoForm.detail.unit的值,那么这也可能导致显示错误。
5.异步数据加载问题 :如果数据是异步加载的(比如通过API调用),需要确保在数据到达并设置到cargoSpaceInfoForm.detail.unit之后,模板才进行渲染。
- 我这次犯的是 0 格式问题, 后端传过来是 ‘0’
2.【列表】后端给英文,前端显示中文
- 英文和num :把
{}改成type:'select', 再加dicData,传参是后端要的数据,显示的我们自己规定的中文 - 区别 :英 –
value:‘abc’; num –value :1
改之前 代码:
{
label: '单据状态',
prop: 'status',
width: 100,
viewDisplay: false,
span: 8,
hide: false,
showColumn: true,
search: false,
searchPlaceholder: '请输入订单编号',
slot: true,
sortable: true
},

改之后 代码:
{
label: '单据状态',
prop: 'status',
type: 'select',
width: 100,
viewDisplay: false,
span: 8,
hide: false,
showColumn: true,
search: false,
searchPlaceholder: '请输入订单编号',
slot: true,
sortable: true,
dicData: [
{
value: 'IDLE',
label: '未执行',
},
{
value: 'RUN',
label: '执行中',
},
{
value: 'FINISH',
label: '已完结',
},
{
value: 'LACK',
label: '缺拣',
},
],
},

十四、VScode
1.格式化
- Prettier


十五、表格
1.elementui 表格表头变灰+边框+居中

- elementui 官网,需要使用 header-cell-style 属性
- 网址 :https://element.eleme.io/#/zh-CN/component/table
代码 :
<el-table :data="viewData" style="width: 100%" :header-cell-style="{background:'#F0F2F5',color:'#606266'}" border >
<el-table-column
type="index"
label="序号"
width="100"
align="center"
></el-table-column>
<el-table-column label="名称" width="140" align="center">
<template slot-scope="scope">
<span v-if="currentView === 'point'">
{{ scope.row.name }}
</span>
<span v-if="currentView === 'line'">
{{ scope.row.name }}
</span>
<span v-if="currentView === 'siteType'">
{{ scope.row.name }}
</span>
<span v-if="currentView === 'site'">
{{ scope.row.name }}
</span>
</template>
</el-table-column>
</el-table>
- 边框: border
- 居中: align=“center”
- 表头::header-cell-style=“{background:‘#F0F2F5’,color:‘#606266’}”
- scope.row:viewData是[],要取数组里面的{},用scope.row拿行内数据
效果 :居中+表头变灰+有边框

2.表格项数据
- 代码 :
<!-- 表格部分 -->
<el-table
:data="viewData"
style="width: 100%"
:header-cell-style="{background:'#F0F2F5',color:'#606266'}"
border
@selection-change="handleSelectionChange"
>
<!-- 多选框 -->
<el-table-column
type="selection"
width="55"
align="center"
></el-table-column>
<el-table-column
type="index"
label="序号"
width="100"
align="center"
></el-table-column>
<el-table-column label="名称" width="140" align="center">
<template slot-scope="scope">
<span v-if="currentView === 'point'">
{{ scope.row.name }}
</span>
<span v-if="currentView === 'line'">
{{ scope.row.name }}
</span>
<span v-if="currentView === 'siteType'">
{{ scope.row.name }}
</span>
<span v-if="currentView === 'site'">
{{ scope.row.name }}
</span>
</template>
</el-table-column>
<el-table-column :label="tableLabel" align="center">
<template slot-scope="scope">
<span v-if="currentView === 'line'">
{{ scope.row.detail }}
</span>
<span v-if="currentView === 'point'">
{{ scope.row.detail }}
</span>
<span v-if="currentView === 'siteType'">
{{ scope.row.detail }}
</span>
<span v-if="currentView === 'site'">
{{ scope.row.detail }}
</span>
</template>
</el-table-column>
<el-table-column
fixed="right"
label="操作"
width="100"
align="center"
>
<template slot-scope="scope">
<el-button
type="text"
size="small"
@click="infoEdit(scope.row)"
>
编辑
</el-button>
</template>
</el-table-column>
</el-table>
- 讲解
1.多选框 拿到勾选项row
HTML:
@selection-change="handleSelectionChange"
<!-- 多选框 -->
<el-table-column
type="selection"
width="55"
align="center"
></el-table-column>
data() {
return {
// 菜单-编辑弹窗被选择项
multipleSelection: [],
}
JS:
// 表格项被勾选
handleSelectionChange(val) {
this.multipleSelection = val;
},
this.multipleSelection就是 勾选的[]
- 操作栏 row
<template slot-scope="scope">
<el-button
type="text"
size="small"
@click="infoEdit(scope.row)"
>
编辑
</el-button>
</template>
data() {
return {
// 菜单-编辑弹窗内的编辑row
editRowList: {},
}
// 编辑
infoEdit(row) {
this.editRowList = row;
}
@click=“infoEdit(scope.row)” : 直接用scope.row就行
this.editRowList :row数据 放到了editRowList里










