文章目录
前言
主要是记录下使用vue3开发中遇到的一些问题,其中有vue3代码,以及一些第三方组件element-plus组件样式的问题;
一、vue3中的问题
vue3中踩坑问题汇总,主要是针对,vue3 <scipt setup>
这种语法糖形式使用的问题
1、defineExpose方法
当我们想要通过父组件调用子组件的方法的时候,我们发现直接使用
proxy.$refs['子组件ref'].子组件方法
。这种方式不行。然后我看了下官方文档,问题就是父组件想要调用子组件方法,子组件的方法必须通过defineExpose的方式把子组件暴露出来,这样父组件才可以使用
官方使用方法:暴露变量
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
</script>
实际案例中的使用:暴露方法
<template>
//父组件中使用子组件
<child-component ref='child'/>
</template>
//父组件调用
<script setup>
import {getCurrentInstance} from 'vue';
const {proxy} = getCurrentInstace();
//showChild方法是子组件的方法
proxy.$refs['child'].showChild();
</script>
//子组件使用
<script setup>
const showChild = ()=>{
console.log('子组件方法');
}
//暴露子组件方法
defineExpose({showChild});
</script>
2、defineEmits()
这个方法就是用来子组件向父组件发送事件的方法,
也可以理解成子组件通过这种方式来修改父组件中变量的方法
defineProps 和 defineEmits 都是只能在
先看官网上的案例:
<script setup>
const props = defineProps({
foo: String
})
const emit = defineEmits(['change', 'delete'])
// setup 代码
</script>
//子组件发送
emit('change');
//父组件中接收
<child-component @change=change></child-component>
<script setup>
const change = ()=>{
console.log('子组件触发');
}
</script>
3、动态生成form表单内容获取不到$refs的问题
通过v-for循环遍历数组,生成form表单中的各项form-item,然后通过v-if判断item中的类型是否存在,如果存在就展示对应的元素,并展示动态的内容,然后我需要获取当前生成的form-item中的子组件富文本编辑器wangEditor的ref并调用富文本编辑器中的方法。我们直接来看代码:
<el-dialog :title="title" v-model="open" :width="dialogWidth" append-to-body :destroy-on-close="true">
<el-form ref="templateRef" :model="form" :rules="rules" label-width="80px">
</el-row>
<el-row v-if="itemList.length>0" >
<template v-for="(item,index) in itemList" :key="index">
<el-col :span="item.itemType === 'editor'? 24 :12" >
<el-form-item :label="item.itemLabel" v-if="item.itemType === 'input'" :prop="item.itemFiled">
<el-input :placeholder="item.itemDesc" disabled style="width: 100%"/>
</el-form-item>
<el-form-item :label="item.itemLabel" v-if="item.itemType === 'radio'" :prop="item.itemFiled">
<el-radio-group v-model="item.itemId" class="ml-4">
<el-radio label="1" v-for="(it,index) in typeList.gender" :key=index :label="it" disabled>{{it}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="item.itemLabel" v-if="item.itemType==='checkbox'" :prop="item.itemFiled">
<el-checkbox v-for="(it,index) in typeList.hobby" :key=index v-model="item.itemId" :label="it" disabled />
</el-form-item>
<el-form-item :label="item.itemLabel" v-if="item.itemType ==='droplist'" :prop="item.itemFiled">
<el-select v-model="typeList.education[0]" disabled style="width: 100%">
<el-option v-for="(it,index) in typeList.education" :key="index" :value="index" :label="it" ></el-option>
</el-select>
</el-form-item>
<el-form-item :label="item.itemLabel" v-if="item.itemType==='textarea'" :prop="item.itemFiled">
<el-input :type="item.itemType || ''" :placeholder="item.itemDesc" disabled style="width: 100%"/>
</el-form-item>
<el-form-item :label="item.itemLabel" v-if="item.itemType==='file'" :prop="item.itemFiled">
<el-upload
class="avatar-uploader"
:action="uploadImgUrl"
:show-file-list="false"
:headers="headers"
accept=".jpg,.jpeg,.png,.PNG,.JPG,.JPEG"
:on-success="handleAvatarSuccess"
disabled
:before-upload="beforeAvatarUpload">
<img v-if="form[item.itemFiled]" :src="form[item.itemFiled]" class="avatar" />
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</el-form-item>
<el-form-item :label="item.itemLabel" v-if="item.itemType==='editor'" :prop="item.itemFiled">
<BasicEditor ref='contentRef' :isAble="true" :text="item.itemDesc" v-model="form[item.itemFiled]"></BasicEditor>
</el-form-item>
</el-col>
</template>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="submitForm">保 存</el-button>
<el-button type="primary" @click="handleReport">发 布</el-button>
</div>
</template>
</el-dialog>
//js逻辑部分
<script setup>
//当我们通过平常的方法去获取对应的ref的时候,控制台直接报错,`说insertText这个function is undefined`,其中insertText是子组件暴露出来的方法,父组件可以调用
proxy.$refs.contentRef.insertText("<p>这是富文本框中的额内容</p>");
//首先我根据这个错误,我觉得是因为没有获取到对应的dom元素,所以才找不到这个方法,所以我就在nextTick()中调用这个方法,但是结果还是错误的,所以我排除了这个方法,
//最后发现应该是$refs这个不是动态的,而且我的这个结构时v-for和v-if影响的结果,所以我就改变了富文本框中的结构,使用了下面的方式来实现,下面只展示富文本框中的信息。
</script>
<el-form-item :label="item.itemLabel" v-if="item.itemType==='editor'" :prop="item.itemFiled">
//basicEditor,是封装的富文本编辑器wangEditor
<BasicEditor :ref='setRef' :isAble="true" :text="item.itemDesc" v-model="form[item.itemFiled]"></BasicEditor>
</el-form-item>
//在这里可以看到我改变了ref的方式使用了setRef
<script setup>
import {ref} from 'vue';
const contentRef = ref([]);//设置响应式的数据
function setRef(el){
if(el){
contentRef.value[o] = el;
contentRef.value[0].insertText("<p>这是富文本框中的额内容</p>");//现在可以设置成功
}
}
</script>
二、element-plus中问题
在使用element-plus组件的时候,遇到的一些问题汇总
1、select选择器
我发现当我们使用字典接口的时候,我们取到字典数组,然后通过
select选择器
中的option
中遍历数组,但是如果只在新增的时候调用字典方法,就会导致我们点击编辑的时候,页面中只会回显对应的id或者数字,这是因为我们没有没有在编辑的时候获取获取到对应的字典值。
所以这个问题的解决方法就是:我们调用字典的时候,直接在页面初始化的时候调用,这样就不会没有数据了,就能够回显出正确的label 了
2、tree-select树形选择器
项目描述:在一个dialog编辑中有一个树形选择器,选择器中数据量很大,当我们点击编辑的时候如果选择器的树形结构默认展开,dialog就会加载很长的时间,大概10s左右(跟数据量有关系),严重影响了用户的操作体验;
所以根据上面的问题有下面两种解决方案:
2.1 折叠树形结构
设置
:default-expand-all="false"
:这种方法确实可以解决上面的问题,dialog正常打开,但是编辑中树形选择器回显数据不对,回显的是id,因为选择器我们一般都是通过id去回显对应的label的。所以这种方式存在数据回显不对的bug,不推荐使用,这里只是提供一种思路。
<el-col :span="24">
<el-form-item label="发布范围" prop="publishRangeIdsArray" v-if="isAdd">
<el-tree-select style="width: 100%" v-model="form.publishRangeIdsArray" :data="pubScopedList"
multiple :node-key="defaultProps.value" check-strictly :default-expand-all="false"
placeholder="请选择发布范围" :props="defaultProps" :expand-on-click-node="false" clearable/>
</el-form-item>
</el-col>
2.2给dialog中的form表单添加loading
当我们点击编辑的时候给form一个loading的加载过程,让用户知道页面正在加载,而不是上面的等10s之后再出来,这种方式只能说临时解决了我们上面的问题(用户可以接受,但体验感不好),但是没有从根本上解决。
<el-dialog :title="title" v-model="open" width="507px" append-to-body :destroy-on-close="true">
//实现加载的效果
<div v-loading="editLoading">
<el-form ref="standardRef" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="24">
<el-form-item label="名称" prop="reportName">
<el-input v-model="form.reportName" placeholder="请输入名称" clearable/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="所属专题" prop="subjectId">
<el-select v-model="form.subjectId" placeholder="请选择所属专题" style="width: 100%;" clearable>
<el-option v-for="(item, index) in subjectList" :key="index" :value="item.subjectId" :label="item.subjectName"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="发布范围" prop="publishRangeIdsArray" v-if="isAdd">
<el-tree-select style="width: 100%" v-model="form.publishRangeIdsArray" :data="pubScopedList"
multiple :node-key="defaultProps.value" check-strictly :default-expand-all="isExpand"
placeholder="请选择发布范围" :props="defaultProps" :expand-on-click-node="false" clearable/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="上传附件" prop="files">
<file-upload v-model="form.files" :disabled="true" :isShowTip="false" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="dialog-footer" style="text-align: right;">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="submitForm">保 存</el-button>
</div>
</div>
</el-dialog>
<script setup>
//页面加载的效果
const editLoading = ref(false);
//isAdd:是否展示发布范围
const isAdd = ref(true);
//isExpand:设置是否展开树形接口
const isExpand = ref(false);
//新增的时候处理
function handleAdd(){
reset();
title.value = "新增"
open.value = true;
isExpand.value = false;
isAdd.value = true;
}
//编辑时候的处理
function handleUpdate(row){
isAdd.value = false;
open.value = true;
title.value = '编辑'
editLoading.value = true;
//调取获取详情接口,回显数据
detailReport(row.reportId).then(res=>{
form.value = {
reportId : row.reportId,
reportName : res.data.reportName || undefined,
subjectId : res.data.subjectId || undefined,
publishRangeIdsArray: res.data.publishRangeIdsArray || [],
files : JSON.stringify(res.data.files) || undefined
}
});
setTimeout(()=>{
isAdd.value = true;
isExpand.value = true;
editLoading.value = false;
},1000)
}
</script>