Vue自定义事件

182 阅读2分钟

vue自定义事件

Vue的组件通信一直都是一道常见面试题,今天面试被问一道十分简单的题目。

题目:父组件给子组件传递一个值(数据),如何做到子组件修改后,父组件也同步修改?

可能一般人,都会想到用组件的事件触发来做也就是this.$emit('事件名',参数)然后父组件监听v-on:事件名然后让父组件的监听处理函数来做值的修改

这样虽然可以做,但是如果我又很多个子组件,那不要重复写事件触发,然后监听的代码?很明显太累了。其实我自己也忘了还有啥方式。(文档有更新忘记了)

不过你可以使用$parent直接操作父组件属性,不过这个非常不推荐,或者你传递一个操作父组件属性的函数,交给子组件来调用。(都不好)

正确方式其实在官网有提到:(自定义事件)cn.vuejs.org/v2/guide/co…

使用场景:www.cnblogs.com/wind-lanyan…

img

个人测试代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>01-自定义事件</title>
    <script src="../js/vue.js"></script>
</head>
<div id="app">
    <base-checkbox v-model="lovingVue"></base-checkbox>
    <div>lovingVue:{{lovingVue}}</div>
</div>

<body>

</body>
<script>
    Vue.component('base-checkbox', {
        model: {
            prop: 'checked',
            event: 'change'
        },
        props: {
            checked: Boolean
        },
        template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
    })

    var app = new Vue({
        el: '#app',
        data() {
            return {
                lovingVue: false
            }
        },
    })

</script>

</html>

.sync 修饰符

深入理解vue 修饰符sync:www.jianshu.com/p/6b062af8c…

2.3.0+ 新增

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件两侧都没有明显的变更来源。

这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之。举个例子,在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:

this.$emit('update:title', newTitle)

然后父组件可以监听那个事件并根据需要更新一个本地的数据 property。例如:

<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>

为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符:

<text-document v-bind:title.sync="doc.title"></text-document>

原来写法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>02-sync修饰符</title>
    <script src="../js/vue.js"></script>
</head>

<body>
    <div id="app">
        父组件
        <hr>
        <text-document v-bind:title="doc.title" v-on:update:title="doc.title = $event"></text-document>
        {{doc.title}}
    </div>

    <template id="aaa">
        <button @click="click">我是子组件</button>
    </template>
</body>
<script>

    Vue.component('text-document', {
        template: '#aaa',
        methods: {
            click() {
                this.$emit('update:title', '新标题')
            }
        },
    })

    var app = new Vue({
        el: '#app',
        data() {
            return {
                doc: {
                    title: '你好'
                }
            }
        },

    })
</script>

</html>

使用sync简化后

就是把指令做了简化

`<text-document v-bind:title.sync="doc.title"></text-document>`

这帮我做了什么?

答案:很明显,这样帮助我们,好多时候子组件需要主动修改父组件的值,或者绑定。

这时候再用单纯的父子组件通信显得不合适,最好是让父组件不在过多的自己去操作数据,不然就不像一个本分的组件了,这时候就需要v-model(自定义组件的v-model)。

vue 修饰符sync的功能是:当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定。如果我们不用.sync,我们想做上面的那个弹窗功能,我们也可以props传初始值,然后事件监听,实现起来也不算复杂。

完整样例代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>02-sync修饰符</title>
    <script src="../js/vue.js"></script>
</head>

<body>
    <div id="app">
        父组件
        <hr>
        <!-- <text-document v-bind:title="doc.title" v-on:update:title="doc.title = $event"></text-document> -->
        <!-- 简化后 -->
        <text-document v-bind:title.sync="doc.title"></text-document>
        {{doc.title}}
        {{doc}}
    </div>

    <template id="aaa">
        <button @click="click">我是子组件</button>
        <!-- <button>我是子组件</button> -->
    </template>
</body>
<script>

    Vue.component('text-document', {
        template: '#aaa',
        methods: {
            click() {
                this.$emit('update:title', '新标题')
            }
        },
    })

    var app = new Vue({
        el: '#app',
        data() {
            return {
                doc: {
                    title: '你好'
                }
            }
        },

    })
</script>

</html>

这篇写的针对上述问题做了组件通信的分类与区别,这就是上面那道题目最棒的解答了:www.cnblogs.com/penghuwan/p…

image-20211028211652624

image-20211028211707585

image-20211028211900749

v-model实现下拉框原理

在Vue中 使用select下拉框 主要靠的是 v-model 来绑定选项 option 的 value 值。

常见使用方式:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>03-v-model绑定下拉列表</title>
    <script src="../js/vue.js"></script>
</head>

<body>
    <div id="app">
        <select name="status" id="status" v-model="selected">
            <!-- <option value="">请选择</option>
            <option value="1">未处理</option>
            <option value="2">处理中</option>
            <option value="3">处理完成</option> -->
            <option :value="item.statusId" v-for="(item,index) in statusArr">{{item.statusVal}}</option>
        </select>
    </div>
</body>
<script>
    var app = new Vue({
        el: '#app',
        data() {
            return {
                //默认选中项的value值是什么  就给绑定的属性什么值  这里默认选中项请选择的value值是空  我们就给绑定的属性 select 一个空值
                selected: '',
                statusArr: [
                    {
                        statusId: '0',
                        statusVal: '请选择'
                    },
                    {
                        statusId: '1',
                        statusVal: '未处理'
                    },
                    {
                        statusId: '2',
                        statusVal: '处理中'
                    },
                    {
                        statusId: '3',
                        statusVal: '处理完成'
                    },
                ],
            }
        },
        created() {
            // 在组件创建之后,把默认选中项的value值赋给绑定的属性
            //如果没有这句代码,select中初始化会是空白的,默认选中就无法实现
            this.selected = this.statusArr[0].statusId
        },

    })
</script>

</html>

原理剖析:blog.csdn.net/qq_27460969…