vu3踩坑

前言

主要是记录下使用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>
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值