1.js变量后边加空格后边加
+"\xa0\xa0\xa0\xa0"
2.验证写法:
<!-- 电话号 -->
expertPhone:[
{
required: true,
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur"
}
],
// 邮箱
expertEmai:[
{required: true, message: "请输入联系人电话", trigger: ["blur", "change"] },
{
type: "email",
message: "请输入正确的邮箱地址",
trigger: ["blur", "change"]
}
],
// 身份证号码
corporate: [
{
required: true,
pattern:
/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
message: "请填写正确的法人身份证号",
trigger: "blur",
},
],
// 数字:只校验类型,不是必填
projectNumber: [
{
required: false,
pattern: /^[0-9]*$/,
message: "项目编号为数字类型",
trigger: "blur",
},
],
// 不是必填,校验大于0且只有一个小数点的数字
<el-input
type="text"
v-model="form.lanBiaoPrice"
oninput="this.value = this.value.replace(/[^\d.]/g, '').replace(/(\..*)\./g, '$1');"
placeholder="请输入拦标价(只能输入大于0的数字)"
></el-input>
3.父组件调用子组件的方法
<!-- 父组件 -->
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['basicLibrary:extendedMonitoringIndicators:add']"
>添加</el-button
>
handleAdd() {
this.$refs.Add1.open();
},
4.子组件调用父组件的方法
(1)直接在子组件中通过“this.$parent.event”来调用父组件的方法。
<template>
<div>
<child></child>
</div>
</template>
<script>
import child from './components/childcomponent';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('父组件方法');
}
}
};
</script>
<!-- 子组件 -->
<template>
<div>
<button @click="childMethod()">点击按钮</button>
</div>
</template>
<script>
export default {
methods: {
childMethod() {
this.$parent.fatherMethod();
}
}
};
</script>
(2)子组件用“$emit”向父组件触发一个事件,父组件监听这个事件即可。
<!-- 父组件 -->
<template>
<div>
<child @fatherMethod="fatherMethod"></child>
</div>
</template>
<script>
import child from './components/childcomponent'
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('父组件方法');
}
}
};
</script>
<!-- 子组件 -->
<template>
<div>
<button @click="childMethod()">点击按钮</button>
</div>
</template>
<script>
export default {
methods: {
childMethod() {
this.$emit('fatherMethod');
}
}
};
</script>
(3)父组件把方法传入子组件中,在子组件里直接调用这个方法即可
<!-- 父组件 -->
<template>
<div>
<child :fatherMethod="fatherMethod"></child>
</div>
</template>
<script>
import child from './components/childcomponent';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('父组件方法');
}
}
};
</script>
<!-- 子组件 -->
<template>
<div>
<button @click="childMethod()">点击按钮</button>
</div>
</template>
<script>
export default {
props: {
fatherMethod: {
type: Function,
default: null
}
},
methods: {
childMethod() {
this.fatherMethod();
}
}
}
};
</script>
5.!import – 最高优先级
6.路径重写
7.JS中? ?和??=和?.和 ||的区别?
undefined和null是两个比较特殊的数据类型,是不能用点操作符去访问属性的,否则将会报错
?? 与 || 的区别
相同点:
?? 和 || 的用法相同,都是前后是值,中间用符号连接,根据前面的值来判断最终是返回前面的值还是后面的值。
A ?? B
A || B
不同点:
判断的方法不同:
使用 ?? 时,只有A为 null 或者 undefined 时才会返回 B;
使用 || 时,A会先转化为布尔值判断,为true时返回A , false 返回B
// ??
console.log(undefined ?? 2); // 2
console.log(null ?? 2); // 2
console.log(0 ?? 2); // 0
console.log("" ?? 2); // ''
console.log(true ?? 2); // true
console.log(false ?? 2); // false
// ||
console.log(undefined || 2); // 2
console.log(null || 2); // 2
console.log(0 || 2); // 2
console.log("" || 2); // 2
console.log(true || 2); // true
console.log(false || 2); // 2
空值合并操作符 ??
只有当左侧为null 或者undefined 时,才会返回右侧的值
可选链操作符 ?.
?. 允许读取连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。
?. 操作符的功能类似于. 链操作符,不同之处在于,在引用为空,即 null 或者 undefined 的情况下不会引起错误,该表达式短路返回值。
const obj = { a: { b: [{ name: “obj” }] } };
// 原本的写法
console.log(obj && obj.a && obj.a.b.length && obj.a.b[0].name); //obj
// 可选链写法
console.log(obj?.a?.b?.[0]?.name); // obj
console.log(obj?.b?.c?.d); // undefined
空值赋值运算符(??=)
当??=左侧的值为null、undefined的时候,才会将右侧变量的值赋值给左侧变量.其他所有值都不会进行赋值
let a = "你好";
let b = null;
let c = undefined;
let d = 0;
let e = "";
let f = true;
let g = false;
console.log((b ??= a)); // 你好
console.log((c ??= a)); // 你好
console.log((d ??= a)); // 0
console.log((e ??= a)); // ''
console.log((f ??= a)); // true
console.log((g ??= a)); // false
console.log(b); // 你好
console.log(c); // 你好
console.log(d); // 0
console.log(e); // ''
console.log(f); // true
console.log(g); // false
8.请假审批流程?
新增 – 页面 – 功能(提交、修改、下载、重新下载、查看详情)-- 搜索 – 导出(列表内容)
提交之前不出现重新提交,提交之后不出现提交和修改按钮,下载按钮下载的是附件
9.若依系统数据字典的使用?
1. ERP项目
1.1. 在函数中使用this.getDicts()方法
1.2. 在data函数中定义
1.3. 在页面中进行使用 – 固定写法 – 在页面以下拉选的方式展示
this.getDicts("字典类型").then((res) => {
this.自定义名称 = res.data;
}),
data(){
return {
自定义名称:[]
}
}
<el-select v-model="form.字段" placeholder="请选择文件类型" >
<el-option v-for="dict in 自定义名称" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" ></el-option>
</el-select>
// 在表格中的使用
<el-table-column label="行业属性" align="center" prop="hangYeShuXing">
<template slot-scope="scope">
<span>
{{
replace(
infoIndustryeList,
"dictValue",
"dictLabel",
scope.row.hangYeShuXing
)
}}
</span>
</template>
</el-table-column>
this.getDicts("info_Industry").then((response) => {
this.infoIndustryeList = response.data;
});
替换数字
//替换数组
replace(dataList, coluem, coluemVal, val) {
if (dataList.length != 0) {
for (var i = 0; i < dataList.length; i++) {
var temp = dataList[i]
var t = temp[coluem]
if (t == val) {
return temp[coluemVal]
}
}
}
},
2. 其他项目
2.1. 在页面根据后台的返回直接展示
2.1.1. 直接定义
2.1.2. 页面直接使用
export default {
dicts: ["apply_status(给的字段)"],
}
<el-table-column label="审核状态" align="center" prop="processStatus">
<template slot-scope="scope">
<dict-tag
:options="dict.type.apply_status"
:value="scope.row.processStatus"
/>
</template>
</el-table-column>
2.2. 下拉选
dicts: ["leave_type"]
<el-form-item label="状态" prop="leaveType">
<el-select
v-model="queryParams.leaveType"
placeholder="请选择请假类型"
clearable
>
<el-option
v-for="dict in dict.type.leave_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
10.若依按钮权限
需要管理员加权限,添加相应名称,才可以使用
v-hasPermi="['workflowLeave:workflowLeave:remove']"
11.时间字段问题?
情况:后端给了两个字段,前端页面只有一个字段
<!-- 1.在页面自己随便定义一个字段,写一个方法 -->
<el-form-item label="请假时间" prop="Time">
<el-date-picker
v-model="form.Time"
type="daterange"
style="width: 100%"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="yyyy 年 MM 月 dd 日"
value-format="yyyy-MM-dd"
@change="handleDatePicker"
>
</el-date-picker>
</el-form-item>
<!-- 2.在方法里边分别获取两个状态 -->
handleDatePicker(e) {
console.log(e, 99999);
if (e) {
this.form.leaveStartTime = e[0];
this.form.leaveEndTime = e[1];
}
},
//
this.form.projectStage = `${this.form.projectStage[0]}至${this.form.projectStage[1]}`;
// 时间反显 后端返回来字符串
var splitAdd = data.projectStage.split("至");
this.form.projectStage = [splitAdd[0], splitAdd[1]];
12.头部搜索状态问题?
情况:后端返回来的是0,1,2的状态–数据字典样式,但是页面需要根据汉字查找?
直接将状态根据数据字典写成下拉选的样式
<el-form-item label="状态" prop="leaveType">
<el-select
v-model="queryParams.leaveType"
placeholder="请选择请假类型"
clearable
>
<el-option
v-for="dict in dict.type.leave_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
13.修改文本框内容?
情况:页面文本框和弹出修改页面文本框使用同一个字段,修改页面修改的同时页面会随之改变,不需要调用修改接口,但是这样是错误的?
<!-- 使用深拷贝方式,重新赋值 -->
this.form = {
...response.data,
};
14.表单验证trigger属性的区别?
对el-input输入框的验证,trigger的值选blur,即失去焦点时进行验证。
下拉框(el-select)、日期选择器(el-date-picker)、复选框(el-checkbox)、单选框(el-radio)验证时,trigger的值选择change,即当值发生变化时就进行验证。
15.async、await请求发送?
1. async函数:
async用来修饰函数,async函数的返回值为Promise对象、这个promise对象的结果,由async函数执行的返回值决定。
(1)async函数的返回值为普通类型,那么对应的Promise对象的状态为成功。
(2)async函数的返回值为Promise对象,那么返回的Promise对象的状态由这个返回值决定。
(3)async函数通过throw语句抛出异常,那么返回的Promise对象的状态恒定为失败。
2. await
await用于异步请求、修饰一个表达式,用同步代码实现异步编程。
await -> 等await里边的所有执行结束才会进行下一步 – 方同步代码(没必要)/promise对象(只能放promise对象)-- await表达式返回的一般都是值,而非promise对象
(1)若await关键字右侧为Promise对象,那么await表达式返回的就是Promise成功的值;
(2)若await关键字右侧是其它值,那么会直接将此值作为await的返回值。
(3)此外,await表达式必须写在async函数中,否则会报错;如果await关键字右侧promise对象是失败的,那么可以使用try…catch…语句块中进行捕获处理。
async里边代码如果报错,就不会继续向下执行了。
如何在async里边获取错误
try{
}.catch(){
错误代码;
}
16.样式穿透、深度选择器? – v-html解析的标签样式设置
::样式穿透:v-deep
深度选择器:
和 /deep/
17.时间格式化?
<el-table-column
width="250px"
label="上传时间"
prop="reviewerTime"
align="left"
>
<template slot-scope="scope">
<span>{{ timeConversion(scope.row.reviewerTime) }}</span>
</template>
</el-table-column>
<!-- timeConversion -->
// 时间转换
export function timeConversion(oldDate, fmt = true) {
// 方式1 转换为'yyyy-MM-dd HH:mm:ss'
function add0(num) {
return num < 10 ? "0" + num : num;
} // 个位数的值在前面补0
const date = new Date(oldDate);
const Y = date.getFullYear();
const M = date.getMonth() + 1;
const D = date.getDate();
const h = date.getHours();
const m = date.getMinutes();
const s = date.getSeconds();
const dateString1 = Y + '-' + add0(M) + '-' + add0(D) + ' ' + add0(h) + ':' + add0(m) + ':' + add0(s)
const dateString2 = Y + "-" + add0(M) + "-" + add0(D);
if (fmt) {
return dateString1;
} else {
return dateString2;
}
}
// 只去月份
export function timeConversionGetMonth(oldDate, fmt) {
// 方式1 转换为'yyyy-MM-dd HH:mm:ss'
function add0(num) {
return num < 10 ? "0" + num : num;
} // 个位数的值在前面补0
const date = new Date(oldDate);
const Y = date.getFullYear();
const M = date.getMonth() + 1;
const D = date.getDate();
const h = date.getHours();
const m = date.getMinutes();
const s = date.getSeconds();
// const dateString = Y + '-' + add0(M) + '-' + add0(D) + ' ' + add0(h) + ':' + add0(m) + ':' + add0(s)
const dateString = add0(M)
return dateString;
}
// 表格时间格式化
<el-form-item label="投标时间" prop="tenderTime">
<el-date-picker
clearable
size="small"
v-model="queryParams.tenderTime"
type="date"
value-format="yyyy-MM-dd-ss-ff-mm"
placeholder="选择投标时间"
>
</el-date-picker>
</el-form-item>
18.使用find遍历?
changeSelect(val) {
let newRow = this.inviteTendersList.find((item) => item.id == val);
if (newRow) {
this.form.invitePerson = newRow.customerName;
this.form.invitePhone = newRow.customerPhone;
this.form.belongDept = newRow.customerDepartment;
this.form.biddingSubject = newRow.customerCompany;
}
}
19.批量下载
// 批量下载
handleDown() {
console.log(this.ids)
this.ids.forEach( items => {
let newList= this.basicLibList.find(item=>item.id==items)
console.log(newList,9999)
<!-- 下载接口 -->
this.downloadFileBoldName(newList.basicLibName, newList.path);
});
},
20.电脑下载git第一次使用流程?
git push -u origin master 远程仓库为空时,直接pull会报错,使用
20.1 使用步骤
21.高度的使用?
高度100%设置:所有父级元素高度100%
22.js中setTimeout和clearTimeout的使用
1、js中可以通过setTimeout函数设置定时器,让指定的代码在指定的时间运动. 如果我们希望在setTimeout之行前终止其运行就可以使用clearTimeout()。
2、clearTimeout()用于重置js定时器,如果你希望阻止setTimeout的运行,就可以使用clearTimeout方法。
(1)clearTimeout和clearInterval()区别?
clearTimeout()取消由setTimeout() 方法设置的 timeout。
clearInterval() ,这个函数只有一个作用,就是暂停setInterval()调用函数
23.多种判断方法?
v-if 和 v-else
使用时需要两个标签,才能完美配合
<el-form-item label="投标预览:">
<div v-if="fileList.length == 0">暂无可预览文件</div>
<div
style="cursor: pointer"
v-for="item in fileList"
:key="item.id"
@click="handleView(item.id)"
>
{{ item.name ? item.name : "暂无可预览文件" }}
<!-- <span v-if="item.name">{{ item.name }}</span>
<span v-else>暂无可预览文件</span> -->
</div>
</el-form-item>
三目运算符?
{{ item.name ? item.name : "暂无可预览文件" }}
24.获取元素?
<el-table-column
label="状态"
prop="expertIdcardStatus"
align="center"
>
<template slot-scope="scope">
{{ scope.row.expertIdcardStatus ? "暂停" : "正常" }}
</template>
</el-table-column>
<el-form-item label="年度目标:" prop="projectPerformanceTarget">
{{formData.projectPerformanceTarget}}
</el-form-item>
25.传给后台的状态?
后台没有给,但是给后端只能传0/1
<el-form-item label="机构认证情况:" prop="expertIdcardStatus">
<el-radio-group v-model="formData.expertIdcardStatus">
<el-radio label="0">未认证</el-radio>
<el-radio label="1">已认证</el-radio>
</el-radio-group>
</el-form-item>
26.直接赋值,视图不会更新?
this.$set(this.form,"joinManPeople",res.data[0].nickName)
this.$set{元素,"字段",需要渲染的数据}
this.$delete(this.obj, 'propName', val)
27.封装弹框/组件?
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['infoAssetApply:infoAssetApply:add']"
>新增</el-button>
<!-- 新增/修改弹框 -->
<Add ref="Add" :title="title" @getlist="getList"></Add>
<!-- 函数 -->
handleAdd() {
this.reset();
this.$refs.Add.open();
this.title = "添加资产相关审批记录 调拨等";
},
<!-- 新增 -->
<el-dialog
:title="title"
:visible.sync="dialogVisible"
width="35%"
append-to-body
:close-on-click-modal="false"
>
</el-dialog>
export default{
data(){
return {
dialogVisible:false,
}
},
methods:{
open(){
this.dialogVisible = true;
}
}
}
// 修改
open(row) {
console.log(row.id, "row.id");
// 赋值一个给rowData
this.rowData = row;
this.dialogVisible = true;
// 根据有无id判断
if (row) {
this.getFirstProjectList(row.id);
}
},
// 查询列表详情
async getFirstProjectList(id) {
let res = await getFirstProjectList(id);
console.log(res, "res");
},
// 提交
submitForm() {
// 绑定form表单,获取form表单的值
this.$refs.form.validate((valid) => {
if (valid) {
console.log(this.form, "reasonAdjust");
// 查出来的是带id,点击的这一行的数据
if (this.rowData) {
console.log(this.rowData, "this.rowData");
}
}
});
},
2.透明度区别?
第一种:rgba(0,0,0,0.2); 透明度是不会被继承的,就不用考虑继承问题
第二种:opacity:0.5; 设置opacity属性后它的后代元素会随着一起具有透明度
第三种:filter:50;
第四种:transparent; 表示全透明黑色
29.点击不同按钮,使用同一个弹框?
(1)新增和修改使用同一个?
同上:封装弹框 --> 都是使用两个按钮调用同一个弹框,但是这个弹框里边只有一个内容,只是一个有数据,一个没有数据
(2)两个完全没有关系的按钮使用同一个弹框?
<template>
<div>
<el-dialog
:title="title"
:visible.sync="dialogVisible"
width="30%"
append-to-body
:close-on-click-modal="false"
>
<!-- 申请调整 -->
<template v-if="title == '审核'">
<el-form
:model="ruleForm"
status-icon
:rules="rules"
ref="ruleForm"
label-width="100px"
class="demo-ruleForm"
style="padding: 0 30px"
>
</el-form>
</template>
<!-- 查看详情 -->
<template v-else>
<el-form label-width="100px" :model="form">
</el-form>
</template>
</el-dialog>
</div>
</template>
30.表格套表格?
<template>
<el-row :gutter="10" class="mb8">
<right-toolbar :show-search.sync="showSearch" @queryTable="getList" />
</el-row>
<el-table
v-loading="loading"
:data="projectList"
@expand-change="expandChange"
>
<!-- 展开键 -->
<el-table-column type="expand">
<template slot-scope="scope">
<el-table
style="width: 95%; margin: auto"
<!-- 子集写法 -->
:data="scope.row.infoProjectTargetAdjust"
>
<el-table-column
prop="createTime"
align="center"
label="申请时间"
>
</el-table-column>
</el-table>
</template>
</el-table-column>
<!-- 数据列表 -->
<el-table-column
show-overflow-tooltip
width="300"
label="项目名称"
// 父级写法
prop="infoBaseProjects.projectName"
/>
<el-table-column
show-overflow-tooltip
width="300"
label="建设内容与规模"
prop="projectMoney"
</el-table>
</template>
let { rows } = await getshProjectList(this.queryParams);
this.projectList = rows.infoBaseProjects;
getshProjectList(this.queryParams).then((res) => {
console.log(res.total, res, "res");
let list = res.rows;
console.log(list, "list");
this.projectList = list.map((item) => {
return {
isWho: item.isWho,
...item.infoBaseProjects,
childrenList: item.infoProjectTargetAdjust,
});
31.部署前端项目
1.设置publicPath:process.env.NODE_ENV===“production” ? " ./ : "/ "
32.高级按钮写法?
33.解构赋值
(1)对象解构赋值
…
(2)数组解构赋值
…
34.数据插值
this.$set(原始数据,插入数据字段,“插入的数据”)
35.防止图片被挤压变形
object-fit: cover;
36.javascript中的function 函数名(){}与函数名:function(){}?
function 函数名(){} --> 定义一个函数
函数名:function(){}; --> 设置一个对象的方法 --> 简写写法 函数名( ){ }
37.路由的使用?
{
path: 'projectLibrary/indexCopy/:projectIds/:isAddChild', // path必须是唯一的
name: 'ManyAddProject', // name也必须是唯一的
component: () => import('@/views/baseLibrary/projectLibrary/components/addProject/indexCopy'),
meta: { // 用来记录地址
activeMenu: '/baseLibrary/projectLibrary'
}
},
37.1 二级路由的写法
<!-- 第一种 -->
<!-- 一级路由 二级路由 -->
path:"/index" path:"/two"
// 第二种
// <!-- 一级路由 二级路由 -->
path:"index" path:"/index/two"
38.处理二进制流
第一步:请求接口设置responseType为blob
第二步,在拿到文件流后生成一个URL来是先下载。 传递row.id
封装文件下载方法
// 下载模板
export function downTemplate(query) {
return request({
url: '/common/download/downName',
method: 'get',
params: query,
responseType: 'blob'
})
}
/**
* 下载文件
* @param url 文件路径
* @param fileName 文件名
* @param parameter
* @returns {*}
*/
export function downloadFile(path, name) {
var params = {
path: path,
downName: name
}
return downTemplate(params).then((data) => {
if (!data || data.size === 0) {
alert("文件下载失败")
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), name)
} else {
let url = window.URL.createObjectURL(new Blob([data]))
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', name)
document.body.appendChild(link)
link.click()
document.body.removeChild(link) //下载完成移除元素
window.URL.revokeObjectURL(url) //释放掉blob对象
}
})
}
// 下载模板
export function downTemplate(query) {
return request({
url: '/common/download/downName',
method: 'get',
params: query,
responseType: 'blob'
})
}
/**
* 下载文件
* @param url 文件路径
* @param fileName 文件名
* @param parameter
* @returns {*}
*/
export function downloadFile(path, name) {
var params = {
path: path,
downName: name
}
return downTemplate(params).then((data) => {
if (!data || data.size === 0) {
alert("文件下载失败")
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), name)
} else {
let url = window.URL.createObjectURL(new Blob([data]))
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', name)
document.body.appendChild(link)
link.click()
document.body.removeChild(link) //下载完成移除元素
window.URL.revokeObjectURL(url) //释放掉blob对象
}
})
}
/**
* 通用js方法封装处理
* Copyright (c) 2019 ruoyi
*/
const baseURL = process.env.VUE_APP_BASE_API
import { getToken } from '@/utils/auth'
// 日期格式化
export function parseTime(time, pattern) {
if (arguments.length === 0 || !time) {
return null
}
const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
time = parseInt(time)
} else if (typeof time === 'string') {
time = time
.replace(new RegExp(/-/gm), '/')
.replace('T', ' ')
.replace(new RegExp(/\.[\d]{3}/gm), '')
}
if (typeof time === 'number' && time.toString().length === 10) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') {
return ['日', '一', '二', '三', '四', '五', '六'][value]
}
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
// 表单重置
export function resetForm(refName) {
if (this.$refs[refName]) {
this.$refs[refName].resetFields()
}
}
// 添加日期范围
export function addDateRange(params, dateRange, propName) {
const search = params
search.params =
typeof search.params === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {}
dateRange = Array.isArray(dateRange) ? dateRange : []
if (typeof propName === 'undefined') {
search.params['beginTime'] = dateRange[0]
search.params['endTime'] = dateRange[1]
} else {
search.params['begin' + propName] = dateRange[0]
search.params['end' + propName] = dateRange[1]
}
return search
}
// 回显数据字典
export function selectDictLabel(datas, value) {
var actions = []
Object.keys(datas).some((key) => {
if (datas[key].value == '' + value) {
actions.push(datas[key].label)
return true
}
})
return actions.join('')
}
// 回显数据字典(字符串数组)
export function selectDictLabels(datas, value, separator) {
var actions = []
var currentSeparator = undefined === separator ? ',' : separator
var temp = value.split(currentSeparator)
Object.keys(value.split(currentSeparator)).some((val) => {
Object.keys(datas).some((key) => {
if (datas[key].value == '' + temp[val]) {
actions.push(datas[key].label + currentSeparator)
}
})
})
return actions.join('').substring(0, actions.join('').length - 1)
}
// 字符串格式化(%s )
export function sprintf(str) {
var args = arguments
var flag = true
var i = 1
str = str.replace(/%s/g, function () {
var arg = args[i++]
if (typeof arg === 'undefined') {
flag = false
return ''
}
return arg
})
return flag ? str : ''
}
// 转换字符串,undefined,null等转化为""
export function praseStrEmpty(str) {
if (!str || str == 'undefined' || str == 'null') {
return ''
}
return str
}
// 数据合并
export function mergeRecursive(source, target) {
for (var p in target) {
try {
if (target[p].constructor == Object) {
source[p] = mergeRecursive(source[p], target[p])
} else {
source[p] = target[p]
}
} catch (e) {
source[p] = target[p]
}
}
return source
}
/**
* 构造树型结构数据
* @param {*} data 数据源
* @param {*} id id字段 默认 'id'
* @param {*} parentId 父节点字段 默认 'parentId'
* @param {*} children 孩子节点字段 默认 'children'
*/
export function handleTree(data, id, parentId, children) {
const config = {
id: id || 'id',
parentId: parentId || 'parentId',
childrenList: children || 'children'
}
var childrenListMap = {}
var nodeIds = {}
var tree = []
for (const d of data) {
const parentId = d[config.parentId]
if (childrenListMap[parentId] == null) {
childrenListMap[parentId] = []
}
nodeIds[d[config.id]] = d
childrenListMap[parentId].push(d)
}
for (const d of data) {
const parentId = d[config.parentId]
if (nodeIds[parentId] == null) {
tree.push(d)
}
}
for (const t of tree) {
adaptToChildrenList(t)
}
function adaptToChildrenList(o) {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]]
}
if (o[config.childrenList]) {
for (const c of o[config.childrenList]) {
adaptToChildrenList(c)
}
}
}
return tree
}
/**
* 参数处理
* @param {*} params 参数
*/
export function tansParams(params) {
let result = ''
for (const propName of Object.keys(params)) {
const value = params[propName]
var part = encodeURIComponent(propName) + '='
if (value !== null && typeof value !== 'undefined') {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
if (value[key] !== null && typeof value[key] !== 'undefined') {
const params = propName + '[' + key + ']'
var subPart = encodeURIComponent(params) + '='
result += subPart + encodeURIComponent(value[key]) + '&'
}
}
} else {
result += part + encodeURIComponent(value) + '&'
}
}
}
return result
}
// 验证是否为blob格式
export async function blobValidate(data) {
try {
const text = await data.text()
JSON.parse(text)
return false
} catch (error) {
return true
}
}
// 通用下载方法
// export function downLoadFile(fileName, filePath) {
// window.location.href =
// baseURL + '/common/download/downName?downName=' + encodeURI(fileName) + '&path=' + encodeURI(filePath)
// }
export function downLoadFile(fileName, filePath) {
const url = baseURL + '/common/download/downName?downName=' + encodeURI(fileName) + '&path=' + encodeURI(filePath)
const xhr = new XMLHttpRequest()
xhr.open('get', url)
xhr.responseType = 'blob' //设置后端返回类型为二进制流,不设置会返回乱码
xhr.setRequestHeader('Authorization', 'Bearer ' + getToken()) // 若依的鉴权token
xhr.onload = function () {
if (this.status == 200) {
//接受二进制文件流
var blob = this.response
const blobUrl = window.URL.createObjectURL(blob)
// 这里的文件名根据实际情况从响应头或者url里获取
const a = document.createElement('a')
a.href = blobUrl
a.download = fileName
a.click()
window.URL.revokeObjectURL(blobUrl)
}
}
xhr.send()
}
/** 根据文件名下载 */
export function downLoadFileByName(fileName) {
const url = baseURL + '/common/download?fileName=' + encodeURI(fileName) + '&delete=false'
const xhr = new XMLHttpRequest()
xhr.open('get', url)
xhr.responseType = 'blob' //设置后端返回类型为二进制流,不设置会返回乱码
xhr.setRequestHeader('Authorization', 'Bearer ' + getToken()) // 若依的鉴权token
xhr.onload = function () {
if (this.status == 200) {
//接受二进制文件流
var blob = this.response
const blobUrl = window.URL.createObjectURL(blob)
// 这里的文件名根据实际情况从响应头或者url里获取
const a = document.createElement('a')
a.href = blobUrl
a.download = fileName
a.click()
window.URL.revokeObjectURL(blobUrl)
}
}
xhr.send()
}
/** 根据路径下载 */
export function downLoadFileByPath(filePath) {
const url = baseURL + '/common/download/downloadFundDocument?path=' + encodeURI(filePath)
const xhr = new XMLHttpRequest()
xhr.open('get', url)
xhr.responseType = 'blob' //设置后端返回类型为二进制流,不设置会返回乱码
xhr.setRequestHeader('Authorization', 'Bearer ' + getToken()) // 若依的鉴权token
xhr.onload = function () {
if (this.status == 200) {
//接受二进制文件流
var blob = this.response
const blobUrl = window.URL.createObjectURL(blob)
// 这里的文件名根据实际情况从响应头或者url里获取
const a = document.createElement('a')
a.href = blobUrl
a.download = filePath
a.click()
window.URL.revokeObjectURL(blobUrl)
}
}
xhr.send()
}
/** 精确计算加法 */
export function accutateAdd(num1, num2) {
if (typeof num1 !== 'number') {
num1 = parseFloat(num1) || 0
}
if (typeof num2 !== 'number') {
num2 = parseFloat(num2) || 0
}
// 获取数字1和2的小数位长度得到小数位多的x, 给两个数乘10的x次方, 保证了两个数都是整数
const ext1Len = num1.toString().split('.')[1] ? num1.toString().split('.')[1].length : 0
const ext2Len = num2.toString().split('.')[1] ? num2.toString().split('.')[1].length : 0
const m = Math.pow(10, Math.max(ext1Len, ext2Len))
return (num1 * m + num2 * m) / m
}
/**
* 精确计算
* @param {*} num1 数字1
* @param {*} num2 数字2
* @param {*} method 计算方法 plus加法 minus减法 times乘法 divide除法
*/
export function accutateCalc(num1, num2, method) {
if (!method) {
return NaN
}
if (typeof num1 !== 'number') {
num1 = parseFloat(num1) || 0
}
if (typeof num2 !== 'number') {
num2 = parseFloat(num2) || 0
}
// 获取数字1和2的小数位长度得到小数位多的x, 给两个数乘10的x次方, 保证了两个数都是整数
const ext1Len = num1.toString().split('.')[1] ? num1.toString().split('.')[1].length : 0
const ext2Len = num2.toString().split('.')[1] ? num2.toString().split('.')[1].length : 0
const m = Math.pow(10, Math.max(ext1Len, ext2Len))
switch (method) {
case 'plus':
return (num1 * m + num2 * m) / m
case 'minus':
return (num1 * m - num2 * m) / m
case 'times':
return (num1 * m * (num2 * m)) / Math.pow(m, 2)
case 'divide':
return (num1 * m) / (num2 * m)
default:
return NaN
}
}
39.Echarts使用?
1.设置容器大小
<template>
<div class="echart" id="mychart" :style="myChartStyle"></div>
</template>
2.引用
import * as echarts from "echarts";
import Apis from "@/api/index.js";
3.定义使用方法及使用
initEcharts() {
const mulColumnZZTData = {
color: ["#0A88F5", "#FF7878"],
grid: {
left: "5%", //距离左边的距离
right: "5%", //距离右边的距离
bottom: "8%", //距离下边的距离
top: "12%", //距离上边的距离
},
xAxis: {
data: this.xData,
},
yAxis: {},
series: [
{
type: "line", //形状为折线图
data: this.taskDate,
barWidth: 15,
smooth: true,
name: "任务数", // legend属性
label: {
// 柱状图上方文本标签,默认展示数值信息
show: true,
position: "top",
},
},
],
};
const myChart = echarts.init(document.getElementById("mychart"));
myChart.clear();
myChart.setOption(mulColumnZZTData);
//随着屏幕大小调节图表
window.addEventListener("resize", () => {
myChart.resize();
});
},
4.发送请求
async projectSum(year) {
let { data, code } = await Apis.projectSum({
year,
});
// console.log(data.projects, data.statisticsVos, "data123");
if (code == 200) {
this.clearEchart();
for (let y = 1; y <= 12; y++) {
const a = data.statisticsVos.filter((item) => {
return Number(item.ym) == y;
});
// console.log(a);
if (a.length) {
this.taskDate.push(a[0].totalSum);
} else {
this.taskDate.push(null);
}
this.xData.push(Number(y) + "月");
}
this.initEcharts();
}
// console.log(this.yData);
// console.log(this.taskDate);
// console.log(this.xData);
},
40.icon图标的使用
npm install css-loader -D
import "./assets/fontIcon/iconfont.css"
1.添加到项目库
2.将生成的图标库下载至本地,并解压,文件目录如下:
3.在项目中使用
对应Unicode编码,点击复制
引入iconfont.css
@font-face {
font-family: "iconfont"; /* Project id 3434668 */
src: url('iconfont.woff2?t=1653710624498') format('woff2'),
url('iconfont.woff?t=1653710624498') format('woff'),
url('iconfont.ttf?t=1653710624498') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* 最主要的部分 */
.icon-quanxuan:before { /* 全选Icon,class为icon-quanxuan,content对应的是unicode编码*/
content: "\100d9";
}
4.页面使用
<i class:"icon iconfont icon-quanxuan></i>
41.点击新增弹框清楚原本数据?
有时候清空表单数据不起作用,使用此方法->在弹框加上v-if="dialogVisible",同时:visible.sync="dialogVisible"改为:visible="dialogVisible"
<el-dialog
title="新增"
v-if="dialogVisible"
:visible="dialogVisible"
width="100%"
:before-close="handleClose"
:fullscreen="true"
>
</el-dialog>
42.点击新增按钮新增一行表单,删除按钮删除一行表单
<div style="display: flex; margin: auto">
<el-form ref="formData" :model="{ formData }" label-width="140px">
<div v-for="(item, index) in formData" :key="index" class="flex">
<el-form-item label="中标单位">
<el-input
v-model="item.Winning"
placeholder="请输入中标单位"
></el-input>
</el-form-item>
<el-form-item label="中标金额">
<el-input
v-model="item.amount"
placeholder="请输入中标金额"
></el-input>
</el-form-item>
<i
class="el-icon-remove-outline"
style="
font-size: 24px;
font-weight: bold;
margin-left: 20px;
line-height: 30px;
"
v-if="index != 0" // 第一行不显示删除按钮
@click="deleteNextTarget(index)"
></i>
</div>
</el-form>
</div>
<div style="display: flex; justify-content: center">
<el-button
icon="el-icon-plus"
plain
size="small"
@click="addNextTarget"
></el-button>
</div>
formData: [
{
Winning: "",
amount: "",
participants: "",
participant: "",
},
],
// 新增投标后项目信息
addNextTarget() {
this.formData.push({
Winning: "",
amount: "",
participants: "",
participant: "",
});
},
// 删除
deleteNextTarget(index) {
if (this.formData.length > 1) {
this.formData.splice(index, 1);
}
},
43.鼠标事件
@keyup.enter.native和@click.native.prevent
@keyup.enter.native
一般监听写法
<input v-on:keyup.enter="submit"> <input @keyup.enter="submit">
如果用了封装组件的话,比如element,这个时候使用按键修饰符需要加上.native
<el-input v-model="account" placeholder="请输入账号" @keyup.enter.native="search()"></el-input>
@click.native.prevent
1.在封装好的组件上使用,所以要加上.native才能click
2.prevent就相当于event.preventDefault()
preventDefault() 方法阻止元素发生默认的行为(例如,当点击提交按钮时阻止对表单的提交)
44.时间轴组件 -- el-timeline -> <el-timeline-item></el-timeline-item>
<el-timeline>
<el-timeline-item
v-for="(activity, index) in activities"
:key="index"
:icon="activity.icon"
:type="activity.type"
:color="activity.color"
:size="activity.size"
:timestamp="activity.timestamp"
@click.native="handleChangeVideo(activity)"
>
<div>{{ activity.content }}</div>
</el-timeline-item>
</el-timeline>
45.全局组件、方法及样式配置
// 引入组件路径
import Pagination from '@/components/Pagination'
// 组件挂载
Vue.component('Pagination', Pagination)
// 引入方法路径--使用{ }解构
import { handlePreview } from '@/utils/ruoyi'
// 方法挂载
Vue.prototype.handlePreview = handlePreview
// 引用路径
import '@/assets/styles/index.scss' //
46.this指向&变量提升
1.普通this
window是js中的全局对象,我们创建的变量实际上是给window添加属性,所以这里可以用window点o对象
全局环境下,this指向window
浏览器中,this指向window
this 默认指向全局对象window,严格模式下,this为undefined;如果有定义,this最终指向的是调用它的对象
// a()没有定义指向,所以指向window,所以this.user为undefined
function a() {
var user = "追梦子";
console.log(this.user); //undefined
console.log(this); //Window
}
a();
this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁
this指向 o 对象
var o = {
user:"追梦子",
fn:function(){
console.log(this.user); //追梦子
}
}
o.fn();
this只会指向它的上一级对象,不管这个对象中有没有this要的东西
var o = {
a:10,
b:{
// a:12,
fn:function(){
console.log(this.a); //undefined
}
}
}
o.b.fn();
47.文字间距
p {
word-spacing: 0.2em; // 单词
letter-spacing: 0.1em; // 文字
}
48.自定义表格校验
data(){
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.ruleForm.pass) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
return{
rules: {
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
],
}
}
49.通用方法-首字母大小-下划转驼峰-金额自动添加两位小数-金额千分位加逗号-合并方法
// 首字母大小
export function titleCase(str) {
return str.replace(/( |^)[a-z]/g, (L) => L.toUpperCase());
}
// 下划转驼峰
export function camelCase(str) {
return str.replace(/_[a-z]/g, (str1) => str1.substr(-1).toUpperCase());
}
export function isNumberStr(str) {
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str);
}
// 金额自动添加两位小数
export function fundPut(num) {
let result = Number(num).toFixed(4);
if (isNaN(result)) {
return null;
} else {
return result;
}
}
// 金额千分位加逗号
export function thousands(num) {
// console.log(num, isNaN(num));
if (num == null || num == undefined) {
return null
} else {
var str = num.toString();
var reg = str.indexOf(".") > -1 ? /(\d)(?=(\d{3})+\.)/g : /(\d)(?=(?:\d{3})+$)/g;
return str.replace(reg, "$1,");
}
}
// 逗号隔开
export function toThousands(num) {
if (num != null) {
var a = parseInt(num)
var b = String(num).substring(String(num).lastIndexOf("."))
var result = [], counter = 0;
a = (a || 0).toString().split('');
for (var i = a.length - 1; i >= 0; i--) {
counter++;
result.unshift(a[i]);
if (!(counter % 3) && i != 0) { result.unshift(','); }
}
if (String(num).lastIndexOf(".") == -1) {
return result.join('')
} else {
return result.join('') + b
}
}
else {
return 0
}
}
// 合并方法
export function setdates(row, rowIndex, data) {
const len = data.length;
const arr = [];
if (!this.setdatesObj[row]) {
const obj = {};
let k;
for (let i = 0; i < len; i++) {
k = data[i][row];
if (obj[k]) obj[k]++;
else obj[k] = 1;
}
this.setdatesObj[row] = obj;
}
for (const key in this.setdatesObj[row]) {
for (let i = 0; i < this.setdatesObj[row][key]; i++) {
if (i === 0) arr.push([this.setdatesObj[row][key], 1]);
else arr.push([0, 0]);
}
}
return arr[rowIndex];
}
50.动态修改表格数据
页面:
<template>
<el-table
:data="tableData"
border
style="width: 100%"
@cell-click="handleRowClick"
>
<el-table-column type="index" label="序号" width="50" align="center">
</el-table-column>
<el-table-column prop="entryWeek" label="本周进场数" align="center">
<template slot-scope="scope">
<div v-if="scope.row.entryWeekEdit">
<el-input
v-model="scope.row.entryWeek"
@blur="handleBlur(scope.row, 'entryWeekEdit')"
/>
</div>
<div v-else>{{ scope.row.entryWeek }}</div>
</template>
</el-table-column>
</el-table>
</template>
方法:
<script>
export default {
data() {
return {
// 表格数据
tableData: [],
}
}
methods: {
/**
* 表格点击事件
*/
handleRowClick(row, column) {
console.log(121212121);
// 将当点击的属性处改为true
const prop = column.property + "Edit";
this.$set(row, prop, true);
},
/**
* 输入失去焦点事件
*/
handleBlur(row, prop) {
console.log(34343434343);
// 将当前可编辑处改为false
this.$set(row, prop, false);
// 新增的指标不处理,非新增的调用接口
if (!row.isNewAdd) {
// 如果是已存在的指标
// 这个地方调用修改接口
}
},
};
</script>