父子组件的双向绑定 结合model 选项定制 prop 和 event

1,176 阅读1分钟

背景

vue中,数据是响应式单向,不是双向。v-model实现双向绑定,是对表单应用的一层单独封装,一般,由子组件单独维护一份数据,提交时传递出来。不能直接将父元素传递给子元素的属性挂在到子组件上面来双向绑定。

但有的业务场景,需要子组件和父组件的部分数据双向绑定;如果不想用vue-bus或vuex去添加状态监听,可以用model选项来实现双向数据传递。

用model的目的 是可以自由定制子组件和父组件的双向绑定功能,而不仅仅是局限在表单组件

注意 vue3的语法有变化 下面的demo是基于vue2实现

vue3的model模块 参考 t.csdn.cn/IWuJh

v-model的含义

一个语法糖。比如对input实现双向绑定

<input v-model="data">

实际上就是监听input事件 把值绑定给变量data

<input v-bind:value="data" v-on:input="data = $event.target.value">

v-model 默认把 value 用作 prop 、 input 用作 event。自定义组件,没有默认value和input事件,使用v-model不能实现双向绑定,需要按照显式的去声明定义这些东西。

model选项就派上用场了,在定义组件的时候,指定prop的值和监听的事件。

blog.csdn.net/Liu_Jun_Tao…

代码实现

子组件 定义绑定属性和回调

<template>
    <div class="bj">
        <van-radio-group v-model="uname" @change="updateVal" direction="horizontal">
            <van-radio name="1">样式1</van-radio>
            <van-radio name="2">样式2</van-radio>
            <van-radio name="3">样式3</van-radio>
        </van-radio-group>
    </div>
</template>


<script>
export default {
    name: "BaseBox",
    model: {
        prop: 'childName',//父组件v-model去绑定的变量 
        event: 'changeX'  // 随便命名事件,对应下面$emit即可。demo是在输入框输入值后,触发emit去通知父组件更新 
    },
    props: {
        uname: {
            type: String,
            default: '1'//会被父组件的绑定值给覆盖掉
        }
    },
    methods: {
        //val就是更新后的值 通知父组件更新
        updateVal(val) {
            window.console.log(val)
            this.$emit('changeX', val)
        }
    }
}
</script>

<style scoped>
.bj {
    margin-top: 10%;
}
</style>

父组件 绑定值被子组件修改后 更换样式

<template>
  <div class="homeView">
    <BaseBox v-model="name" value="some value"></BaseBox>
    <van-button class="btn" v-if="name == 1" type="primary" >父组件样式1</van-button>
    <van-button class="btn" v-if="name == 2" type="info" >父组件样式2</van-button>
    <van-button class="btn" v-if="name == 3" type="warning" >父组件样式3</van-button>
  </div>
</template>

<script>
//引入子组件
import BaseBox from './BaseBox'

export default {
  name: "HomeView",
  //注册子组件
  components: {
    BaseBox,
  },
  data() {
    return {
      //定义v-model属性初值
      name: '1'
    }
  },
  created() {
    this.$nextTick(() => {

    })
  },
  methods: {

  }

}
</script>

<style scoped>
.homeView {
  width: 80%;
  height: auto;
  margin: auto;
}
.btn{
  margin-top: 10%;
}
</style>

效果

微信图片_20220408005413.png

微信图片_20220408005619.png

微信图片_20220408005728.png

总结

model模块 把在表单组件上的双向绑定实现,扩展到了一个单独的子组件中。避免了子直接更改父传递属性的导致的报错、也使封装组件定义个性化功能变得更简单。

在代码层面,这种父子组件的双向通信,不需要用全局变量、或私有变量再赋值等其他方式实现;直接的双向绑定,提高了代码可维护性

仓库地址 基于vant-demo/vue2 github.com/xuhongg/def…