如何自定义组件的v-model

工作中经常会涉及到父子组件数据更新和页面相应数据样式改变的问题。

通俗点来说,就是涉及到公共组件的可以抽离出来作为子组件,如果父组件中与子组件相关的数据改变,子组件中的数据也会改变,如果子组件的数据改变,则需要做一定的处理才能改变父组件中的相关数据。

处理方式:考虑使用 自定义组件的v-model(vue2 中方式)

父组件

<search-tab :list="list" v-model="active" />
...
export default {
    data(){
        return {
            list: [],
            active: 0
        }
    }
}
...

子组件 SearchTab

<el-tabs :value="active" @tab-click="handleClick">
  <el-tab-pane v-for="(item, key) in list" :key="key" :label="item.name" :name="item.value"></el-tab-pane>
</el-tabs>
...
export default {
  name: 'SearchTab',
  props: {
    active: {
      type: Number,
      default: 0
    },
    list: Array
  },
  model: {
    prop: 'active',
    event: 'changeActive'
  },
  methods: {
    handleClick(val) {
      this.$emit('changeActive', val.name)
    }
  }
}
...

这种方式如果涉及到选中组件的选中样式问题,能够响应式

而如果我们不用自定义组件的 v-model 方法,而是普通的父子组件通信,子组件改变父组件的值通过子组件中声明的另一个来作为中间变量,监听中间变量的值来改变父组件中的值,这种方式虽然能改变值,但是选中样式却不能及时更新。

子组件示例

<el-tabs :value="active" @tab-click="handleClick">
  <el-tab-pane v-for="(item, key) in list" :key="key" :label="item.name" :name="item.value"></el-tab-pane>
</el-tabs>
...
export default {
  name: 'SearchTab',
  props: {
    name: String,
    activeTab: {
      type: String,
      default: '0'
    },
    list: Array
  },
  data() {
    return {
      active: this.activeTab
    }
  },
  watch: {
    active() {
      this.activeTab = this.active
    }
  },
  methods: {
    handleClick(val) {
      console.log(val)
    }
  }
}
...

vue2与vue3在自定义组件v-model的区别

在vue开发中,通常会对一个自定义的组件进行封装,并实现v-model双向绑定功能

在vue2中,通常这样实现

父组件

<template>
  <Child v-model="number"></Child>    
</template>
<script>
  export default {
    data() {
      return {
        number: 0
      }
    },
    components: {
      Child: () => import("./Child.vue")
    }
  }
</script>

子组件

<template>
  <button @click="handleClick">{{ value }}</button>
</template>
<script>
  export default {
    props: {
      value: Number
    },
    methods: {
      handleClick() {
        // 通过emit一个input事件出去,实现 v-model
        this.$emit('input', this.value + 1)
      }
    }
  }
</script>

在vue3中,通过这样实现

父组件

<template>
  <Child v-model="number"></Child>    
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
  setup() {
    const number = ref(0);
    return {
      number
    };
  },
});
</script>

子组件

<template>
  <button @click="handleClick">{{ value }}</button>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
  props: {
    // 更换成了 modelValue
    modelValue: Number
  },
  setup(props, { emit }) {
    // 关闭弹出层
    const handleClick = () => emit('update:modelValue', props.modelValue + 1);
    return { handleClick };
  },
});
</script>

以上为个人经验,希望能给大家一个参考,也希望大家多多支持阿兔在线工具。

点赞(0)

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部