vue学习笔记(八)组件校验&通信

时间:2023-03-08 15:39:46
vue学习笔记(八)组件校验&通信

前言

在上一章博客的内容中vue学习笔记(七)组件我们初步的认识了组件,并学会了如何定义局部组件和全局组件,上一篇内容仅仅只是对组件一个简单的入门,并没有深入的了解组件当中的其它机制,本篇博客将会带大家深入了解组件的其它知识,组件的校验,组件的通信等等。

本章目标

  • 学会组件简单的校验
  • 学会父组件向子组件传递数据
  • 学会子组件向父组件传递数据

父组件向子组件传递数据

父组件向子组件传递数据实现的方式特别简单,只用使用props进行数据传递就可以了。

语法:props['属性1',‘属性2’,...]

我找了一张图给大家参考一下

vue学习笔记(八)组件校验&通信

在 Vue.js 中,父子组件的关系可以总结为 props down, events up 。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息

(1)简单的父组件向子组件传递信息

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>父组件向子组件传递信息</title>
</head>
<body>
<div id="app">
<my-content :title='title' :content='content'></my-content>
</div>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
let vm=new Vue({
el:'#app',
data:{
title:'标题',
content:'内容'
},
methods:{ },
computed:{ },
components:{
'myContent':{
props:['title','content'],
template:`<div>
<h1>{{title}}</h1>
<p>{{content}}</p>
</div>`
}
} }) </script>
</body>
</html>

结果:显示标题和内容,最简单的父组件向子组件传递信息我们就实现了,但是里面还有其它的小知识点我们没有讲解到,而且后期开发都是使用vue-cli来实现父组件向子组件传递数据的,所以这个知识点下一篇博客会讲解到,不会搭建vue-cli项目的朋友可以参考这篇博客使用webstorm搭建vue-cli项目后续的许多文章都会使用vue-cli中的组件进行讲解,而不是通过简单的引入vue.js文件了,所以强烈推荐大家一定要学会搭建vue-cli项目。

总结:父组件向子组件传递数据使用props

(2)props传递整个对象

假设父组件中的对象含有多个属性,我们每一个属性都需要进行传递,那么是不是需要绑定每一个属性呢?

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>props传递多个属性</title>
</head>
<body>
<div id="app">
<my-content :title="attr.title" :content1="attr.content1" :content2="attr.content2"></my-content>
</div>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
let vm=new Vue({
el:'#app',
data:{
attr:{
title:'新闻主题',
content1:'新闻内容1',
content2:'新闻内容2',
}
},
methods:{ },
computed:{ },
components:{
'myContent':{
props:['title','content1','content2'],
template:'<div><h4>{{title}}</h4><span>{{content1}}</span><span>{{content2}}</span></div>'
}
} }) </script>
</body>
</html>

现在这个实例所表现出来的就是一个对象里面有很多个属性,现在仅仅只有三个属性而已,我们的父组件绑定属性的时候就需要绑定三个属性,如果是100个或者1000个那么绑定组件的那个标签不是很长吗?和同事一起开发的话,你的同事看到那么长的代码肯定会怀疑人生的,所以为了解决这个问题我们将代码改写下面那样。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>props传递多个属性</title>
</head>
<body>
<div id="app">
<my-content v-bind="attr"></my-content>
</div>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
let vm=new Vue({
el:'#app',
data:{
attr:{
title:'新闻主题',
content1:'新闻内容1',
content2:'新闻内容2',
}
},
methods:{ },
computed:{ },
components:{
'myContent':{
props:['title','content1','content2'],
template:'<div><h4>{{title}}</h4><span>{{content1}}</span><span>{{content2}}</span></div>'
}
} }) </script>
</body>
</html>

在这里我们使用v-bind将整个对象打包传递过去,这样一来就大大的减少了代码的冗余度了,那么你的同事肯定夸你小伙子不错,你就等着被领导表扬吧!(自己脑补出来的)

data必须是函数

为什么说data必须是一个函数呢?这个知识点在上一篇博客中没有提及到,现在的话我们来讨论一下,这个案例就足够说明了。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>data必须是函数</title>
</head>
<body>
<div id="app">
<my-content></my-content>
</div>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
Vue.component('myContent',{
data:{
msg:'hello world'
},
template:'<span>{{msg}}</span>',
});
let vm=new Vue({
el:'#app'
})
</script>
</body>
</html>

结果:

vue学习笔记(八)组件校验&通信

控制台显示vue.js给出的警告也是提出data必须是一个函数,好的既然规定data必须是一个函数,那我们就按照它说的来做。看看结果如何

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>data必须是函数</title>
</head>
<body>
<div id="app">
<my-content></my-content>
<my-content></my-content>
<my-content></my-content>
</div>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var data={
count:1
}
Vue.component('myContent',{
data:function(){
return data;
},
template:'<button @click="count+=1">{{count}}</button>',
});
let vm=new Vue({
el:'#app'
})
</script>
</body>
</html>

vue学习笔记(八)组件校验&通信

vue学习笔记(八)组件校验&通信

现在的话,我们的data是一个函数,但是解决一个问题的同时新的问题又出现了,点击任意一个按钮的时候发现其它按钮的值都会发生改变,这是因为我们引用了同一个对象,我们知道对象是引用传递的,所以为了改变这一种情况,我们让每个组件内部都有自己的状态而不会去干涉其它组件。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>data必须是函数</title>
</head>
<body>
<div id="app">
<my-content></my-content>
<my-content></my-content>
<my-content></my-content>
</div>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
Vue.component('myContent',{
data(){
return{
count:1
}
},
template:'<button @click="count+=1">{{count}}</button>',
});
let vm=new Vue({
el:'#app'
})
</script>
</body>
</html>

结果:

vue学习笔记(八)组件校验&通信

我们在data中使用return返回新的对象,这样一来每一个组件都有自己本身的状态了,从而不会去影响其它的组件。

组件的校验

组件的校验从字面上看就是对父组件向子组件传递的信息中,子组件对父组件传递过来的信息进行验证,一方面是为了数据的安全性,另一方面给他人使用的时候也可以限制他人传递过来的数据的验证。

Vue.component('example', {
props: {
// 基础类型检测 (`null` 意思是任何类型都可以)
propA: Number,
// 多种类型
propB: [String, Number],
// 必传且是字符串
propC: {
type: String,
required: true
},
// 数字,有默认值
propD: {
type: Number,
default: 100
},
// 数组/对象的默认值应当由一个工厂函数返回
propE: {
type: Object,
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
return value > 10
}
}
}
})

type可选:

  • Sting
  • Number
  • Boolean
  • Function
  • Object
  • Array

(1)示例一

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>组件的校验示例一</title>
</head>
<body>
<div id="app">
<my-content :name="name" :age="age" :sex="sex"></my-content>
</div>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
let vm=new Vue({
el:'#app',
data:{
name:'小明',
age:18,
sex:'男'
},
methods:{ },
computed:{ },
components:{
'myContent':{
props:{
name:{
type:Number,
required:true,
},
age:{
type:Number,
default:20,
},
sex:{
type:String,
default:'女'
}
},
template:'<div><span>{{name}}</span><span>{{age}}</span><span>{{sex}}</span></div>'
}
} }) </script>
</body>
</html>

结果:

vue学习笔记(八)组件校验&通信

我们对name做了验证规定,name的类型必须是Number,而传递过来的却是String,所以vue.js给出了警告,对name属性也要求是必须传递的参数,required:true,对sex给定默认值,当我们没有传递sex的时候,子组件中的sex默认值是女的,所以有了组件的这一校验,大大提高的数据的安全性。

(2)示例二

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>组件的校验示例二</title>
</head>
<body>
<div id="app">
<my-content name="喜马拉雅" :size="8848" :is-boy="false" address="中国*"></my-content>
</div>
<script type="text/template" id="template1">
<div>姓名:{{name}}身高:{{size}}是否是男生:{{isBoy}}位置:{{address}}重量:{{weight.ton}}亿吨</div>
</script>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
Vue.component('myContent',{
template:'#template1',
props:{
name:{
type:String, //类型
required:true, //规定必填
},
size:Number, //规定整形
isBoy:Boolean, //规定布尔值
age:[Number,String],// 多种类型
address:{
type:String,
default:'中国',
validator:function(value){
return value.indexOf('中国')>=0
}
},
weight:{
type:Object,
default:function(){
return {ton:999999999}
}
},
} })
let vm=new Vue({
el:'#app',
data:{ },
methods:{ },
computed:{ } }) </script>
</body>
</html>

结果:

vue学习笔记(八)组件校验&通信

子组件向父组件传递数据

我们知道,父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,应该怎样做?那就是自定义事件!每个 Vue 实例都实现了事件接口(Events interface),即:

  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件

接下来我们一步一步对子组件向父组件传递数据进行讲解,先来看下一个特别简单的示例,这个需求是这样的,当我们改变子组件的count的时候,父组件的count也需要改变

(1)子组件实现功能

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>子组件向父组件传递数据</title>
</head>
<body>
<div id="app">
<my-content :count="count"></my-content>
父组件的count:<span>{{count}}</span>
</div>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
let vm=new Vue({
el:'#app',
data:{
count:1
},
methods:{ },
computed:{ },
components:{
'myContent':{
data(){
return{
ownCount:this.count
}
},
props:['count'],
template:'<div>子组件的count:<span>{{ownCount}}</span><button @click="handleClick">add</button></div>',
methods:{
handleClick(){
this.ownCount++;
}
}
}
} }) </script>
</body>
</html>

我们通过父组件向子组件传递了count值,然后子组件中的count值在点击之后会发生改变,但是这仅仅实现了子组件的值改变,并没有实现父组件中的count改变

vue学习笔记(八)组件校验&通信

(2)向父组件传递信息

需要向父组件传递信息的话,我们就需要子组件通知父组件,然后父组件在做相应的处理,而需要通知父组件我们就i需要用到this.$emit('事件名称',值)。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>子组件向父组件传递数据</title>
</head>
<body>
<div id="app">
<my-content :count="count" @add="handleAdd"></my-content>
父组件的count:<span>{{count}}</span>
</div>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
let vm=new Vue({
el:'#app',
data:{
count:1
},
methods:{
handleAdd(count){
this.count=count;
}
},
computed:{ },
components:{
'myContent':{
data(){
return{
ownCount:this.count
}
},
props:['count'],
template:'<div>子组件的count:<span>{{ownCount}}</span><button @click="handleClick">add</button></div>',
methods:{
handleClick(){
this.ownCount+=10;
this.$emit('add',this.ownCount);
}
}
}
} }) </script>
</body>
</html>

结果:

vue学习笔记(八)组件校验&通信

我们在子组件点击按钮的时候添加了this.$emit()来通知父组件,然后将需要注册的事件和每次改变的值传递了过去,这时父组件注册子组件传递过来的事件和值,然后将父组件中的值替换子组件传递过来的就可以了。

(3)优化子组件向父组件传递信息

其实我们可以做到让父组件来控制子组件中count值的变化,假设我们每次让子组件增加10,我们先来一个小案例

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>子组件向父组件传递数据</title>
</head>
<body>
<div id="app">
<my-content :count="count" @add="handleAdd" v-bind="info"></my-content>
父组件的count:<span>{{count}}</span>
<button @click="handleClick">点击</button>
</div>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
let vm=new Vue({
el:'#app',
data:{
count:1,
info:{
name:'男',
age:18
}
},
methods:{
handleAdd(count){
this.count=count;
},
handleClick(){
this.info.name='女'
}
},
computed:{ },
components:{
'myContent':{
data(){
return{
ownCount:this.count
}
},
props:['count','name','age'],
template:'<div><span>姓名:{{name}}</span><br/>子组件的count:<span>{{ownCount}}</span><button @click="handleClick">add</button></div>',
methods:{
handleClick(){
this.ownCount+=10;
this.$emit('add',this.ownCount);
}
}
}
} }) </script>
</body>
</html>

结果:

vue学习笔记(八)组件校验&通信

vue学习笔记(八)组件校验&通信

当我们点击按钮的时候发现父组件传递给子组件的姓名发生了改变,那么我们只要改变父组件中的count的值,那么子组件中count的值也会发生改变

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>子组件向父组件传递数据</title>
</head>
<body>
<div id="app">
<my-content :count="count" @add="hanldeAdd"></my-content>
父组件中的count<span>{{count}}</span>
</div>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
let vm=new Vue({
el:'#app',
data:{
count:1
},
methods:{
hanldeAdd(count){
this.count+=count;
}
},
computed:{ },
components:{
'myContent':{
data(){
return{
//ownCount=this.count;
}
},
props:['count'],
template:'<div>子组件中的count<span>{{count}}</span><button @click="handleClick">add</button></div>',
methods:{
handleClick(){
this.$emit('add',10)
}
}
}
} }) </script>
</body>
</html>

vue学习笔记(八)组件校验&通信

这样一来父子组件的简单通信就全部讲完了,接下来为了巩固一下父子组件之前通信的知识,我们来做一个任务清单

总结:子组件向父组件传递信息this.$emit('事件名称',值)

(4)任务清单

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>任务清单</title>
</head>
<body>
<div id="app">
任务:<input type="text" v-model="newTask" @keyup.enter="addNew" placeholder="请输入您要完成的任务" />
<ul>
<li is="todoImte" v-for="(item,index) of tasks" :title="item" @remove="removeItem(index)"></li>
</ul>
</div>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
Vue.component('todoImte',{
props:['title'],
template:"<li>{{title}}<button @click='$emit(\"remove\")'>X</button></li>"
});
let vm=new Vue({
el:'#app',
data:{
newTask:'',
tasks:['买一本书','写一次博客','和朋友一起吃饭']
},
methods:{
addNew(){
this.tasks.unshift(this.newTask);
this.newTask='';
},
removeItem(index){
if(confirm('确定要删除吗?')){
this.tasks.splice(index);
}
}
},
computed:{ } }) </script>
</body>
</html>

结果:

vue学习笔记(八)组件校验&通信

vue学习笔记(八)组件校验&通信

vue学习笔记(八)组件校验&通信

任务清单中,首先有个添加任务的框,然后通过addNew方法将任务添加到任务清单中,子组件中通过this.$emit()告诉父组件执行相应的方法,任务清单中,我们可以添加任务清单也可以删除任务清单,添加任务清单的话,没有涉及组件通信,二删除任务清单的时候,子组件通知父组件需要删除那个任务,然后将需要删除任务的索引传递过去,父组件根据传递过来的index进行删除。

总结

本篇博客主要讲了三个知识点,组件的校验,父组件向子组件传递信息(通过props),子组件向父组件传递信息(通过this.$emit),本篇博客讲解的内容也比较简单,但是我认为这仅仅也还是组件的开始,下一遍博客我们将会讲解vue-cli中的组件通信,毕竟这个才是重点,现在的组件通信也才是入门。欢迎大家在博客下方评论,我们一起交流。