两种方法实现 vue3 父子组件双向绑定 (踩了大坑)呜呜呜

3,171 阅读2分钟

背景

  • 因为要封装一个表单嘛 然后就要实现父子组件的双向绑定 使得子组件的表单值也能传递回给父组件 当时这里是踩了挺多坑的 呜呜呜呜 太难了
  • 话不多说 直接来吧

基础知识

  • 双向绑定 那么当然想到的就是 v-model 啊 那么有必要对这个知识点有一定的了解才好去使用
  • 那么必然是上官网啊
  • 也可以看我总结的 笔记 有一些官网 写的没那么详细 直达

vue3 的使用

  • 这里当时踩了一个很大的坑

    • 就是动态传值不能使用 基本数据类型 要使用对象才行

    • 当时测试的时候怎么都不成功 一直报传递的值时只读的 不能修改

    • 代码

      • // 父组件
        <page-search :father-data="test" @update:father-data="test = $event" />
        <el-button @click="getChildren">获取子组件 input</el-button>
        // 定义了 几倍呢数据类型 字符串
        let test = ref('123')
        ​
        // 获取子组件值得测试按钮
        const getChildren = function (e: any) {
          console.log(test.value.str, 'user', e)
          test.value.str = ''
        }
        ​
        // 子组件
        <input v-model="props.fatherData" />
        ​
        const props = defineProps({
          fatherData: {
            type: String,
            default: '',
          },
        })
        ​
        const emit = defineEmits([
          'update: fatherData',
        ])
        ​
        watchEffect(() => {
          emit('update: fatherData', props.fatherData)
        })
        // 第二种写法
        <input :value="props.fatherData" @input="changeInput($event)" />
        ​
        const changeInput = function (e: any) {
          emit('update: fatherData', e.traget.value)
        }
        
      • 这么当时怎么都无法把值传回给父组件 各种不同写法写了好几天 哭了呜呜呜
    • 然后我就 把数据改为 object 进行传值了

      • // 父组件 两种写法等效
        <page-search :father-data="test" @update:father-data="test = $event"
        <page-search v-model:father-object="test" />
        <el-button @click="getChildren">获取子组件 input</el-button>let test = ref({
          str: '12',
        })
        ​
        const getChildren = function (e: any) {
          console.log(test.value.str, 'user', e)
          test.value.str = ''
        }
        ​
        // 子组件
        第一种写法
        <input v-model="props.fatherObject.str" /> // eslint 不让这么写 下面贴出链接
        const props = defineProps({
          fatherObject: {
            type: Object,
            default: () => {
              // eslint 语法规范 传空值不行 要加一行注释
            },
          },
        })
        ​
        const emit = defineEmits([
          'update: fatherObject',
        ])
        // 监听 依赖发生变化 更新
        watchEffect(() => {
          emit('update: fatherObject', props.fatherObject)
        })
        ​
        // 第二种写法 因为开启了 eslint-plugin-vue 上面不让那么写 改成下面这种写法 然后还是不让 嘻嘻嘻 真阴间 我就把它设置为不理睬这种 eslint 了 
        <input :value="props.fatherObject.str" @input="changeInput($event)" />
        ​
        const changeInput = function (e: any) {
          props.fatherObject.str = e.target.value // eslint 这行不让
          emit('update: fatherObject', props.fatherObject)
        }
        
      • eslint-plugin-vue

最后来说一下思路

第一种

  • 父组件使用 v-model 以自定义参数得形式 传参给子元素 参数是 fatherData

  • 子组件接收到参数 使用 v-model 双向绑定到 input 框

  • 要使用 emits 要传递给父组件

  • 但是因为是双向绑定 所以 这里使用 watch 监听数据变化执行传递得函数

    • watch watchEffect computed 不太懂可以看我另一篇文章 直达

第二种

  • 因为 第一种是使用双向绑定语法糖 v-model 所以要使用 侦听器

    • 但是 eslint 不推荐 v-model 这种写法 所以改成第二种
  • 第二种 相当于自己实现了 v-model 所以不需要 侦听

    • 本来第二种是可以的 但是因为我是用得是对象得形式

    • changeInput 得到的是 e.target.value 字符串

    • 而 emit('update: fatherObject', props.fatherObject) 绑定得是对象

    • 所以要 props.fatherObject.str = e.target.value 赋值才能双向绑定成功

      • 然后这条语句 对陈传过来得 props 直接赋值 eslint 不让
    • 啊啊啊啊啊啊 死循环 不使用 对象我连值都改不了 那也没办法吧 只能这样了