当前位置: 首页 > 知识库问答 >
问题:

前端 - 请教一下非原生组件的v-model传值问题?

东方河
2023-06-06
<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修改值呢?

共有3个答案

祁飞飙
2023-06-06
  1. 组件里很忌讳直接修改公共数据,基本上是万恶之源
  2. 所以第二种做法就不好
  3. vue 的优势不应该这么理解,Vue 的优势主要在于:只要你改了数据,就能改变视图。但是什么时候、该怎么改数据,仍然是我们要深思熟虑的。

故而这里通常应该是:

  • props.modelValue 克隆到本地,成为 localValue
  • 日常操作 localValue
  • 确认后,再提交给父组件
谢英耀
2023-06-06

虽然你在做双向绑定,但是最好还是遵循单向数据流,数据修改后通知父组件这个数据修改了,子组件不要去直接改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)
}
苏乐
2023-06-06

emits('update:modelValue', data);的意思是触发update:modelValue事件通知父组件更新modelValue的值。所以按照同样的思路,我们可以在子组件中仅触发删除按钮的点击事件,在父组件中处理删除逻辑。

function handleDelete(index: number) {
  emits('delete', index);
}

在实际业务中,数组内容的修改、删除、添加一般也会涉及到其他逻辑,比如请求接口等。所以这样看来,子组件仅负责数据的展示,父组件负责相关的数据修改、业务功能等,也是合理的。

 类似资料:
  • 大家好,组件 B.jsx 的代码如下,大概意思是它里面有一个按钮,可以打开菜单,也可以关闭菜单,切换菜单的打开和关闭 组件 A.jsx 是组件 B 的父组件,即 B 组件被 A 组件引用,部分代码如下 这些代码实现了当 B 组件中的菜单展开后,点击其父组件 A 中页面任何地方,都能关闭该菜单。但现在遇到的问题是总是有错误警告 Warning: Cannot update a component (

  • v-for循环组件,组件key都是同一个固定值,组件还会被重新创建吗 v-for循环组件,内部组件每次的生命周期都是从beforeCreated开始的吗

  • 大佬们,这种边框都有哪些方法实现啊 。。。。

  • 本文向大家介绍巧妙运用v-model实现父子组件传值的方法示例,包括了巧妙运用v-model实现父子组件传值的方法示例的使用技巧和注意事项,需要的朋友参考一下 v-model介绍 熟悉Vue的小伙伴们都知道 v-model 是Vue的一个很大的特色,可以实现双向数据绑定。但本质上呢,它不过是语法糖,它负责监听用户的输入事件以更新数据。 以下摘取自Vue官方文档 v-model 在内部使用不同的属性

  • https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_flow_lay... 上面的文章写到: 1.常规流中:块级盒子是在块格式上下文(BFC)中的,而内联盒子是在内联格式上下文中的(IFC); 2.块格式上下文(BFC)中,盒子是垂直排列的; 3.内联格式上下文(IFC)中,盒子水平排列; 那么问题来了: 例子:通过display:flow-r