请教一下非原生组件的v-model传值问题?
<template> <ElTag
v-for="(item,i) in modelValue"
:key="item"
closable
@close="handleDelete(i)"
>
{{ item }}
</ElTag>
</template>
<script setup lang="ts">
import { ElInput, ElTag } from "element-plus";
const props = withDefaults(defineProps<{
modelValue?: string[];
}>(),{
modelValue: () => [],
});
const emits = defineEmits(["update:modelValue"]);
// 通过索引删除元素
function handleDelete(index: number) {
const data = props.modelValue.slice();
data.splice(index, 1);
emits('update:modelValue', data);
}
</script>
在上面的代码中,handlerDelete
是将props.modelValue
的原数组通过slice
进行浅克隆,最后将浅克隆的值传回父组件,通过父组件修改原值,之所以使用这种传值方式,是因为我采用了react
的更新机制。
然而由于vue
本身是响应式数据,因此直接修改props.modelValue
也能实现:
function handleDelete(index: number) { // 这里甚至都不用emit事件
props.modelValue.splice(index, 1);
}
问题
因此这引发了我的一个思考:
- 第二种直接修改props的方法虽然方便,但是带来了许多的隐患,组件内部随意更改外部值,会导致数据流紊乱,会导致许多的后期问题,因此不可取。
- 但是第一种浅克隆的方式又丢掉了
vue
响应式的优势。
所以:我想问下有没有更优雅的方式实现v-model
修改值呢?
回答:
emits('update:modelValue', data);
的意思是触发update:modelValue
事件通知父组件更新modelValue
的值。所以按照同样的思路,我们可以在子组件中仅触发删除按钮的点击事件,在父组件中处理删除逻辑。
function handleDelete(index: number) { emits('delete', index);
}
在实际业务中,数组内容的修改、删除、添加一般也会涉及到其他逻辑,比如请求接口等。所以这样看来,子组件仅负责数据的展示,父组件负责相关的数据修改、业务功能等,也是合理的。
回答:
虽然你在做双向绑定,但是最好还是遵循单向数据流,数据修改后通知父组件这个数据修改了,子组件不要去直接改props.modelValue
// 通过索引删除元素function handleDelete(index: number) {
const data = props.modelValue.slice();
data.splice(index, 1);
emits('update:modelValue', data);
}
你这一段代码生效纯粹是因为数组是引用类型,传入之后 props.modelValue 和 data 都是引用地址而已,所以你改了 data,父组件的数据也改了
一般来说数据的双向绑定,会先将元数据深拷贝保存
const value = ref([])watch(
() => props.modelValue,
(newVal) => {
value.value = cloneDeep(newValue)
}
)
function handleDelete(index: number) {
value.value.splice(index, 1)
emits('update:modelValue', value.value)
}
回答:
- 组件里很忌讳直接修改公共数据,基本上是万恶之源
- 所以第二种做法就不好
- vue 的优势不应该这么理解,Vue 的优势主要在于:只要你改了数据,就能改变视图。但是什么时候、该怎么改数据,仍然是我们要深思熟虑的。
故而这里通常应该是:
- 将
props.modelValue
克隆到本地,成为localValue
- 日常操作
localValue
- 确认后,再提交给父组件
以上是 请教一下非原生组件的v-model传值问题? 的全部内容, 来源链接: utcz.com/p/934409.html