vue3踩坑
引入vue-router
几个细节:
-
npm install vue-router@next,或者4.0.6版本,不能直接npm install vue-router
-
需要从vue-router里面引入两个函数createRouter,createWebHistory,之前的我们直接引入Router
vue3:
import { createRouter,createWebHistory} from "vue-router";
const router = createRouter({
history: createWebHistory(),
routes
});
vue2:
import { Router} from "vue-router";
const router = new Router({
routes
})
-
组件必须要有.vue后缀,要不然会找不到文件(可以是vite的原因)
-
@这个东西好像也没用,会找不到文件
-
注意是history不是model,还有就是createWebHistory()记得加上()
react 改变数组
cloud.tencent.com/developer/a… 数组不能用push
react hook中的setTodos方法传入的数组会对原来的数据进行覆盖,这里需要注意传入的数组和原先的数组不能指向同一内存地址,也就是或setTodos方法的参数只能是todos的副本,而不能是引用,如果是引用则不会更新。
setTodos([
...todos,
{
text: "Learn Hooks"
}
]);
echart 横坐标在ios不会显示,因为ios 处理时间new Dates(time),time不能是'-',可改成'/'
new Date(time..replace(/-/g,"/")).getTime()
页面两个不同状体切换,会出现闪一下,可以改成路由的方式
react
if(this.state.selectedFieldId.includes(item.field)){
let index = this.state.selectedFieldId.indexOf(item.field)
this.state.selectedField.splice(index,1)
this.state.selectedFieldId.splice(index,1)
this.setState({
selectedField: this.state.selectedField,
selectedFieldId: this.state.selectedFieldId
});
console.log('index:',index, this.state.selectedFieldId)
} else {
this.state.selectedField.push(item)
this.state.selectedFieldId.push(item.field)
this.setState({
selectedField: this.state.selectedField,
selectedFieldId: this.state.selectedFieldId
// selectedField: [...this.state.selectedField,item],
// selectedFieldId: [...this.state.selectedFieldId,item.field]
});
console.log( this.state.selectedFieldId)
}
echart 混合图,需要加上zindex
ant design TimePicker 默认点击才能滚动,浮动层默认是以body进行定位的
Modal层滚动的时候body整体页面并没有滚动,所以导致浮动层不会跟随滚动. 解决方法就是使用TimePicker中的getPopupContainer属性来改变浮动层绑定的元素,Select和DatePicker同理。
TimePicker改成不需要点击就出现滚动条
.ant-picker-time-panel-column{
overflow-y: auto;
}
同时在移动端TimePicker下面的操作按钮没有居中对齐,手动设置
.ant-picker-ranges{
display: flex;
justify-content: space-between;
align-items: center;
}
创建全局组件
let div = document.createElement('div');
document.body.appendChild(div);
创建一个div,插到body里,再通过ReactDOM,将属性和你要写的组件样子传入,如
ReactDOM.render(React.createElement(Loading, props), div); 最后在你不需要它的时候,摧毁它,如
ReactDOM.unmountComponentAtNode(div);
document.body.removeChild(div);
el-table 树状结构 设置默认展开行
el-table 树状结构需要设置左对齐,不然看不清层级结构
treeselect组件 远程搜索 编辑 反显内容 unknown的问题,设置默认值,并且定义hack 布尔值重新渲染
this.backFillOptions = [
{ id: res.companyInfo.companyName,
label: res.companyInfo.companyName,
} ]
this.hack =! this.hack
<treeselect
v-if="hack"
key="t1"
v-model="companyName"
:async="true"
searchPromptText="输入搜索"
:default-options="backFillOptions"
:load-options="loadOptions"
placeholder="输入搜索再选择事业部名称"
@select="changeCompanyName" />
<treeselect
v-else
key="t2"
v-model="companyName"
:async="true"
searchPromptText="输入搜索"
:default-options="backFillOptions"
:load-options="loadOptions"
placeholder="输入搜索再选择事业部名称"
@select="changeCompanyName" />
vue 对象的属性没有初始化,赋值不会响应(不会被监听)
el-upload 自定义上传
-
无提交按钮::http-request="httpRequest" 自定义httpRequest函数
-
:auto-upload="false" 有提交按钮:在提交按钮时触发自定义请求接口
上传时候设置FormData,但是打印为{},并且直接使用axios不能成功,使用axios拦截的公共接口才执行通
直接打印是看不到的,要用FormData的get()和getAll()方法
同时校验多个子表单,任何一个没填都显示一个错误,使用自定义校验
var checkWater = (rule, value, callback) => {
let waterMid = this.$refs.waterMid.value;
let waterUpper = this.$refs.waterUpper.value;
if( value && waterMid && waterUpper ){
callback()
} else if(!this.form.waterDifference) {
callback()
}else {
callback(new Error('请填写阈值范围'))
}
}
el-select联动,不会清空错误,要手动clearValidate;并且被联动的选不中,需要$forceUpdate
this.$refs.form.clearValidate('departmentId')
el-tree只能在同级拖拽,使用:allow-drop = allowDrop
el-date-time-picker 设定不可选时间范围精确到秒,需要加selectableRange
let str = '12:12:12'
let pickOptions = {
disableDate: (time) =>{
return time.getTime() > Date.now()
},
selectableRange: str + ' - 23:59:59'
}
可以设置str,str就是临界的开始位置,它之前的值就不能选
下载文件
后端返回一堆乱码,前端需要设置responseType : 'blob'
element el-select 数据太多导致卡顿
解决方案:采用懒加载
<template>
<div class="flex-between-center edit-row" >
<el-select v-model="choose" placeholder="请选择" filterable
v-el-select-loadmore:rangeNumber="loadMore(rangeNumber)" size="small"
@change="handleMachineChange"
style="width: 280px"
:filter-method="filterMethod">
<el-option
v-for="(item, index) in finalList"
:label="`${item.machineNo} (${item.machineName})`"
:value="item.machineNo"
:key="index">
</el-option>
</el-select>
</div>
</template>
<script>
export default {
// model: {
// prop: 'choose',
// event: 'change'
// },
props:{
machineList: {
type: Array,
default: ()=>[]
},
value: {
type: String,
default: ''
}
},
watch: {
value(newVal){
this.choose = newVal
},
choose(newVal,oldVal){
this.$emit("input", this.choose)
},
// 执行2次,是因为请求了2次。 machineList有上千条
machineList:{
handler(){
this.currentList = []
// 深拷贝
this.currentList = this.machineList.slice(0)
this.handleList()
},
immediate: true ,
deep: true
},
},
directives: {
'el-select-loadmore':{
bind(el, binding){
const selectDom = el.querySelector(".el-select-dropdown .el-select-dropdown__wrap");
if(selectDom){
selectDom.addEventListener("scroll", function(){
// const condition = this.scrollHeight - this.scrollTop <= this.clientHeight;
// 不加条件才对,有待研究
// if(condition) binding.value()
binding.value()
})
}
}
}
},
computed: {
finalList(){
return this.currentList.slice(0, this.rangeNumber)
}
},
data(){
return {
currentList: [],
rangeNumber: 10,
choose: this.value
}
},
mounted(){// 切换的时候,这里不执行},
methods:{
filterMethod(val){
if(val){
this.currentList = this.machineList.filter((item)=>{
if(item.machineNo.includes(val) || item.machineName.includes(val)){
return item
}
})
}else{
this.currentList = this.machineList
}
},
handleList(){
let index0 = -1
let item0 = this.currentList.find((item, index)=>{
if(item.machineNo == this.choose) {
index0 = index
}
return item.machineNo == this.choose
})
// 修改:在展示前,循环总数据把选中的放在list的最前面
if(index0 > 0){
this.currentList.splice(index0,1)
this.currentList.splice(0,0, item0)
}
},
loadMore(n){
return () => this.rangeNumber +=5
},
handleMachineChange(e){
this.$emit('change',this.choose)
}
}
}
</script>
el-input监听paste事件
el-input v-model="val" placeholder="请输入内容" @paste.native.capture.prevent="handlePaste"/>
//获取粘贴的值
let clip = e.clipboardData.getData('Text')
this.val = clip
map遍历异步
async handleQrCode (ids) {
...
let promises = list.map(async (item, i) => {
return {
...item,
equipQrcodePath: (images[i]),
equipQrcodeFullPath: await formatFileUrl(images[i]),
}
})
this.qrCodeEquips = await Promise.all(promises);
}
forEach遍历异步换成for 循环遍历异步
async handleQrCode (ids) {
...
if(files && files.length>0){
for(let item of files) {
item.fullPath = await formatFileUrl(item.path);
}
}
}
在form种使用button,必须设置type=button,不然会跳走
使用position:relative 和 absolute实现相对于父元素的FIXED定位的实现
想让特定子元素相对于父元素"fixed"定位,也就是说,剩余的子元素不定位。那可以分开来想,如果添加一个祖先元素assistor,有两个祖先元素,一个用于辅助定位,一个用于包裹不定位的内容。
只要assistor和parent一样大,看起来就像是子元素child相对于父元素parent固定定位了。
<div class="assistor">
<div class="parent">
<div class="child"></div>
<div class="placeholder"></div>
</div>
</div>
.assistor {
position: relative; /*关键点*/
display: block;
width: 500px;
height: 300px;
margin: 100px auto 0 auto;
background-color: #ddd;
}
.parent {
width: 500px;
height: 300px;
background-color: #888;
overflow: auto; /*关键点*/
}
.child {
position: absolute; /*关键点*/
width: 120px;
height: 120px;
margin: 100px 50px;
background-color: #333;
}
.placeholder {
width: 1000px;
height: 1000px;
}