Live2d Test Env

vue小知识~实现父子组件双向数据绑定

vue的数据是单向数据流动,在子组件中是不可以修改父组件的数据的,但是还是可以通过其他方式间接修改父组件的数据。

核心思想:数据在哪个组件,就在哪个组件修改。

1,方式一:通过向子组件传递方法

这个方式主要是在父组件内定义一个改变父组件数据的方法,然后将方法转入大子组件内。由于vue数据是单向流动的,父组件的数据只能通过父组件直接修改,而子组件只能间接修改,子组件间接修改的方式就是获取到父组件传递过来的方法,向该方法传入一个值以修改父组件的数据。

代码流程如下:

父组件:

<template>
    <div id="app">
        <div>{{ numbers }}</div>
        <boy :changNumber="changNumber"></boy>
    </div>
</template>
<script>
import boy from './components/boy.vue';
export default {
    components: {
        boy
    },
    data() {
        return {
            numbers: 0
        };
    },
    methods: {
        changNumber(value) {
            this.numbers = value;
        }
    }
};
</script>

<style>
</style>

这里我们需要修改的数据是numbers,在父组件定义一个修改该组件的方法changNumber(参数就需要在子组件内传入),将这个方法传入子组件。

<boy :changNumber="changNumber"></boy>

子组件:

<template>
    <div class="checked-box">
        <input v-model="num" />
        <button @click="change">改变</button>
    </div>
</template>
<script>
export default {
    props: ['changNumber'],
    data() {
        return {
            num: 1
        };
    },
    methods: {
        change() {
            this.changNumber(this.num);
        }
    }
};
</script>
<style scoped></style>

子组件首先使用props接收父组件转过来的方法:

 props: ['changNumber'],

什么了这个方式之后,相对于在该组件的数据中以及存在changNumber方法的索引,此时相当于在子组件的data中存在changNumber这个方法变量(引用),所以取值得时候需要使用this来取。

随后在子组件内定义一个方法来实现间接改变父组件内的数据。

2,方式二,使用$emit来触发绑定在子组件的方法。

该方式主要是在父组件引入组件时,在引入的组件标签上绑定一个方法,这时子组件的$emit实例上就会有该方法,可用在子组件中使用$emit触发绑定在它的方法上,来实现修改父组件的数据。值得注意的是,在子组件标签上需要绑定被修改的变量,将这个变量传入子组件内并接收。

代码:父组件

<template>
    <div id="app">
        <div>{{ numbers }}</div>
        <boy :nums="numbers" @changNumber="changNumber"></boy>
    </div>
</template>
<script>
import boy from './components/boy.vue';
export default {
    components: {
        boy
    },
    data() {
        return {
            numbers: 0
        };
    },
    methods: {
        changNumber(value) {
            this.numbers = value;
        }
    }
};
</script>
<style></style>

 子组件:

<template>
    <div class="checked-box">
        <input v-model="num" />
        <button @click="change">改变</button>
    </div>
</template>
<script>
export default {
    props: ['nums'],
    data() {
        return {
            num: 1
        };
    },
    methods: {
        change() {
            this.$emit('changNumber', this.num);
        }
    }
};
</script>
<style scoped></style>

运行结果:

这里可能会有人不了解,为什么子组件还需要接收父组件的数据而不是接收绑定的方法。

这里要注意的是,子组件标签已经绑定了方法,在它的实例上已经存在了,只需要通过$emit来触发该方法执行就可以了,但是需要传入父组件中需要修改的数据,这是需要通知子组件的的方法,要修改的是哪个数据。

this.$emit('changNumber', this.num);

相当于:

 
this.$emit(
    changNumber(value) {
    this.numbers = value;
    }, 
this.num
);

如果不传入父组件的数据numbers ,子组件将会报undefined的错。

以上代码中。父组件可以简写为:

<template>
    <div id="app">
        <div>{{ numbers }}</div>
        <boy :nums="numbers" @changNumber="changNumber=>thischangNumber=changNumber"></boy>
    </div>
</template>
<script>
import boy from './components/boy.vue';
export default {
    components: {
        boy
    },
    data() {
        return {
            numbers: 0
        };
    },
    methods: {
    }
};
</script>
<style></style>

3,方式三,使用v-model实现父子组件双向数据绑定。

还记得方式而中的这段吗?

 <boy :nums="numbers" @changNumber="changNumber=>thischangNumber=changNumber">

我们给标签绑定一个方法和传入一个参数,就可以实现父子组件双向数据绑定了,如果这个标签是一个html标签呢?

啊!

这个是不是和v-model实现的功能类似?

其实,这个就是v-model的实现原理,我们在一个标签使用v-model的时候,渲染过程中会把v-model渲染成名为:value和@input。

<boy :value="numbers" @input="changNumber=>thischangNumber=changNumber"></boy>

等价于

<boy v-model="numbers"></boy>

所以就清晰了。

父组件:

<template>
    <div id="app">
        <div>{{ numbers }}</div>
        <boy v-model="numbers"></boy>
    </div>
</template>
<script>
import boy from './components/boy.vue';
export default {
    components: {
        boy
    },
    data() {
        return {
            numbers: 0
        };
    }
};
</script>
<style></style>

子组件:

<template>
    <div class="checked-box">
        <input v-model="num" />
        <button @click="change">改变</button>
    </div>
</template>

<script>
export default {
    props: ['value'],
    data() {
        return {
            num: 1
        };
    },
    methods: {
        change() {
            this.$emit('input', this.num);
        }
    }
};
</script>
<style scoped></style>

效果图:

需要注意的是,子组件中的props接收的名称不一定是叫value,$emit触发的方法必须是input(不会报错,但是数据不会改变)

如下:

子组件:

<template>
    <div class="checked-box">
        <input v-model="num" />
        <button @click="change">改变</button>
    </div>
</template>

<script>
export default {
    props: ['shdfnf'],
    data() {
        return {
            num: 1
        };
    },
    methods: {
        change() {
            this.$emit('input', this.num);
        }
    }
};
</script>
<style scoped></style>

效果为:

说明

 props: ['shdfnf'],

可以接收任意变量名。而改变input名呢?

子组件:

<template>
    <div class="checked-box">
        <input v-model="num" />
        <button @click="change">改变</button>
    </div>
</template>

<script>
export default {
    props: ['value'],
    data() {
        return {
            num: 1
        };
    },
    methods: {
        change() {
            this.$emit('input1234', this.num);
        }
    }
};
</script>
<style scoped></style>

效果图:

它既不报错,怎么点击按钮,值也无法跟着变化。

写了这么多,讲的这么细,难道不知道您点个赞吗?

posted @ 2021-07-01 23:15  waywardcode  阅读(471)  评论(0)    收藏  举报