提示

本文主要讲解 Vue 中的组件自定义事件。@ermo

# 组件自定义事件

# 自定义事件

父组件像子组件传递数据使用 Prop,子组件向父组件传递数据使用自定义事件。

<!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>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14"></script>
</head>
<body>
    <div id="app">
        <p>{{ total }}</p>
        <button-counter v-on:increment="incrementTotal"></button-counter>
    </div>
    <script>
        Vue.component('button-counter', {
            template: '<button v-on:click=incrementHandler>点我 {{ counter }}</button>',
            data: function() {
                return {
                    counter: 0
                }
            },
            methods: {
                incrementHandler: function() {
                    this.counter += 1;
                    this.$emit('increment');
                }
            }
        });
        var vm = new Vue({
            el: '#app',
            data: {
                total: 0
            },
            methods: {
                incrementTotal: function() {
                    this.total += 1;
                }
            }
        });
    </script>
</body>
</html>

可以参考另一个示例:

<!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>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14"></script>
</head>

<body>
    <div id="blog-post-events-demo">
        <div v-bind:style="{fontSize: postFontSize + 'em'}">
            <blog-post 
                v-for="post in posts" 
                v-bind:key="post.id" 
                v-bind:post="post"
                v-on:add="addEm"
            >

            </blog-post>
        </div>
    </div>
    <script>
        Vue.component('blog-post', {
            props: ['post'],
            template:
                `
                <div class="blog-post">
                    <h3>{{post.title}}</h3>    
                    <button v-on:click="$emit('add')">
                        放大文字
                    </button>
                    <div v-html="post.content"></div>
                </div>
            `
        });
        new Vue({
            el: '#blog-post-events-demo',
            data: {
                posts: [
                    {id:1,title:'博文1',content:'<p>一段内容1</p>'},
                    {id:2,title:'博文2',content:'<p>一段内容2</p>'},
                    {id:1,title:'博文2',content:'<p>一段内容3</p>'},
                ],
                postFontSize: 1
            },
            methods: {
                addEm: function() {
                    this.postFontSize += 1;
                }
            }
        });
    </script>
</body>

</html>

# 使用事件抛出一个值

如果需要父组件抛出一个值,就需要 $emit 中的第二个参数。

在子组件 addEm 中的第一个参数就父组件抛出的值。

<!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>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14"></script>
</head>

<body>
    <div id="blog-post-events-demo">
        <div v-bind:style="{fontSize: postFontSize + 'em'}">
            <blog-post 
                v-for="post in posts" 
                v-bind:key="post.id" 
                v-bind:post="post"
                v-on:add="addEm"
            >

            </blog-post>
        </div>
    </div>
    <script>
        Vue.component('blog-post', {
            props: ['post'],
            template:
                `
                <div class="blog-post">
                    <h3>{{post.title}}</h3>  
                    <!-- 设置放大参数 -->
                    <button v-on:click="$emit('add', 0.1)">
                        放大文字
                    </button>
                    <div v-html="post.content"></div>
                </div>
            `
        });
        new Vue({
            el: '#blog-post-events-demo',
            data: {
                posts: [
                    {id:1,title:'博文1',content:'<p>一段内容1</p>'},
                    {id:2,title:'博文2',content:'<p>一段内容2</p>'},
                    {id:1,title:'博文2',content:'<p>一段内容3</p>'},
                ],
                postFontSize: 1
            },
            methods: {
                // 第一个参数就是父组件抛出的值
                addEm: function(addAmount) {
                    console.log(addAmount);
                    this.postFontSize += addAmount;
                }
            }
        });
    </script>
</body>

</html>

# 在组件中使用 v-model

v-on:input 表示监听用户输入事件。

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

上例等价于:

<input type="text" v-model="text">

参考完整示例:

<!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>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14"></script>
</head>
<body>
    <div id="app">
        <input type="text" v-bind:value="text"
        v-on:input="text = $event.target.value"
        >
        <p>输入的值: {{text}}</p>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                text: ''
            }
        });
    </script>
</body>
</html>

在组件上使用 v-model 是这样:

<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"
></custom-input>

为了让这个子组件正常工作,有2个必要条件:

  • value 属性绑定到叫 value 的 props 上
  • input 事件被触发时,将新的值通过自定义 input 事件抛出
<!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>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14"></script>
</head>

<body>
    <div id="app">
        <input-box v-model="num"></input-box>
        <p>输入值:{{num}}</p>
    </div>

    <script>
        Vue.component('input-box', {
            template: `
                <input
                v-bind:value="value" 
                v-on:input="$emit('input', $event.target.value)">
            `,
            props: ['value']
        })

        new Vue({
            el: '#app',
            data: {
                num: 100,
            }
        })
    </script>
</body>

</html>

v-model 默认传的是 value,不是 checked,像选择框和复选框这种元素在组件中使用时,就需要使用到 model 选项,指定当前的事件类型和传入的 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>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14"></script>
</head>
<body>
    <div id="app">
        <checked-box v-model="longValue"></checked-box>
        <div v-show="longValue">
            选中我就会显示
        </div>

    </div>

    <script>
        Vue.component('checked-box', {
            model: {
                prop: 'checked', // 指定属性值为 checked
                event: 'change' // 指定事件类型,change 事件
            },
            props: {
                checked: Boolean
            },
            template: `
                <p>选中:
                <input 
                    type="checkbox"
                    v-bind:checked="checked"
                    v-on:change="$emit('change', $event.target.checked)"
                >
                </p>
            `
        });
        new Vue({
            el: '#app',
            data: {
                longValue: false
            }
        });
    </script>
</body>
</html>
上次更新: 2/20/2023, 9:02:17 PM