提示
本文主要讲解 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>