前言

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

本章目标

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

父组件向子组件传递数据

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

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

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

在 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.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>

现在的话,我们的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>

结果:

我们在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>

结果:

我们对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>

结果:

子组件向父组件传递数据

我们知道,父组件是使用 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改变

(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>

结果:

我们在子组件点击按钮的时候添加了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>

结果:

当我们点击按钮的时候发现父组件传递给子组件的姓名发生了改变,那么我们只要改变父组件中的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>

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

总结:子组件向父组件传递信息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>

结果:

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

总结

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

vue学习笔记(八)组件校验&通信的更多相关文章

  1. vue学习笔记(七)组件

    前言 在前面vue的一些博客中,我们几乎将vue的基础差不多学习完了,而从本篇博客开始将会进入到vue的另一个阶段性学习,本篇博客的内容在以后的vue项目中占很大的比重,所以小伙伴们需要认真学习,本篇 ...

  2. Vue 学习笔记之 —— 组件(踩了个坑)

    最近在学习vue,学习组件时,遇到了一个问题,困扰了半个多小时.. <!DOCTYPE html> <html lang="en"> <head> ...

  3. Vue学习笔记八:v-for,v-if,v-show指令

    目录 v-for指令:遍历 HTML和效果图 v-for讲解 v-if和v-show:创建,删除,显示,隐藏 HTML和效果图 v-if和v-show的原理 v-for指令:遍历 HTML和效果图 有 ...

  4. vue学习笔记(九)vue-cli中的组件通信

    前言 在上一篇博客vue学习笔记(八)组件校验&通信中,我们学会了vue中组件的校验和父组件向子组件传递信息以及子组件通知父组件(父子组件通信),上一篇博客也提到那是对组件内容的刚刚开始,而本 ...

  5. Vue学习笔记-Vue.js-2.X 学习(二)===>组件化开发

    ===重点重点开始 ========================== (三) 组件化开发 1.创建组件构造器: Vue.extends() 2.注册组件: Vue.component() 3.使用 ...

  6. Vue学习笔记-Vue.js-2.X 学习(三)===>组件化高级

    (四) 组件化高级 1.插槽(slot)的基本使用 A:基本使用: <slot></slot> B:默认置:<slot><h1>中间可以放默认值< ...

  7. vue学习笔记(十)路由

    前言 在上一篇博客vue学习笔记(九)vue-cli中的组件通信内容中,我们学习组件通信的相关内容和进行了一些组件通信的小练习,相信大家已经掌握了vue-cli中的组件通信,而本篇博客将会带你更上一层 ...

  8. Vue学习笔记-rest_framework_jwt 学习

    一  使用环境 开发系统: windows 后端IDE: PyCharm 前端IDE: VSCode 数据库: msyql,navicat 编程语言: python3.7  (Windows x86- ...

  9. Vue学习笔记-Django REST framework3后端接口API学习

    一  使用环境 开发系统: windows 后端IDE: PyCharm 前端IDE: VSCode 数据库: msyql,navicat 编程语言: python3.7  (Windows x86- ...

随机推荐

  1. 谜一样的Java编码和Windows编码

    本文适用于Java源码用UTF-8编码,平台系统为Windows的情况 不管是maven,还是javac,你的IDE都会带上一个参数:-Dfile.encoding=UTF-8 Windows(或许W ...

  2. Mysql数据库(二)Mysql数据库管理

    一 .创建数据库 1.通过CREATE DATABASE db_library;创建名称为db_library的数据库. 2.通过CREATE SCHEMA db_library1;创建名称为db_l ...

  3. 两种unity双击事件

    有时候需要用到双击事件,而unity未提供双击控件,在此提供两种双击事件方法,进攻参考: 1)此方法为通过unityevent来实现 首先新建image(或其他不带点击事件的控件),添加如下脚本,然后 ...

  4. go map数据结构和源码详解

    目录 1. 前言 2. go map的数据结构 2.1 核心结体体 2.2 数据结构图 3. go map的常用操作 3.1 创建 3.2 插入或更新 3.3 删除 3.4 查找 3.5 range迭 ...

  5. net core WebApi——使用xUnits来实现单元测试

    目录 前言 单元测试 xUnit 小结 附录 前言 从开始敲代码到现在,不停地都是在喊着记得做测试,记得自测,测试人员打回来扣你money之类的,刚开始因为心疼钱(当然还是为了代码质量),就老老实实自 ...

  6. Android原生PDF功能实现

    1.背景 近期,公司希望实现安卓原生端的PDF功能,要求:高效.实用. 经过两天的调研.编码,实现了一个简单Demo,如上图所示. 关于安卓原生端的PDF功能实现,技术点还是很多的,为了咱们安卓开发的 ...

  7. C语言1作业5

    问题 答案 这个作业属于那个课程 C语言程序设计1 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-2 我在这个课程的目的是 学习并掌握C ...

  8. 学习笔记30_ORM框架

    *在以往DAL层中,操作数据库使用DataTable,如果使得数据表DataTable转为List<>的话,写错属性名,在编译阶段是查不出来的,而ORM框架能解决此问题. *ORM是指面向 ...

  9. SpringBoot系列:Spring Boot定时任务Spring Schedule

    Spring Schedule是Spring提供的定时任务框架,相较于Quartz,Schedule更加简单易用,在中小型应用中,对于大部分需求,Schedule都可以胜任. 一.Spring Sch ...

  10. [考试反思]1008csp-s模拟测试65:突袭

    博客园挂了,不让粘图. 写的朴素一点. #1:100+100+25=225 #2:100+70+35=205 #2:100+60+45=205(我) 回到第一机房还算不错的第一仗. 考完之后我以为我A ...