Vue项目中的问题汇总(持续更新中)
1.vue 循环 span 标签产生了间隙
代码如下:
<template>
<div class="box">
<span v-for="(item,index) in items" ::key="index">{{ item }}</span>
<span>修改</span>
<span>删除</span>
</div>
</template>
<script>
export default {
data() {
return {
items: ["审批", "拒绝审批", "核销"],
};
},
};
</script>
<style lang="less">
.box {
span {
display: inline-block;
width: 40px;
height: 20px;
}
}
</style>
html

原因和解决方法:
当遇到display:inline或display:inline-block的元素相邻,并且它们之间存在强制回车换行时,则会自动形成一段间隙。
可以在这些元素的父元素上设置font-size:0;,就可以消除换行带来的间隙。
这种情况下,如果代码不换行,就不会产生间隙。
2.ElementUI 的表单resetFields()方法无法清空
为每个 form-item 加上 prop 属性(大部分的问题就是出在这 )
弹框时:
记得使用this.$nextTick(()=>{})
The <router-view> cannot be embedded directly within the <transition> or <keep-alive> components.
最近正在学习 Vue3 技术,在开发项目的过程中发现当对 router-view 进行请求时,在应用层通常会受到 keep-alive 机制的影响而触发相关警告信息
<router-view> can no longer be used directly inside <transition> or <keep-alive>
js
代码如下:
<transition
:name="!noTransition ? 'fade-transform' : ''"
:mode="!noTransition ? 'out-in' : ''"
>
<keep-alive :include="cachedViews">
<router-view :key="key" />
</keep-alive>
</transition>
html
提示以下警告
[Vue Router warn]: <router-view> can no longer be used directly inside <transition> or <keep-alive>.
Use slot props instead:
<router-view v-slot="{ Component }">
<transition>
<component :is="Component" />
</transition>
</router-view>
js
从警告信息可以看出是路由包裹出现了问题,现做如下调整
<router-view :key="key" v-slot="{ Component }">
<transition
:name="!noTransition ? 'fade-transform' : ''"
:mode="!noTransition ? 'out-in' : ''"
>
<keep-alive :include="cachedViews">
<component :is="Component"></component>
</keep-alive>
</transition>
</router-view>
html

4.Vue3 reactive不能直接赋值的解决方法
1. 改为 ref 定义
const arr = ref([]);
arr.value = [1, 2, 3];
js
2. push 新增数据
const arr = reactive([]);
arr.push(...[1, 2, 3]);
js
3.再封装一层数据,改成对象(推荐!)
const state = reactive({
arr: [],
});
state.arr = [1, 2, 3];
js
reactive 与 ref 区别
reactive
reactive的本质在于将输入的数据封装为一个Proxy。
reactive所接受的参数数据类型限定为对象或数组结构。
实现响应式变化较为复杂的情况通常需采用toRefs进行封装。
需要注意的是,在这种情况下无需为每个变量预先分配存储空间。
ref
- ref 通常用于定义基本类型的变量
- 当参数为对象类型时……其实底层的本质仍然是 reactive,并被转换为代理对象
- ref 的响应式原理基于 Object.defineProperty() 的 get() 和 set() 方法
- 在 JS 中的操作中,默认情况下默认值会被赋给 ref 对象;而在 template 模板中则不需要。
ref、toRef、toRefs 的区别
ref :复制,修改响应式数据不影响以前的数据;数据改变,界面自动更新
toRef :引用时会发现修改响应式数据会影响之前的数据显示;当数据发生变化时,默认情况下界面不会自动更新
toRef :引用时会发现修改响应式数据会影响之前的数据显示;当数据发生变化时,默认情况下界面不会自动更新
toRefs :
该对象将被接受,并将其所有属性逐一处理后调用一次toRef。
(2)将对象的多个属性转换为响应式数据,并要求这些响应式数据与原始数据建立关联关系,在对响应式数据进行更新时无需触碰界面以实现批量设置多个属性值为响应式状态
5.Vue 获取当前页面路由
//当前页面
window.location.href; //完整url可以用
this.$route.path; //路由路径可以用
this.$route.params; //路由路径参数
js
监听路由
一并将在监听后向系统提供一个与之对应的字符串,在路由变化时即时处理该字符串
watch: {
// 如果路由有变化,会再次执行该方法
'$route': 'fetchData'
},
methods:{
fetchData () {
//...
}
}
js
如果我们要通过识别路由发生的特定变化来实现某种方法,则可以使用handler。
watch:{
"$route":{
handler(route){
const that=this;
if(route.name=='Hello'){
that.fetchData();
}
}
}
}
js

6.Vue 请求本地 JSON 文件的方法
使用 vue-cli2.0 生成的项目,静态文件是 static 文件。
使用 vue-cli3.0 生成的项目,静态文件变成了 public 文件。(vue3 相同)
将 JSON 文件放入静态文件目录中,在使用时 Vue 会默认被请求到此目录中。
案例:
this.$axios.get("data.json").then(
res => {
// 200响应
console.log(res); // 此处的res对象包含了json的文件信息和数据,看控制台点出来即可
},
err => {
// 500响应
console.log(err);
}
);
js

7.解决 script 标签写在元素节点前面无法获取元素节点的问题
文档加载过程遵循文档结构层次进行操作,并因此无法实现在其后被加载的元素节点。
两个方法,如下:
解决方案一:使用 onload事件,window.onload当页面加载完成后触发。
因为将 script 标签放置在 div 块之前会导致代码出现错误,并且无法捕获 box 元素。可以通过调用 window.onload 来解决问题。
代码说明:
<style>
.box {
width: 100px;
height: 100px;
background-color: blue;
}
</style>
<script>
window.onload = function () {
//页面加载完后执行
var box = document.getElementById("box");
box.style.background = "green";
};
</script>
<div id="box">我是box</div>
html

解决方案二: 利用脚本的异步加载,需要用到两个属性 async 和 defer
这两个属性常用于外部导入JavaScript文件的情境中。当从外部导入JavaScript文件且其script标签位于元素节点之前时,则会导致无法获取到对应的元素节点。此时通常会采用JavaScript的异步执行机制或延迟加载机制(即通过使用async和defer来处理)。
代码说明:
<style>
.box {
width: 100px;
height: 100px;
background-color: blue;
}
</style>
<script scr="index.js" async></script>
<div id="box">我是box</div>
html

创建一个 index.js 文件
window.onload = function () {
//页面加载完后执行
var box = document.getElementById("box");
box.style.background = "green";
};
js
详情查看:JS 基础篇:JS 脚本调用策略
8.justify-content: space-between;没有两端对齐,没有生效
原因:
伪元素::after,::before影响
解决方法:
去掉伪元素
代码:
.el-row::before {
display: none;
}
.el-row::after {
display: none;
}
css
9.ElementUI 中el-table-column的 type 为 selection 时选择框旁边有个点
场景:
使用el-table配置多选组件时,默认情况下会将该组件的type字段设置为默认值(通常对应表格单行选择),但当显式设置该字段值为selection时,则会将该字段值显式指定为此类型,并使该组件呈现为勾选形式。
但是会在勾选框旁边显示一个或多个实心的小点。
原因:
这是因为在设置el-table-column的宽度为30 太窄导致的。
<el-table-column type="selection" width="30" align="center" />
html
解决方法:
将其宽度调大点。
<el-table-column type="selection" width="55" align="center" />
html
10.Vue 3 ::v-deep usage as a combinator has been deprecated. Use ::v-deep() instead
原因新的 Vue 3.0 单文件规范中的 ::v-deep 写法已被移除。建议可替代采用 :deep() 方式来实现同样的效果。
/* Vue 2.0 写法 */
::v-deep .carousel-btn.prev {
left: 270px;
}
/* Vue 3.0 更改为以下写法 */
:deep(.carousel-btn.prev) {
left: 270px;
}
/* 或是 */
:deep() {
.class {
}
}
css

深度选择器 扩展:
有时我们可能想要明确地制定一个针对子组件的规则。
最初我们采用>>>组合器用于选择"deep"。然而,在解析方面存在局限性:由于其并非标准认证的CSS组合器。
后来我们转向了/deep/路径。这一选择最初是 CSS 功能的直接灵感来源(甚至Chrome浏览器在其开发中就已内置)。尽管如此但随后我们放弃了这一功能。这确实给一些开发者带来了困扰因为他们担心在某些旧版本浏览器中无法正常使用的选件会影响他们的开发体验。然而就像使用>>>一样Vue的SFC编译器将这种选件仅用作编译时提示来重写对应的CSS选择器但在最终生成的样式表文件中这种标记会被彻底移除以确保纯文本输入的安全性
为了避免被丢弃的/deep/组合器的混淆,我们引入了另一个自定义组合::v-deep器,这一次更明确地表明这是一个特定于 Vue 的扩展,并使用伪元素语法,以便任何预处理器都应该能够解析它.
由于兼容性考虑
在开发 v3 版本的新 SFC 编译器过程中, 我们发现 CSS 伪元素本质上并非传统的组合子. 其接受参数的方式与通用 CSS 规范一致, 因此我们采用 ::v-deep() 的方式来进行编译器实现. 如果您对显式 v- 前缀不感兴趣, 您也可以选择较短的 ":deep()" 简化方式.
继续认可当前作为组合器使用的做法::v-deep ,已被认为是过时的方法,并且会在后续版本中不再支持
Do not should access the method of Object.prototype on the target object.
原因分析:
为何 ESLint 不允许从目标对象调用 Object 原型方法?
在 JS 中,往往通过改变原型链实现继承。一旦原型链发生改变,原先可以访问到的原型属性 、方法 便可能无法访问。考虑最极端的情况,若 obj 原先原型链的最顶端是Object,此时可以通过原型链访问 Object.hasOwnProperty 方法;而若改变后,顶端不再是 Object,那么访问 obj.hasOwnProperty 访问就会得到 undefined。因此,直接从对象访问原型方法,很可能会带来隐藏的 BUG。
为了避免这种细微的 bug,最好总是从 Object.prototype 调用这些方法。即直接在 Object 对象上调用其方法,利用 call 改变其 this 指向到我们的目标对象上,即可安全使用 hasOwnProperty 方法了。
/** * 错误提示:Do not access Object.prototype method 'hasOwnProperty' from target object
* 解决方法:foo.hasOwnProperty("bar") 改为 Object.prototype.hasOwnProperty.call(foo, "bar")
*/
js
12.css display:flex 弹性布局 子标签设置固定宽度无效的问题
出现的情况 :
如果子级盒宽总和超过父盒宽时会出现问题
表面原因:
一个父容器内包含了两个嵌套的子容器,在设置display:flex后的情况如下:即使这些子容器均设置了宽度均为50%,但当左侧的容器内容较为丰富时,则左侧的容器可能会超出右侧容器的实际范围范围,并由此导致右侧容器的实际宽度未能正确显示
根本原因:
当父容器设置为Flex布局时,默认情况下所有子级元素将继承Flex属性,并带有值为 flex:0 1 auto 。这里的数值1对应Flex中的 flex-shrink属性,在这种情况下会开启元素的收缩功能。因此会导致左侧子级块挤压右侧块的情况出现。因此一种可行的方式就是:我们可以将该块段的自动收缩功能关闭掉,具体设置为 flex:0 0 auto ;接着再单独指定该块段所需的宽度就可以了。
解决方法:
//针对需要设置固定宽度的子标签,其中 50% 是根据自己的盒子宽度自定义设置的
//方法1:
flex: 0 0 auto;
width: 50%;
//方法2:
flex: 0 0 50%;
//方法3:
flex-shrink: 0;
width: 50%;
//方法4:
min-width: 50%;
css

问题源于 The "xxx" property must adhere to the structure of a constructor in vue/require-prop-type-constructor.
场景:
在有 eslint 情况下,使用 String | Number 会报如上错误。
报错原因:
组件 props 有多种类型时要用数组写法
解决方法:
props: {
pid: {
type: [Number, String],//String | Number
default: 1
}
}
js
13.Vue style 里面使用@import 引入外部 css, 作用域是全局的解决方案
场景:
使用@import引入外部css ,作用域却是全局的
<style scoped>
@import "../css/reset.css";
/* 或 */
@import url("../css/reset.css");
</style>
或是
<script>
import "../css/reset.css";
</script>
html

原因:
使用@import引入外部样式表作用域是全局的
@import并非仅仅是将代码导入到 <:style> 内部,
而是通过发起新的请求来获取样式资源,
而没有添加 scoped 标签。
解决方法:
为了避免样式全局化问题,请将原有的@import标签更换为一个完整的<style>元素,并指定其来源路径
<style scoped src="../css/reset.css"></style>
<!-- 这种方法使用会出现一个玄学问题,路由首页使用,reset.css的样式会被本页面的样式覆盖,但是在 非路由首页使用(注:首页没有引入)时,reset.css会在样式最上方,相当于会覆盖本页面样式-->
<style scoped>
/* 本页面样式 */
</style>
html
14.JS 在一个数组中过滤掉另一个数组的简易方法
// 方法1:
let Arr1 = [
{
id: 1,
},
{
id: 12,
},
{
id: 13,
},
{
id: 14,
},
];
let Arr2 = [
{
id: 1,
},
{
id: 12,
},
];
let newArr = [];
newArr = Arr1.filter(itemA => {
return Arr2.every(itemB => {
return itemB.id !== itemA.id;
});
});
// 方法2:
let arr1 = [1, 2, 3, 4, 5, 6];
let arr2 = [3, 2];
let newArr = [];
Arr1.forEach(item => {
if (!Arr2.includes(item)) {
newArr.push(item);
}
});
// 方法3:
let arr1 = [1, 2, 3, 4, 5, 6];
let arr2 = [3, 2];
let newArr = [];
newArr = arr1.filter(item => arr2.indexOf(item) == -1);
// 方法4:
let arr1 = [1, 2, 3, 4, 5, 6];
let arr2 = [3, 2];
let newArr = [];
function getArrDifference(arr1, arr2) {
return arr1.concat(arr2).filter(function (v, i, arr) {
return arr.indexOf(v) === arr.lastIndexOf(v);
});
}
newArr = getArrDifference(arr1, arr2);
js

15.解决 el_table 固定列下方多了一条线问题
::v-deep {
.el-table__fixed-right,
.el-table__fixed {
height: 100% !important;
}
}
css
16.解决 setInterval 方法在 if 条件语句判断无效的问题
同一页面若未清除clearInterval()后,则会导致持续定时执行。
var timer = null;
var a = 1;
if (a === 1) {
clearInterval(timer);
timer = null;
} else {
timer = setInterval(() => {}, 1000);
}
js
17.axios 的 post 请求为什么要使用 qs
结论:用不用取决于后端怎么接收参数
axios默认情况下采用application/json作为content-type, 也就是json格式. 后端则可以通过字符串进行捕获, 然后对其进行解析即可完成数据处理流程.
18.关于 js 的 style.width 取不到元素的宽度值的问题
过去长期依赖于jquery框架中的.width()方法来获取任意HTML元素的当前宽度值。这种技术在任何情况下(无论是CSS样式设置为内联样式、外部样式表还是内部样式定义的情况下)都是有效的。
在尝试获取一个元素宽度时,在使用 native JavaScript 时,请注意调用 document.getElementById("id").style.width 或者 document.getElementById("id").width 都无法得到结果。
原来,在以下情况下,js 无法取到.style.width或者.width的值。
-
- 元素没有指定宽度值。
-
- 元素设置了宽度值,并未将其放置于内联或外联样式表中;相反地,在内嵌式布局中。
比如:
css 代码
p {
background: red;
width: 200px;
}
css
html 代码
<p id="p1">一段很长的文字</p>
html
尽管这种方案无法直接获取宽度值, 但也能够设定元素的宽度值. 例如: 将p元素的宽度设定为200px:
document.getElementById("p1").style.width = "200px";
js
因此,在设置元素样式为嵌入式之前,请确保能够通过 document.getElementById("id").style.width 获得宽度信息;例如:
<p id="p1" style="144px;">一段很长的文字</p>
执行 js 代码
var w = document.getElementById("p1").style.width;
alert(w);
js
执行后输出结果为 144px。
值得注意的是,在未预先指定宽度的元素或采用非内嵌式CSS样式的情况下,默认情况下无法通过直接访问元素宽度来实现目标。为了获取该属性值,请使用offsetWidth属性。
即:
document.getElementById("p1").offsetWidth;
js
对于设置了 CSS 样式的元素(内联、内嵌、外联)
offsetWidth也都可以获得值
因此,在使用时可以通过jquery的width()或 js 的offsetWidth来获得元素的宽度,并且不同之处在于…
jquery属性中的.width()仅表示内容区域的宽度,并未包含外部及内部边框。offsetWidth参数涉及内层边框及外围边界框。
19.sass-loader版本的问题导致了错误:$options中存在未知属性'prependData'。这些属性都是有效的。
原因:npm 和 sass-loader 的版本高了。
因为 sass-loader 版本有所变化,在 loaderOptions 中 additionalData 的 key names 也会相应调整
sass-loader v8-,这个选项名是"data"
sass-loader v8,这个选项名是"prependData"
sass-loader v10+,这个选项名是"additionalData"
bash
结果:
//原来的
css: {
loaderOptions: {
sass: {
prependData: '@import "@/scss/settings.scss";';
}
}
}
//修改后
css: {
loaderOptions: {
sass: {
additionalData: '@import "@/scss/settings.scss";';
}
}
}
js

20.为什么 document.addEventListener(‘load’, function(){})不能生效?
根本原因在于,在document.addEventListener$event listeners$load()内部并没有被显式配置为监听该事件。因此,在这种情况下运行相关代码可能会出现错误提示吗?如果代码未出现错误提示,则仍然无法正常执行。
应该在window对象上监听load事件,所以正确的代码如下:
window.addEventListener("load", function () {
console.log("load");
});
js
21.Vue 中的 render: h => h(App)什么意思?
这是文档里的内容:

在哪里见过呢,就是这里:
new Vue({
el: "#app",
router,
store,
render: h => h(App),
});
//或
new Vue({
router,
store,
render: h => h(App),
}).$mount("#app");
js

这是我们在使用 Vue 创建项目时常用的一句话。但这句话究竟表达了什么意思呢?对于初学者来说一见就懵圈吗?那初学 Vue 的人一见这句话肯定会有诸多困惑和不解。
因为这句写的真是简洁…
那么,参考上面文档中的内容,这句话的意思其实就是:
这是一个ES6箭头函数的写法,还原成一个函数,就是:
render: h => {
return h(App);
};
js
要是还看不懂,再进行还原:
render: function(h) {
return h(App);
}
js
然后,别忘了最先贴的官方文档,解释“h”的含义,进一步还原:
render: function(createElement) {
return createElement(App);
}
js
而这里的render相当于一个渲染函数,
而createElement相当于创建节点,
而App相当于Vue默认的HTML文件,
因此,在本质上这是将App这个HTML页面进行渲染,
当然,在App页面中嵌入了其他路由组件,
从而能够渲染各个嵌入式组件。
22.【前端技巧】git 已经 push 的代码如何修改 commit
- 修改倒数第 n 次的 commit,输入命令:
# 最后的数字1可以是倒数第n次
git rebase -i HEAD~1
bash
按回车键后切换至编辑模式并定位到需要修改注释的那一行。替换该行开头处的"pick"为"edit"并使用Esc键退出编辑模式后输入:wq!完成保存操作。
更正 commit 注释内容,输入命令:
git commit --amend
bash
按下回车键后切换至编辑模式,在当前行的非下方区域设置为正确的格式,并在完成保存操作后按下ESC键脱离编辑状态。
rebase 确认,输入命令(该部可省略):
git rebase --continue
bash
- 强制 push,输入命令:
git push --force
bash
至此,commit 的 message 内容修改完成!
23.Vue3 新属性之 css 中使用 v-bind 的问题汇总(v-bind in css)
有以下 4 种定义:
// 进行拼接调用测试的数据
let width = 400;
// 直接调用的数据
let div_height = "400px";
let div_color = "#e89393";
// 对象调用的数据
let span = {
width: "200px",
height: "200px",
color: "green",
};
// 组合调用的数据
let transition = "cubic-bezier(0, 1.5, .6, 1)";
js

1.在css中使用,使用v-bind()进行绑定 :
直接使用:完全没有问题
拼接使用:这个在css中没有问题,不过在scss中会出现错误
对象调用:在某些编程环境中(如Python),对象的操作如同直接使用类似。但需要注意的是,在某些编程环境中(如Python),必须将对象的操作括起来才能正常使用;如果直接书写会导致错误。
组合使用:完全没问题
四种样式写法如下:
.div {
/* 拼接使用 */
width: v-bind(width + "px");
/* 直接使用 */
height: v-bind(div_height);
background: v-bind(div_color);
}
.span {
/* 对象调用 */
width: v-bind("span.width");
height: v-bind("span.height");
background: v-bind("span.color");
display: flex;
justify-content: center;
align-items: center;
}
.span_title {
width: 100px;
height: 100px;
background: #000;
color: white;
/* 组合使用 */
transition: all 0.9s v-bind(transition);
}
.span:hover .span_title {
border-radius: 50%;
background: #a5f5b8;
color: #ff0000;
}
css

2.在less中使用,使用v-bind()进行绑定 :
直接使用:没有问题
拼接使用:存在问题 ,详见下文
对象调用:没问题
组合使用:没问题
四种样式写法如下:
// 使用变量承接
@height: v-bind(div_height);
.div {
width: 400px;
/* 直接使用 */
height: @height;
background: v-bind(div_color);
.span {
@width: v-bind("span.width");
/* 对象调用 */
width: @width;
height: v-bind("span.height");
background: v-bind("span.color");
display: flex;
justify-content: center;
align-items: center;
.span_title {
@transition: v-bind(transition);
width: 100px;
height: 100px;
background: #000;
color: white;
/* 组合使用 */
transition: all 0.9s @transition;
}
&:hover .span_title {
border-radius: 50%;
background: #a5f5b8;
color: #ff0000;
}
}
}
less

仅对拼接进行修改:
// 定义使用的数据
let width = 400;
js
// 1.直接拼接
@width: v-bind(width + "px");
width: @width;
// 2.拿到内容后拼接
@width: v-bind(width) + "px";
width: @width;
// 3.使用时拼接
@width: v-bind(width);
width: @width + "px";
less

其中第二种、第三种会没有效果,第一种会直接报错。
解决方式(思路):
为变量内容设计拼接方式,并将其应用于所定义的less或scss中;由于这些样式属于行内样式,在应用时需确保优先级及变量位置均位于前面(因此无需额外处理即可正常应用)。
使用数据的定义:
// 大部分数据和预先提供的数据一样(这里只写了新增数据)
let test = 400;
js
页面结构:
<!-- 改变的内容为下面这行(其他内容和原来内容保持一致)-->
<!-- 【在这里对要使用的数据进行单位的绑定】-->
<div class="div" :style="{'--test' :test + 'px'}"></div>
html
样式的使用:
// 承接使用
@width: var(--test);
.div {
/* 使用 */
width: @width;
/* 或者直接使用 */
width: var(--test);
height: 400px;
background: red;
}
less

3.在scss中使用,使用v-bind()进行绑定 :
直接使用:没有问题
拼接使用:存在问题
对象调用:没问题
组合使用:没问题
// 使用变量承接
$width: v-bind(width + "px");
$height: v-bind(div_height);
.div {
/* 拼接使用 */
width: $width; //没有生效
/* 直接使用 */
height: $height;
background: v-bind(div_color);
.span {
$width: v-bind("span.width");
/* 对象调用 */
width: $width;
height: v-bind("span.height");
background: v-bind("span.color");
display: flex;
justify-content: center;
align-items: center;
.span_title {
$transition: v-bind(transition);
width: 100px;
height: 100px;
background: #000;
color: white;
/* 组合使用 */
transition: all 0.9s $transition;
}
&:hover .span_title {
border-radius: 50%;
background: #a5f5b8;
color: #ff0000;
}
}
}
scss

更多详情,查阅:
在Vue3框架的新特性中,在css模块中采用v-bind的方式(亦称v-bind在css中的应用)
24.设置网页为黑白色
/* 网页为黑白色 ,以表哀悼*/
html {
filter: grayscale(100%);
-webkit-filter: grayscale(95%);
-moz-filter: grayscale(100%);
-ms-filter: grayscale(100%);
-o-filter: grayscale(100%);
filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
-webkit-filter: grayscale(1);
}
css

25.解决 el-tree 点击行上面的操作按钮后,当前行变成白色背景的问题

// 此处是导致:el-tree点击上面的操作按钮后,当前行变成白色背景的根本原因,样式中单独看el-tree-node__content无法查看
.el-tree-node:focus > .el-tree-node__content {
background-color: #28335f;
}
css
26.vue 子组件 watch 监听不到 prop 的解决
watch 添加immediate: true,添加immediate: true,添加immediate: true
27.关于 Vue eventBus 总线传值时的生命周期问题
https://www.jianshu.com/p/b1cb604dd4ae
1.解决 vue bus.emit触发第一次on 监听不到问题
https://www.uoften.com/article/186494.html
28.for of 和 for in 的区别
29.Vue 报错 error:0308010C:digital envelope routines::unsupported
原因:其实这不是 vue 的问题,是 nodejs 升级引起的构建错误
该错误出现的原因是由于在 node.js 17版本中 OpenSSL 3.0版本刚被发布。该版本的 OpenSSL 3.0对允许使用的算法以及密钥大小做出了严格的规定。这些规定可能会影响到整个生态系统的稳定性
并非所有项目都会出现。例如,在使用最新版本的 webpack 工具的情况下能够顺利运行。从而弄清问题的根本原因究竟是哪些因素导致了这一现象。
具体详看:
node.js版本升级导致的应用构建出现问题:错误码为0308010C:digital envelope routines::unsupported
解决方法:
方法 1. 启动终端(按下 Win+R 键弹出菜单,在键盘上输入 cmd 然后回车)并按照指示将这些内容复制到剪贴板后回车:(建议尝试后检查返回结果)
Linux & Mac OS (Windows Git Bash)
export NODE_OPTIONS=--openssl-legacy-provider
bash
windows 命令提示符:
set NODE_OPTIONS=--openssl-legacy-provider
bash
方法 2.尝试卸载 Node.js 17+版本并重新安装 Node.js 16+版本
通过将更高版本的webpack进行更新与升级至最新版本以解决此问题
tips:然而,在进行软件开发时发现一个问题
由于最近更新了某些核心库模块
需要注意到这可能导致一系列潜在的问题
特别是那些高度依赖这些库的项目可能会遇到兼容性问题
升级虽然带来了诸多不便
但为了提高开发效率还是值得尝试一下
30.js 模板字符串里面用换行符不起作用
在某些情况下会遇到赋值过程中变量名出现换行的需求但简单地插入\n并不能解决问题严格来说只有在特定语境下才能正确实现这一目标
this.text = `提示: \n ${this.tip}`;
js
解决方法:
在其HTML标签元素中进行相关样式配置:white-space:pre-line;通过应用这些CSS设置即可让上述代码段正常运行。
在其HTML标签元素中进行相关样式配置:white-space:pre-line;通过应用这些CSS设置即可让上述代码段正常运行。
//html
<div style="white-space:pre-line">{{ text }}</div>;
//js
this.text = `提示: \n ${this.tip}`;
js
tips:要让
title换行的具体方法是这样的,并不需要设置白色空格样式的原因在于样式仅影响标签内内容显示效果。
<span :title="`${data[treeProps.label]}\n${data.absolute}`">
{{ data[treeProps.label] }}</span
>
html
31.try catch 无法获取 then 的异常
在 JavaScript 中,在处理同步代码块时通常会使用 try...catch 语句来捕获可能出现的错误;然而,在处理 Promise 基于的异步操作时 try...catch 语句无法直接捕获 then 或 catch 方法中的错误;这是因为 then 和 catch 方法返回的是一个新的 Promise 对象,并且它们内部的回调函数是以异步方式执行的
为了在\texttt{Promise}中捕捉错误\texttt{,}建议在\texttt{Promise}链中调用\texttt{.catch()}\texttt{方法};此外\texttt{,}在代码中通过将$\texttt{async/await}\texttt{与}\texttt{try...catch}\texttt{结合来处理异步错误}。
使用 .catch() 方法
someAsyncFunction()
.then(result => {
// 处理结果
})
.catch(error => {
// 捕获错误
console.error("捕获到错误:", error);
});
js
使用 async/await 与 try...catch
async function main() {
try {
const result = await someAsyncFunction();
// 处理结果
} catch (error) {
// 捕获错误
console.error("捕获到错误:", error);
}
}
main();
js

在 Async/Await 示例中, await 关键字会在 async 函数执行时进行暂停, 直至 Promise 被 solved 或 rejected. 当 promise 被 rejected 时, await 表达式会抛出一个 error, 该 error 可以被外部 try...catch 框cept捕获.
请务必注意,在ES2017版本中引入了async/await这一特性,请确保你的开发环境已配备该功能的支持或采用Babel等工具完成转译以实现兼容性
错误的例子:try…catch 无法捕获 then 中的错误
try {
someAsyncFunction().then(result => {
// 如果这里发生错误,try...catch无法捕获
throw new Error("这是一个错误");
});
} catch (error) {
// 这个catch不会执行,因为上面的错误是在Promise的回调中抛出的
console.error("这个错误不会被捕获:", error);
}
js
在上述示例中,在尝试执行 someAsyncFunction() 时,在尝试执行 someAsyncFunction() 时,
尽管有 try...catch 包围了它的调用,
然而错误却是在 Promise 的 then 调用位置抛出的,
因此 try...catch 无法捕捉到此错误。
要捕获此错误,请确保在 Promise 链中使用 .catch() 方法。
32.vsCode 中的 css 代码提示 reference 怎么关闭
打开设置搜索,将其取消勾选即可
Code Lens
取消 Editor:Code Lens 的勾选
33.el-table、vxe-table 当调整页面宽度时
父级添加overflow: hidden;
34.vue 数组的更新,watcholdVal和newVal值一样
当在 Vue 2 或 Vue 3 中对数组进行操作时(如 push、unshift 和 splice),会观察到 watch 监控下的 oldVal 和 newVal 值相同
原因如下:
oldVal与newVal数值相同的原因是它们共享同一个内存地址 。Vue框架在处理数据时不会复制旧值供后续操作。- 从代码实现来看,在观察时触发
push、unshift、splice三个方法后,在此处手动绑定该观察器即可。其余方法的数据变更均只会对当前索引位置产生影响 ,因此无需再绑定此观察器。
组件的emit事件‘formValidate’并未在emit选项中声明或作为‘onFormValidate’属性设置
- 报错原因
组件触发了事件"confirmForm",但它没有在 emit 中声明
2.错误代码
const emits = defineEmits("formValidate");
js
- 正确
const emits = defineEmits(["formValidate"]);
js
tips: 如果存在 emit 未知的方法,则不能在 defineEmits 中不传递任何值;否则会同样对未定义的事件名发出警告。
建议明确声明组件将触发的事件,并非隐式触发全局事件;尤其是在使用 Vue 3.0 和 TypeScript 的场景下可能会报错。
示例:
// 此时假如有其他emits,如"editCell","selectChange"等
// 当你不传递任何参数给 defineEmits 时,它默认允许组件触发任何事件,而不会对事件名进行任何验证
const emits = defineEmits(); //["editCell","selectChange"]
const operateClick = (rowInfo, btn, rowIndex) => {
if (
btn.disabled &&
(btn.disabled === true || btn.disabled(rowInfo, btn) === true)
)
return;
if (btn.clickFun) {
if (verifyType(btn.clickFun, "Function") === true) {
btn.clickFun(rowInfo, btn, rowIndex);
} else {
emits(btn.clickFun, rowInfo, btn, rowIndex);
}
} else {
console.error("按钮未定义clickFun点击事件回调");
}
};
js

36.absolute 固定在滚动容器里面失效
场景:一个浮动元素位于滚动容器内底部位置。该滚动容器采用相对定位方式放置于父级组件中;而该浮动元素则采用绝对定位方式固定在滚动容器底部附近区域。然而,在实际应用中发现一个问题:当内容数量逐渐增多时(导致滚动条的出现),该浮动元素的位置随之向上移动至滚动条上方区域
解决方法:
就把 position:absolute 换成 sticky
position: sticky;
css
如果滚动容器内的内容不足一屏显示时,则无滚动条生成的情况下此浮层会自动升起。为了实现这一效果可对滚动容器设置为弹性布局并配置其内部的内容使用flex-grow属性设值为1这样会使得滚动内容自动占据可用空间从而解决问题。
//滚动容器
display: flex;
flex-direction: column;
//滚动内容
flex-grow:1;
css
37.el-form 表单输入框回车事件导致页面刷新问题
当一个el-form表单仅包含一个el-input字段时,在按下回车键后该输入字段会自动触发默认提交事件从而导致页面重载;然而在包含多个表单元素的情况下这一问题将不会出现
原因分析:
输入框按回车触发页面刷新的主要原因是由于浏览器的默认行为。
根据 W3C 的规定,在 form 元素仅包含一个输入框时,在该输入框按下回车将提交表单。
el-form 实际上也属于表单(通过查看网页源码即可发现 el-form 会被转换为标准的 form 元素),因此它依照 HTML 的默认规则运作。
解决方案:为 el-form 表单添加一个@submit.native.preventDefault代码段以禁用表单提交的行为
注:vue3,需要使用
@submit.enter.prevent,原因:vue3 中移除v-on.native修饰符
<!-- Vue2 + element UI 禁用表单提交 -->
<!-- 在<from> 中添加@submit.native.prevent -->
<el-form @submit.native.prevent></el-form>
<!-- Vue3 + element Plus 禁用表单提交 -->
<!-- 在<from>中添加@submit.enter.prevent -->
<el-form @submit.enter.prevent></el-form>
html
38.vxe-table 父子不关联,不影响全选功能
场景:表格父子不关联,但此时的全选功能失效
解决方法:
在 handleCheckedAllCheckboxRow 方法和 checkSelectionStatus 方法中进行优化。
根据建议 2 的要求进行优化:在判断是否需要显示表头时加入 showHeader 判断。
避免采用过于粗暴的一刀切式的方法。
详情查看 [checkStrictly 父亲与子女之间关系优化方案及实施计划,在DataBody表中仅涉及数据相关联设置,请确保父亲与子女之间保持脱节状态以避免影响整体选择能力;在多数业务情境下仍需维持选择操作] (https://gitee.com/xuliangzhan/vxe-table/issues/I7NXBJ)
39.使用 flex:1 导致 vxe-table 出现滚动一卡一卡的
如果某个 flex布局设置导致 vxe-table 出现频繁出现卡顿的情况,则可以通过为 flex:1 容器设置 overflow属性来解决此问题
更多查看
-
- 当外层使用 flexbox 适配宽度时, 表格的适配宽度存在一定的局限性, 调整过程较为漫长。
-
- 宽度适配是一个持续性的挑战。
40.ElMessage offset 修改
element-plus下生成es与lib两个文件夹,分别为 ESM 与 CJS 两种格式。
import { ElMessage } from "element-plus"; 方式引入
- 更新相关代码中的 offset 设置为 60
const messageDefaults = mutable({
customClass: "",
center: false,
dangerouslyUseHTMLString: false,
duration: 3e3,
icon: void 0,
id: "",
message: "",
onClose: void 0,
showClose: false,
type: "info",
offset: 16, //修改此次为60
zIndex: 0,
grouping: false,
repeatNum: 1,
appendTo: isClient ? document.body : void 0,
});
js

更改为将 node_modules\element-plus\es\components\message\src\message.d.ts 中的 readonly offset: 16 更改为 readonly offset: 60
export declare const messageDefaults: Mutable<{
readonly customClass: "";
readonly center: false;
readonly dangerouslyUseHTMLString: false;
readonly duration: 3000;
readonly icon: undefined;
readonly id: "";
readonly message: "";
readonly onClose: undefined;
readonly showClose: false;
readonly type: "info";
readonly offset: 16;//修改此次为60
readonly zIndex: 0;
readonly grouping: false;
readonly repeatNum: 1;
readonly appendTo: HTMLElement;
}>;
js

const { ElMessage } = require("element-plus"); 方式引入
更正 node_modules/element-plus/lib/components/message/src/message.js 中的偏移量至值 60
const messageDefaults = typescript.mutable({
customClass: "",
center: false,
dangerouslyUseHTMLString: false,
duration: 3e3,
icon: void 0,
id: "",
message: "",
onClose: void 0,
showClose: false,
type: "info",
offset: 16, //修改此次为60
zIndex: 0,
grouping: false,
repeatNum: 1,
appendTo: core.isClient ? document.body : void 0,
});
js

在node_modules/element-plus/lib/components/message/src/message.d.ts中指定配置项中的offset属性值由16更改为60
export declare const messageDefaults: Mutable<{
readonly customClass: "";
readonly center: false;
readonly dangerouslyUseHTMLString: false;
readonly duration: 3000;
readonly icon: undefined;
readonly id: "";
readonly message: "";
readonly onClose: undefined;
readonly showClose: false;
readonly type: "info";
readonly offset: 16;//修改此次为60
readonly zIndex: 0;
readonly grouping: false;
readonly repeatNum: 1;
readonly appendTo: HTMLElement;
}>;
js

41.有关 form 表单 validate 的使用
第一种写法:
let isValid = await addFormRef.value.validate().catch(err => {
return err; // 关键问题在这里
});
if (isValid === true) {
return true;
} else {
return false;
}
js
这种写法的主要问题在于:
- 错误处理的逻辑问题:
使用 await 关键字立即触发 addFormRef.value.validate() 的操作。
通过 catch 处理所有可能出现的情况,并将所有出现的错误传递给 isValid。
可能包含详细信息的对象作为错误对象。
此时 isValid 的值变为一个包含详细信息的对象。
- 类型判断问题:
if (valid === true)采用了严格的相等判断,在这种情况下进行的比较旨在对比两个布尔型数据。- 当
isValid为无效对象时(即非对象实例),这种比较将无法成功。 - 这种情况可能导致在验证失效时的逻辑判断不符合预期。
- 当
第二种写法:
const isValid = await new Promise(resolve => {
addFormRef.value.validate(valid => resolve(valid));
});
js
这种写法更好:
采用了 Element Plus 表单验证的标准回调方式。
该方法的回调函数接受验证结果(布尔值)。
通过包装验证过程并利用 Promise 的 resolve 方法正确返回布尔值。
保证 isValid 始终为布尔值。
总结:
推荐使用第二种写法,因为:
- 代码更加精炼
- 错误处理更为精确,在采用第一种写法处理验证失败情况时可能存在不足之处:其中一种写法在处理验证失败的情况时可能存在问题;错误对象与
true的比较可能导致结果不准确 - 返回结果更加可靠:总能提供可靠的布尔值反馈
- 符合Element Plus表单验证的标准用法
如果需要处理错误,建议使用这种写法:
const isValid = await new Promise((resolve, reject) => {
addFormRef.value.validate((valid, errors) => {
if (valid) {
resolve(true);
} else {
reject(errors);
}
});
}).catch(errors => {
console.error(errors);
return false;
});
js

42.解决el-popup-parent–hidden 会携带 width: calc(100% - 8px) 样式的问题
当body被打开为弹框时,在使用el-drawer、el-message-box或el-dialog组件的情况下,
body会被配置为一个class: el-popup-parent--hidden,
并且可能会应用类似width: calc(100% - 8px)的样式规则。
更多信息访问:el-popup-parent–hidden
解决方法: 1.重写 el-popup-parent–hidden 的样式
.el-popup-parent--hidden {
width: 100% !important;
}
css
2.在 main.js 中添加关闭 dialog 滚动条配置
// 此方法未验证会不会影响到弹框的滚动条,慎用
// vue2
import ElementUI from "element-ui";
// vue3
import ElementPlus from "element-plus";
import "element-ui/lib/theme-chalk/index.css";
// 关闭dialog滚动条
ElementUI.Dialog.props.lockScroll.default = false;
ElementPlus.Dialog.props.lockScroll.default = false;
js
