1.由于 node 版本问题下载的CopyWebpack版本不正确等原因导致的 bug 的解决
报错:
Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
options[0] should be an object:
object { patterns, options? }
ValidationError: Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
经资料查找等工作发现是vue.config.js的plugin配置产生的问题:
原本的配置:
configureWebpack: {
plugins: [
new CopyWebpackPlugin([
{ from: 'nVVYnBJax5.txt'},
]),
],
},
修改为:
configureWebpack: {
plugins: [
new CopyWebpackPlugin({
patterns:[
{ from: 'nVVYnBJax5.txt'}
]
}
),
],
},
2.npm fixed之后还是报错的解决方案
注意:npm i之后,如果使用了 npm fixed等命令进行了版本修复等工作(大概率是因为 node 版本不匹配),并且运行时还是报错,那么此时无论怎么修改(就算切换了 node 版本)还是大概率会报错,因为 fixed会修改 package.json里面的版本号,所以我们此时最好重新拉取项目,得到本来的 package.json文件,然后更换 node 版本,重新进行 npm i,此时问题大概率会解决掉
注意:经测试,node 版本16.15.1的兼容性较高,比较好用!
3.vscode 的列选择配置项
这个东西千万不要打开:非常不好用!
4.mac 的 clash 切换代理的注意事项
mac上面的 clash 不是双击出现数字就可以了,这样并没有切换过来
必须要让这个代理的背景颜色变深,这样才是切换了过来
4.mac 的 vacode 对于快捷键的设置(终端)
切换终端快捷键的设置
mac 的 vscode 我们把调出终端的命令设置为了``
因为 command+`设置不成功,不知道为什么!
后面经过测试,设置为``会影响我们输入这个模板字符串
所以改成ctrl+`
option+`是调出 itrem2 的!
5.小程序中跳转按钮列表的构建策略
<view class="block-wrap">
<view class="title">统计分析</view>
<view class="block">
<block wx:for="{{blockList3}}" wx:key="index">
<view class="item {{item.match == 'notopen'?'not-open':''}}" wx:if="{{!item.isShow}}" data-item="{{item}}" bindtap="handleJumpRoute">
<image src="{{httpImage}}{{item.icon}}" />
<text>{{item.name}}</text>
</view>
</block>
</view>
</view>
blockList3: [
{
icon: '/home_icon8.png',
url: '/subpackages/home/goodsDetail/index',
name: '备货铺货情况',
match: 'goodsDetail'
},
{
icon: '/home_icon10.png',
url: '',
name: '后端服务情况',
match: 'notopen'
},
{
icon: '/home_icon12.png',
url: '/subpackages/home/agentRankingList/index',
name: '代理商打地基排行榜',
match: 'activeDetail'
},
{
icon: '/home_icon14.png',
url: '',
name: '打地基异常处理数据',
match: 'notopen'
}
],
// 跳转路由
async handleJumpRoute(e) {
let item = e.currentTarget.dataset.item
if(item.match == 'notopen'){
Common.showBox('暂未开放')
return
}
let url = item.url
await wx.navigateTo({ url })
}
.page-wrap .content .block-wrap .not-open{
opacity: 0.3;
}
6.对于wx.showToast的封装
function showBox (text, delayTime = 2000, fn=()=>{}){
wx.showToast({
title: text,
icon: 'none',
duration: delayTime,
success() {
fn()
}
})
}
7.小程序中的nav-bar
小程序中的nav-bar就是最上面的标题栏,带有回退按钮的那个!基本上是全局统一的一个组件!
一般放在每个页面的 index.json里面

8.text标签实现换行类似 p 标签
text标签可以实现类似 p 标签的换行功能
因为 text 标签里面可以写\n,是可以被解析为换行的!
例子:
<text class="title-text">智能硬件代理商\n打地基五星高活榜</text>
使用 css 样式white-space: pre-line;也可以实现 p 标签换行
使用 CSS 样式:可以利用 CSS 样式来实现换行效果。例如,将文本容器的样式设置为 white-space: pre-line;,这样文本中的换行符会被保留并显示为换行。例如:
<text style="white-space: pre-line;">
第一行
第二行
第三行
</text>
view+text标签也可以实现换行
<view>
<text>第一行</text>
<text>第二行</text>
<text>第三行</text>
</view>
9.小程序两种接收事件传参的方法
绑定了bindtap=“test”,并设置data-index=“111”
在test(e){}函数中,可以用e.currentTarget.index或e.detail.value接收,都可以以获取到 index 变量的值!
10.女娲后台项目不具有mac和win的适配性,要适配 win 的方法
本来是适配 mac 的,要适配 win 需要做如下的修改:
package.json本来的样子:

改为:

vue配置文件也要进行修改:

11.element-ui的级联选择器懒加载
级联选择器懒加载,实现省市区的三级联动
在 data 中定义如下内容:
cityProps: {
lazy: true,
checkStrictly: true,
lazyLoad(node, resolve) {
const { level, data } = node;
let params = {
param: {}
};
if (data && data.value) {
params.param["parentId"] = data.value;
} else {
params.param["parentId"] = 0;
}
queryCityListByParentId(params).then(res => {
if (res.code == 0) {
let cityData = [];
cityData = res.data.map(item => {
return {
value: item.id,
label: item.name,
leaf: level >= 2 //修改这个参数即可实现不同的层级
};
});
resolve(cityData);
}
});
}
},
leaf参数的含义
表示什么条件下为叶子节点,叶子结点不可以再向下衍生出节点,不是叶子节点的都可以继续调用懒加载函数,如果是三级,则设置leaf: level >= 2
定义 html:
<div class="search-item">
<!-- 省市区选择 -->
<el-cascader
:props="cityProps"
placeholder="请选择代理商所在地"
@change="changeCity"
clearable
></el-cascader>
</div>
定义如下方法:其中 cityNode 是一个包含了所选的省市区的 id 的列表
// 切换地点
changeCity(cityNode) {
// console.log(cityNode);
if (cityNode.length == 1) {
this.provinceId = cityNode[0];
} else if (cityNode.length == 2) {
this.provinceId = cityNode[0];
this.cityId = cityNode[1];
} else if (cityNode.length == 3) {
this.provinceId = cityNode[0];
this.cityId = cityNode[1];
this.districtId = cityNode[2];
}
if (!cityNode.length) {
//如果city被清空,那么清空表单
this.provinceId = null;
this.cityId = null;
this.districtId = null;
}
},
为什么 cityNode 会是列表呢?
这里的 value 是 id 所以 changeCity得到的就直接是 id了

12.Js数字置空
在 JavaScript 中,数字无法直接置空,因为数字是基本数据类型,它们是不可变的。然而,你可以通过赋予特定的值来表示数字为空或无效。
也就是说Js中数字没有空类型!
Js数字要置空的话,可以设置为 null 或者 undifined,而NaN 代表不是一个数字的空类型
13.AgentTree 组件
AgentTree 看一下原理是什么
html 代码:
<template>
<div class="search-item">
<span v-if="isShowLabel" class="item-label">代理商:</span>
<!--
ref用于让自己作为弹出框的标志
placement是弹出的位置
@show是弹出框被打开的事件
@hide是弹出框被隐藏的事件
-->
<el-popover
placement="bottom-start"
height="300"
ref="choseAgentPopover"
trigger="click"
@show="showAgentDepartmentPopover"
@hide="hideAgentDepartmentPopover"
:visible-arrow="false"
>
<div class="c-popover-tab-pane">
<!--这是小搜索框-->
<el-input
class="keyword-search"
:placeholder="searchPlaceholder"
v-model="filterAgentTextClass"
>
</el-input>
<!--
data 用于指定数据源
props 属性用于指定展示出的效果和内容,将 data 源数据的每一项格式化为含有 label、children 等属性的对象,用于树控件进行识别并进行页面的展示
filter-node-method是用于搜索节点进行过滤的(当小搜索框进行搜索时)
default-checked-keys是表示默认被选中的节点有哪些(用于本次选择之后下一次再打开时的效果)
auto-expand-parent是表示是否自动打开父节点,默认开启,这里我们关闭
check是点击勾选选中框时触发的事件
show-checkbox展示选择框
check-on-click-node被点击时被选中
ref用来帮助获取 el-tree实例对象
-->
<el-tree
:data="agentTreeData"
:props="defaultProps"
height="100px"
show-checkbox
check-on-click-node
node-key="value"
ref="agentClassTree"
:filter-node-method="filterAgentNode"
:default-checked-keys="selectAgent"
:auto-expand-parent="false"
@check="treeCheck"
>
</el-tree>
</div>
</el-popover>
<!--这里是大搜索框,v-popover绑定点击之后弹出的弹出框-->
<el-input
class="selectClass"
:placeholder="inputPlaceholder"
readonly
v-model="lstAgentId"
v-popover:choseAgentPopover
>
<span class="el-input__suffix" slot="suffix">
<span class="el-input__suffix-inner">
<!--这里的 class 可以实现图标的动态翻转-->
<i
class="el-select__caret el-input__icon el-icon-arrow-up"
:class="{
'is-reverse': showAgentDropDown
}"
></i>
</span>
</span>
</el-input>
</div>
</template>
js代码:
import { getDeptTreeInfo } from "@/api/index.js";
//封装的防抖函数
const debounce = (function() {
let timer = 0;
return function(func, delay) {
clearTimeout(timer);
timer = setTimeout(func, delay);
};
})();
export default {
data() {
return {
//用于配置 props 属性,指定 label 为 data 的 title 拼接 value,指定节点的children孩子节点为 node 对象的 children属性
defaultProps: {
children: "children",
label: function(data) { //指定 label为 node 对象的 value 属性与 data 属性进行拼接(label 就是显示在页面上面的内容)
let value = 0;
if (data.value.split("_")[1] - 0 > 0) {
value = data.value.split("_")[1] - 0;
}
return value + "-" + data["title"];
}
},
selectAgent: [],
selectAgentStr: "",
filterAgentTextClass: "",
agentTreeData: [],
showAgentDropDown: false,
lstAgentId: "",
radios: []
};
},
props: {
isShowLabel: {
type: Boolean,
default: false
},
inputPlaceholder: {
type: String,
default: "请选择代理商ID/代理商名称"
},
searchPlaceholder: {
type: String,
default: "输入代理商ID/代理商名查找"
},
isSingleChoice: { //是否开启单选模式
type: Boolean,
default: false
}
},
watch: {
filterAgentTextClass(val) { //监控小搜索框输入的数据,动态进行树控件的数据展示
if (this.showAgentDropDown) {
//在箭头函数内部,通过this.$refs.agentClassTree.filter(val)来调用$refs.agentClassTree引用的<el-tree>组件的filter方法(也就是filterAgentNode方法),并传递了val作为参数。
//debounce是一个防抖函数,用于延迟执行一个函数并控制其调用频率。只有当在300毫秒内没有再次调用该函数时,才会真正执行。
debounce(() => {
this.$refs.agentClassTree.filter(val);
}, 300);
if (val != "") {
this.$set(this.agentTreeData[0], "disabled", true);
} else {
this.isExpand = false;
this.$set(this.agentTreeData[0], "disabled", false);
}
}
}
},
mounted() {
this.queryAgentTree();
},
methods: {
//获取树控件的源数据
queryAgentTree() {
const params = {
param: {}
};
getDeptTreeInfo(params).then(res => {
if (res.code === 0) {
let treeListdata = res.data;
this.agentTreeData = treeListdata;
} else {
this.$message.error(res.message);
}
});
},
// 弹出框被展示的时候
showAgentDepartmentPopover() {
this.showAgentDropDown = true; //用于旋转图标
},
// 重点逻辑在这里,当弹出框被关闭的时候
hideAgentDepartmentPopover() {
this.selectAgent = [];
this.lstAgentId = "";
this.showAgentDropDown = false;
//注意:使用getCheckedKeys()和getCheckedNodes()方法必须在组件上有node-key="属性"这个配置,其中属性指的是绑定的源数据 data 中每一项的那个对应属性
let selectArr = this.$refs.agentClassTree.getCheckedKeys();//得到选中的 key 列表
let selectNodeArr = this.$refs.agentClassTree.getCheckedNodes();//得到选中的 node 节点列表
let selectPeopleName = [];
if (selectArr.length > 0) {
let selectPeopleArr = selectArr; //将 key 列表进行存储
selectNodeArr.map(item => {
selectPeopleName.push(item["title"]);//得到所有选中的节点的 title 属性,即名字
});
let selectAgentStr = selectPeopleName.join(","); //拼接为 string,用于展示在 input 框中
this.selectAgent = selectPeopleArr; //将 key 列表赋值给selectAgent,用于下一次的默认选中的标志
this.lstAgentId = selectAgentStr;
} else {
this.selectAgent = [];
this.lstAgentId = "";
}
let lastArr = []; //存储被切分处理后的 key 列表,将来用于传参到后端进行搜索
this.selectAgent = this.selectAgent.map((item, index) => { //将 key 列表进行切分处理,得到需要的 key 的部分!
if (item.split("_")[1] - 0 > 0) {
lastArr.push(item.split("_")[1] - 0);
}
});
this.$emit("selectedAgentDepartment", lastArr); //触发事件,进行搜索,传 key 列表为参数
},
filterAgentNode(value, data) { //用于搜索过滤,只留下 title 或者 value 中有对应搜索值的节点
//value 为搜索值,data 为 node 列表
if (!value) {
return true;
}
return (
data.title.toString().indexOf(value) !== -1 ||
data.value.toString().indexOf(value) !== -1
);
},
treeCheck(node, list) { //该逻辑用于实现在单选模式下,当用户选择了两个树节点时,自动将第一个选中的节点取消选择,并将第二个选中的节点设置为选中状态。——>在这里结构过于复杂,代码不适用也不启用
//list 是一个对象,它包含了当前树节点的选择状态和相关信息,其中包括一个 checkedKeys 数组,表示当前被选中的树节点的 key 值列表。
//node 也是一个对象,表示当前被选中的树节点对象。
if (list.checkedKeys.length == 2 && this.isSingleChoice) {
//单选实现
this.$refs.agentClassTree.setCheckedKeys([node.PHY_ID]);
}
}
}
};
queryAgentTree方法得到的数据结构:可以直接赋值给树控件作为源数据
注意:这个结构就是el-tree所要求的数据结构和属性,一般 title、value 都是必有的,children 可以没有,但是属性的命名可不一定是 title、value、key,因为 props 属性会把 data 的每一项进行格式化,真正展示的内容是 props 的定义规则的内容,为以下四项:
一般指定node-key="属性"这个配置项,指定的属性都是 data 每一项的那个 value(id)
也只有配置了 node-key=“value”这个配置项,才可以使用以下两个重点的方法:
let selectArr = this.$refs.agentClassTree.getCheckedKeys();//得到选中的 key 列表,即选中的 data 的每一项的 value 属性
let selectNodeArr = this.$refs.agentClassTree.getCheckedNodes();//得到选中的 node 节点列表,即选中的 data 的每一项那整个对象(可以再从中获取 title 等内容)
注意:如果没有为 props 定义 children 属性的话,那么就变成了一层的树!即OnlyAgentTree 组件
14.js 中为假的内容
注意:空字符串“”在 js 中也是假的,但是空数组([])和空对象({})是真的
在 JavaScript 中,以下值被认为是假的(即逻辑上为 false):
- false:布尔值 false。
- null:表示空或无值。
- undefined:表示未定义的值。
- 0:数字 0。
- NaN:非数字值。
- "":空字符串。
这些值在条件语句(例如 if 语句)中被视为假,而其他值都被视为真。请注意,空数组([])和空对象({})被视为真值,因为它们都是对象,即使它们没有任何元素或属性。
NaN 表示的含义
NaN(非数字)不是表示空值的概念。NaN 表示一个特殊的数值,大多数情况它是由计算产生的(表示一个错误的结果,这个结果叫做不是一个数字),表示计算结果不是数字。NaN 是一个特殊的数值,代表 "Not a Number"(不是一个数字)。
NaN 可以通过一些操作产生,例如将非数字字符串解析为数字、进行无效的数学运算或使用无效的数值。
以下是一些产生 NaN 的示例:
let result1 = parseInt("Hello"); // 将非数字字符串解析为数字
console.log(result1); // 输出 NaN
let result2 = 0 / 0; // 0 除以 0
console.log(result2); // 输出 NaN
let result3 = Math.sqrt(-1); // 对负数求平方根
console.log(result3); // 输出 NaN
请注意,NaN 与任何其他值(包括 NaN 本身)进行比较的结果都是 false。这意味着 NaN 不等于任何其他值,包括它自己。要检测一个值是否为 NaN,可以使用全局函数 isNaN()。
let value = NaN;
console.log(isNaN(value)); // 输出 true
15.分页组件的使用模版
后端返回一个 count 字段,count 字段表示总数据量,只有 count>=pageSize时才显示分页组件,所以这个是用于标志是否显示分页按钮组件的!
分页组件的回调函数控制第几页,v-model绑定控制页面数据量
<!--分页组件,总数据量大于10条才会出来-->
<div class="gm-pagination" v-if="dataCount > searchInfo.pagesize">
<el-pagination
background
layout="prev, pager, next"
:page-size="searchInfo.pagesize"
:total="dataCount"
@current-change="handleCurrentChange"
:current-page.sync="searchInfo.page"
>
</el-pagination>
</div>
<!--/.分页-->
data 中的数据:
dataCount: 0,
searchInfo: {
pagesize: 10,
page: 1
},
method 方法:
// 控制页数
handleCurrentChange(currentPage) {
this.searchInfo.page = currentPage;
this.queryAgentHeightRankPage();
},
在构造请求参数的时候,在 params 对象中写上两个分页属性

16.el-table-column的高级用法
el-table-column怎么在 html 中获取当前行的索引?scope.$index
注意:slot-scope和v-slot两种写法都可以
<template>
<el-table :data="tableData">
<el-table-column label="姓名">
<template slot-scope="scope">
<span>{{ scope.$index }}</span>
</template>
</el-table-column>
<!-- 其他列 -->
</el-table>
</template>
怎么在html获取当前列的值,并动态渲染呢?scope.row.变量
<el-table-column prop="area" align="center" label="区域">
<template v-slot="scope">
<template v-if="scope.$index != moreIndex"
>{{ scope.row.area }}
<span class="read-more" @click="lookMore(scope.$index)">
更多
</span></template
>
<template v-else
>{{ scope.row.areaFull }}
<span class="read-more" @click="noLookMore">
收起
</span></template
>
</template>
</el-table-column>
注意:还可以把v-slot="scope"直接写在el-table-column上面
<template>
<el-table :data="tableData">
<el-table-column label="姓名" v-slot="scope">
<span>{{ scope.row.name }}</span>
</el-table-column>
<!-- 其他列 -->
</el-table>
</template>
17.开发中比较常遇到的注意点
1.对于表单或者选择框等组件,不是用v-model绑定值的组件,那么在清空值的时候就要在回调函数中手动把 对应的 data 中的内容进行清除置空,而 v-model绑定了的话,页面空了 js 也就空了,所以不用手动置空
2.后端返回的数据,如果是需要拼接展示的,或者需要在空的时候展示特定的字符串的,用在 html 模版中的时候就需要用三元运算符等判断是否为空,否则可以不判断,但是一般都需要判断空值

3.JavaScript 中的 getMonth()
方法返回的月份是从 0 开始的,即 0 表示一月,1 表示二月,以此类推,11 表示十二月,所以要获得正确的月份的时候需要+1