首页 > 其他分享 >Vue3调用Element-plus涉及子组件v-model双向绑定props问题

Vue3调用Element-plus涉及子组件v-model双向绑定props问题

时间:2023-11-14 15:37:06浏览次数:34  
标签:const props prop plus Vue3 组件 model Element emit

Vue3调用Element-plus涉及子组件v-model双向绑定props问题

在Vue3调用Element-plus的el-dialog组件时,碰到个很有意思的问题,el-dialog的属性值v-model直接控制对话框的显示与否,点击关闭对话框和遮罩区域,组件内部会自动更改v-model的值为false来关闭对话框。问题在于当组件作为子组件时,若v-model绑定的值为父组件的属性,该如何双向绑定。

首先明白prop遵循单向绑定,即数据只能从父组件流向子组件。意味着prop是只读的,且计算属性computed也是只读的

先了解基础的子改父,若想实现子组件更改父组件的值,可以通过emit实现

<!-- 子组件更改父组件的值 -->
<!-- 父组件 -->
<template>
<h2>我是父亲</h2>
<Child :status="isShow" @ChangeStatus="updateisShow"></Child>
</template>
<script setup>
//省略import
const isShow=ref(true)
const updateisShow=(value)=>{
     isShow.value = value;
}
</script>

<!-- 子组件 -->
<template>
<h2 v-if=props.status>我是儿子</h2>
<button @click="emit('ChangeStatus',false)"></button>
</template>
<script setup>
//省略import
const props=defineProps(['status'])
const emit = defineEmits(['ChangeStatus'])
</script>

上述实现了prop的修改的一般需求,通过修改父组件属性同步到子组件进行间接修改。但并不能直接满足我的需求,比如开头说的点击关闭对话框和遮罩区域,el-dialog组件内部会自动更改v-model的值为false来关闭对话框,可以推测子组件的内部实现为status=false(假设v-model=“status”),这样问题就来到了对v-model的直接修改,但开头说了prop是只读的,且计算属性computed也是默认只读的,如何做到修改这两种。vue官方文档指出有两种方法,一是将prop改为对象类型,二是基于该 prop 值定义一个计算属性(为了可写,提供get和set方法)

  • 一、更改prop为对象类型

    官方文档:当对象或数组作为 props 被传入时,虽然子组件无法更改 props 绑定,但仍然可以更改对象或数组内部的值。这是因为 JavaScript 的对象和数组是按引用传递

但这种更改的主要缺陷是它允许了子组件以某种不明显的方式影响父组件的状态,可能会使数据流在将来变得更难以理解。

  • 二、基于prop定义计算属性
    定义计算属性,提供get、set方法,可以实现在直接修改v-model时,会调用set方法实现更改父组件的属性进而更新prop,推荐这种方式
<!--定义计算属性并提供get、set方法-->

<!-- 父组件 -->
<!-- dialogFormVisible作为prop传入子组件-->
<template>
<div class="btn_box">
    <el-button type="primary" @click="dialogFormVisible = true" style="border-radius: 100px;">上传<i
                                class="el-icon-upload el-icon--right"></i>
    </el-button>
</div>
    <UploadDialog :status="dialogFormVisible" :parentid="currentDirId" :userid="userId" @ChangeStatus="updatedialogFormVisible">
	</UploadDialog>
</template>
<scrpit setup>
const dialogFormVisible = ref(false)
const updatedialogFormVisible = (value) => {
    dialogFormVisible.value = value;
}    
</scrpit>

<!-- 子组件  -->
<!-- status属性控制对话框显示状态-->
<template>
    <el-dialog title="上传文件" v-model="status" >
        <el-upload ref="uploadRef" multiple :limit="3" action="" :http-request="uploadFile"
            :file-list="list_data.upload_fileList" :auto-upload="false"
            style="height: 300px;width: 400px;position: relative;left: 50%;transform: translate(-50%,0);">
            <template #trigger>
                <el-button size="small" type="primary">选取文件</el-button>
            </template>
            <el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上传</el-button>
            <template #tip>
                <div class="el-upload__tip">单次最多只能上传3个文件</div>
            </template>
        </el-upload>
    </el-dialog>
</template>
<script setup>
const props = defineProps(['status'])
const emit = defineEmits(['ChangeStatus'])
const uploadFile = (item) => {
    let formData = new FormData();
    formData.append('parentid', props.parentid);
    formData.append('userid', props.userid)
    formData.append('file', item.file);
    axios({
        url: 'http://localhost:8088/api/uploadFile',
        method: 'post',
        headers: { "Content-Type": "multipart/form-data" },
        data: formData
    })
        .then(resp => {
            ElMessage({
                message: resp.data.msg,
                type: resp.data.code === 20000 ? 'success' : 'error'
            });
            if (resp.data.code === 20000) {
                //上传成功,调用emit通知父组件更新dialogFormVisible,进而更新prop
                emit('ChangeStatus', false)
            }
        })
    const status=computed({
    //get
    get(){
        return props.status
    },
    //set
    set(newValue){
        emit('ChangeStatus',newValue)
    }
})
}
</script>

总结

prop:父传子,数据单向传递,且随着父组件数据更新同步更新到子组件

emit:自定义事件,使父组件可以监听到自定义事件,实现子改父

v-model的原理就是prop和emit,实现双向绑定

prop只读无法修改,但是若prop为对象类型,可以修改对应地址内的属性,但无法被computed监听

computed提供set方法可以实现可写

标签:const,props,prop,plus,Vue3,组件,model,Element,emit
From: https://www.cnblogs.com/chuimber/p/17831721.html

相关文章

  • element使用组件el-form自动定位到未填写的必填条目
    问题:在form表单el-form中经常会出现表单条目比较多的问题,而且在提交的时候需要校验表单并且定位到相应的条目位置。解决:html:<el-formref="form":model="form":rules="rules"label-width="140px"><el-form-itemlabel="规则名称"prop="ruleName&quo......
  • 通过PowerShellPlus示例脚本学习PowerShell-读取VMware主机信息
    ##=====================================================================##Title:GetVI-HostList##Description:RetrieveVMwareHosts##Author:Idera##Date:9/11/2008##Input:-VIserver:VirtualInfrastructureserver##......
  • 解决only one element tensors can be converted to Python scalars
    解决"onlyoneelementtensorscanbeconvertedtoPythonscalars"错误当我们使用PyTorch进行深度学习任务时,有时会遇到以下错误信息:"onlyoneelementtensorscanbeconvertedtoPythonscalars"。这个错误通常发生在我们尝试将一个只包含一个元素的张量转换为Python标量(s......
  • Vue3实现图片滚轮缩放和拖拽
    在项目开发中遇到一个需求:1:用鼠标滚轮可对图片进行缩放处理2:点击按钮可对图片进行缩放处理3:可对图片进行拖拽处理 我在开发中通过自己实现与百度查看优秀的铁子进行了两种类型的使用  <template><divref="imgWrap"class="wrap"@mousewheel.prevent="rollImg"......
  • 关于elementUI开发中使用的一些小技巧
    关于表格1.表格的勾选遇上分页问题:当需要对表格批量操作,并且表格数量量不止一页的情况下,怎么在点击下一页时再回来能够保留之前勾选的状态(前端分页)?在element官网中没有这个例子,但是有对应的两个属性就可以了只需要在多选框那一列加上这个属性,并且设置表格每行的key:例子:<el......
  • vue3中的vue-18n的table表格标题不动态变化中英文
    使用computed即可 eg:constcolumns=computed(()=>{returnreactive<any>([{title:proxy.$t('device.pm.table.index'),dataIndex:'index',width:50,slotName:'indexsort',ellipsis:true,......
  • Object.defineProperty(obj,key,val)不可以监听数组变化,需要做特殊处理,所以Vue3.0使用
    关于Vue双向数据绑定说法错误的是()AVue实现双向数据绑定是采用数据劫持和发布者-订阅者模式BObject.defineProperty(obj,key,val)可以监听数组变化,不需要做特殊处理CVue2.0数据劫持是利用ES5的Object.defineProperty(obj,key,val)方法来劫持每个属性的getter和setterD......
  • 通过PowerShellPlus示例脚本学习Powershell
    ##=====================================================================##Title:DisconnectVI-Server##Description:DisconnectsfromaVIserver##Author:Idera##Date:9/11/2008##Input:-VIserver:VirtualInfrastructu......
  • 关于 Gdiplus api 调用的bug解决以及注意事项
    1.加入空间命,以识别这是Gdiplus的类与函数2.调用前需调用   Gdiplus::GdiplusStartupInputgsi;ULONG_PTRpToken;Gdiplus::Statuss=Gdiplus::GdiplusStartup(&pToken,&gsi,NULL);用完Gdiplus函数后调用Gdiplus::GdiplusShutdown(pToken);如果不调用,各个Gdiplus的类将......
  • vue3搭建
    一、Vue3介绍://创建一个Vue实例constapp=Vue.createApp({data(){return{message:'HelloVue!'}}})app.mount('#app')二、安装Vue3:npminstall-g@vue/cli#或者yarnglobaladd@vue/clivuecreatemy-project三、开始开发:<te......