组件设计初衷就是要配合使用的,最常见的就是形成父子组件的关系:组件 A 在它的模板中使用了组件 B。

 <html>
<head>
<title>Vue组件 A 在它的模板中使用了组件 B的例子</title>
<script src="vue.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<my-item :list="list"></my-item>
</div> <script>
new Vue({
el:"#app",
data:{
list:["第一项","第二项","第三项"]
},
components:{
// 组件A
"my-item":{
template : `
<div>
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
<my-list :list="list"></my-list>
</div>
`,
props:['list'], components:{
// 组件B
"my-list":{
template : `
<div>
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
</div>
`,
props:['list']
} } },
}
})
</script>
</body>
</html>

在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息。看看它们是怎么工作的。

Prop

使用 Prop 传递数据

组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。父组件的数据需要通过 prop 才能下发到子组件中。

我们来看一个例子:

 <html>
<head>
<title>Vue子组件的模板内直接引用父组件的数据</title>
<script src="vue.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<child></child>
</div> <script>
new Vue({
el:"#app",
data:{
message:"Hello" },
components:{
"child":{
template:"<p>{{ message }}</p>"
} } })
</script>
</body>
</html>

这样子组件直接引用父组件的数据会出错!

子组件要显式地用 props 选项声明它预期的数据:

 <html>
<head>
<title>Vue props父子之间通信</title>
<script src="vue.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<child message="Hello Vue!!!"></child>
</div> <script>
new Vue({
el:"#app",
components:{
"child":{
template:"<p>{{ message }}</p>" ,
props:['message']
},
} })
</script>
</body>
</html>

这样就可以正常显示我们想要的结果

模板的要求

注意:组件的模板只能有一个根元素。下面的情况是不允许的。

template: `<div>这是一个局部的自定义组件,只能在当前Vue实例中使用</div>
<button>hello</button>`,

camelCase vs. kebab-case

HTML 特性是不区分大小写的。所以,当使用的不是字符串模板时,camelCase (驼峰式命名) 的 prop 需要转换为相对应的 kebab-case (短横线分隔式命名):

  <div id="example">
<child myMessage="Hello Vue!!!"></child>
</div> <script>
new Vue({
el:"#example",
components:{
"child":{
template:"<p>{{ myMessage }}</p>",
props:["myMessage"]
}
}
})
</script>

这样就会报错

应改为

 <div id="example">
<child my-Message="Hello Vue!!!"></child>
</div>

动态prop:

与绑定到任何普通的 HTML 特性相类似,我们可以用 v-bind 来动态地将 prop 绑定到父组件的数据。每当父组件的数据变化时,该变化也会传导给子组件:

 <div id="example">
<input v-model="parentMsg"><br>
<child :message="parentMsg"></child>
</div>
<script>
Vue.component("child",{
template:"<span>{{ message }}</span>",
props:["message"] })
new Vue({
el:"#example",
data:{
parentMsg:""
}
})
</script>

浏览器打开显示

如果你想把一个对象的所有属性作为 prop 进行传递,可以使用不带任何参数的 v-bind (即用 v-bind 而不是 v-bind:prop-name)。

这句话怎么理解呢?我们看一个例子

 <div id="app">
<my-component v-bind="todo"></my-component> <!--重点就是这-->
<!--不用将对象的属性写成 v-bind:first="todo.first" v-bind:second="todo.second"-->
</div>
Vue.component("my-component", {
template: "<div><span>第一个值是:{{first}},第二个值是:{{ second }}</span></div>",
props:["first","second"]
})
new Vue({
el:"#app",
data:{
todo:{
first:"Hello world",
second:"Hello Vue"
}
}
})

字面量语法 vs 动态语法

初学者常犯的一个错误是使用字面量语法传递数值:

<!-- 传递了一个字符串 "1" -->
<comp some-prop="1"></comp>

因为它是一个字面量 prop,它的值是字符串 "1" 而不是一个数值。如果想传递一个真正的 JavaScript 数值,则需要使用 v-bind,从而让它的值被当作 JavaScript 表达式计算:

<!-- 传递真正的数值 -->
<comp v-bind:some-prop="1"></comp>

例子如下:

 <div id="example">
<child num1="4" v-bind:num2="4"></child>
</div>
<script>
Vue.component("child", {
template:"<p>使用了字面量传递数值+2得出结果:{{num1 + 2}}<br>使用了动态语法传递数值+2的结果:{{num2 + 2}}</p>",
props:["num1","num2"]
})
new Vue({
el:"#example",
})
</script>

浏览器打开显示:

单向数据流

Prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解。

另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告。

 <html>
<head>
<title>Vue单向数据流</title>
<script src="vue.js"></script>
</head>
<body>
<div id="example">
<my-button :count="count"></my-button>
</div>
<script>
Vue.component("my-button", {
props:["count"],
template:"<button @click='changeMessage'>{{ count }}</button>",
methods:{
changeMessage:function(){
this.count++
}
}
})
new Vue({
el:"#example",
data:{
count:0
}
})
</script> </body>
</html>

虽然想要做的功能实现了但vue报了个错,你不应该在子组件内部改变 prop

在两种情况下,我们很容易忍不住想去修改 prop 中数据:

  1. Prop 作为初始值传入后,子组件想把它当作局部数据来用;

  2. Prop 作为原始数据传入,由子组件处理成其它数据输出。

上面的例子就是第一种情况子组件怎么把它当局部数据用?

定义一个局部变量,并用 prop 的值初始化它:

 data:function(){
return {
initCount: this.count
}
}
 <html>
<head>
<title>Vue单向数据流</title>
<script src="vue.js"></script>
</head>
<body>
<div id="example">
<my-button :count="count"></my-button>
</div>
<script>
Vue.component("my-button", {
props:["count"],
template:"<button @click='changeMessage'>{{ initCount }}</button>",//别忘了这里也需要修改
data:function(){
return {
initCount: this.count
}
},
methods:{
changeMessage:function(){
this.initCount++
}
}
})
new Vue({
el:"#example",
data:{
count:0
}
})
</script> </body>
</html>

这样就ok了!

第二种情况请看下面例子:

 <html>
<head>
<title>Vue单向数据流</title>
<script src="vue.js"></script>
</head>
<body>
<div id="example">
<input v-model="message">
<child :message="message"></child>
</div>
<script>
Vue.component("child", {
props:["message"],
template:"<p>{{ message }}</p>"
})
new Vue({
el:"#example",
data:{
message:"test"
}
})
</script>
</body>
</html>

这是一个双向绑定的例子,我们如何把输入的值将它用p标签转化成大写显示出来!

computed:{
    changeMessage:function(){
   return this.message.trim().toUpperCase();
}
}

 <html>
<head>
<title>Vue单向数据流</title>
<script src="vue.js"></script>
</head>
<body>
<div id="example">
<input v-model="message">
<child :message="message"></child>
</div>
<script>
Vue.component("child", {
props:["message"],
template:"<p>{{ changeMessage }}</p>",
computed:{
changeMessage:function(){
return this.message.trim().toUpperCase();
}
}
})
new Vue({
el:"#example",
data:{
message:"test"
}
})
</script>
</body>
</html>

props验证

我们可以为组件的 prop 指定验证规则。如果传入的数据不符合要求,Vue 会发出警告。这对于开发给他人使用的组件非常有用。

<html>
<head>
<title>Vueprops验证</title>
<script src="vue.js"></script>
</head>
<body>
<div id="example">
<child
:name="name"
:age="age"
></child>
</div>
<script>
Vue.component("child", {
props:{
name:{
type:String,
default:"Vue",
required:true
},
age:Number
},
template:"<p>同学叫{{ name }},年龄:{{ age }}</p>",
}) new Vue({
el:"#example",
data:{
name:"胡小明",
age:18,
}
})
</script>
</body>
</html>

就从这个简单的例子分析一下用法:

type:可以使用type来声明这个参数可以接受的数据的类型,当检查规则只有一个的时候type可以略写如

当参数可以是多种类型的其中一个的时候,使用数组来表示

message:[String,Number]

type可以是以下原生类型:

String

Number

Boolean

Function

Object

Array

Symbol

required:可以使用required选项来声明这个参数是否必须传入。如果是true则为必填项,如不填则报出警告

defaule:使用default选项来指定当父组件未传入参数时props变量的默认值:

validator:当校验规则很复杂,默认提供的校验规则无法满足的时候可以使用自定义函数来校验。(上面代码没有写这个例子)

举例当小明可以去网吧上网的时候必定年龄是>=18的

 props:{
age:{
validator:function(value){
return value >= 18
}
} }

Vue组件-组件组合的更多相关文章

  1. vue.js组件化开发实践

    前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎么实现,技术选型自然 ...

  2. VUE.JS组件化

    VUE.JS组件化 前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎 ...

  3. 如何抽象一个 Vue 公共组件

    之前一直想写一篇关于抽象 Vue 组件的随笔,无奈一直没想到好的例子.恰巧最近为公司项目做了一个数字键盘的组件,于是就以这个为例聊聊如何抽象 Vue 的组件. 先上 Demo 与 源码.(demo最好 ...

  4. Vue 创建组件的方式

    Vue 创建组件的方式 2018年08月07日 11:10:56 虔诚带着决然 阅读数:1015   版权声明:本文为博主原创文章,未经博主允许不得用做其他商业活动. https://blog.csd ...

  5. Vue.js 组件编码规范

    本规范提供了一种统一的编码规范来编写 Vue.js 代码.这使得代码具有如下的特性: 其它开发者或是团队成员更容易阅读和理解. IDEs 更容易理解代码,从而提供高亮.格式化等辅助功能 更容易使用现有 ...

  6. 【06】Vue 之 组件化开发

    组件其实就是一个拥有样式.动画.js逻辑.HTML结构的综合块.前端组件化确实让大的前端团队更高效的开发前端项目.而作为前端比较流行的框架之一,Vue的组件和也做的非常彻底,而且有自己的特色.尤其是她 ...

  7. 如何理解vue.js组件的作用域是独立的

    vue.js组件的作用域是独立,可以从以下三个方面理解: 1.父组件模板在父组件作用域内编译,父组件模板的数据用父组件内data数据:2.子组件模板在子组件作用域内编译,子组件模板的数据用子组件内da ...

  8. Vue 子组件向父组件传参

    直接上代码 <body> <div id="counter-event-example"> <p>{{ total }}</p> & ...

  9. vue.js 组件之间传递数据

    前言 组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.如何传递数据也成了组件的重要知识点之一. 组件 组件与组件之间,还存在着不同的关 ...

随机推荐

  1. vue中的render函数介绍

    简介:对于不了解slot的用法(参考:大白话vue-slot的用法)又刚接触render函数的同学来说,官网的解释无疑一脸懵逼,这里就整理下个人对render函数的理解 问题: 1.render函数是 ...

  2. 求能粘贴Word 内容(含图片)的在线编辑器

    word图片转存,是指UEditor为了解决用户从word中复制了一篇图文混排的文章粘贴到编辑器之后,word文章中的图片数据无法显示在编辑器中,也无法提交到服务器上的问题而开发的一个操作简便的图片转 ...

  3. (转)Window 中杀死指定端口 cmd 命令行 taskkill

    Windows平台   两步方法 :  1 查询端口占用,2 强行杀死进程 netstat -aon|findstr "8080" taskkill /pid 4136-t -f ...

  4. 虚拟机中安装Linux_Centos7操作系统(最小化安装)

    我们打开之前安装的VM, 点击 “创建新的虚拟机”: 我们选 典型 安装  简单点 然后下一步: 我们稍后安装操作系统 ,点下一步: 这里选 Linux 然后下拉 选CentOS 64位,然后下一步: ...

  5. day29—JavaScript中DOM的基础知识应用

    转行学开发,代码100天——2018-04-14 JavaScript中DOM操作基础知识即对DOM元素进行增删改操作.主要表现与HTML元素的操作,以及对CSS样式的操作.其主要应用知识如下图: 通 ...

  6. 拒绝从入门到放弃_《Python 核心编程 (第二版)》必读目录

    目录 目录 关于这本书 必看知识点 最后 关于这本书 <Python 核心编程 (第二版)>是一本 Python 编程的入门书,分为 Python 核心(其实并不核心,应该叫基础) 和 高 ...

  7. SqlServer 索引和视图

    Ø 索引 1. 什么是索引 索引就是数据表中数据和相应的存储位置的列表,利用索引可以提高在表或视图中的查找数据的速度. 2. 索引分类 数据库中索引主要分为两类:聚集索引和非聚集索引.SQL Serv ...

  8. vim-tabe多标签切换

    vim-tabe多标签切换 本文转载自https://www.cnblogs.com/liqiu/archive/2013/03/26/2981949.html 1.新建标签页 使用:tabe命令和文 ...

  9. debain8 安装mysql8

    一.下载apt源 https://dev.mysql.com/downloads/repo/apt/ 二.更新apt sudo apt-get update 三.安装mysql sudo apt-ge ...

  10. MySQL-第N篇杂记

    1.数据的导入导出 2.查询结果的重定向 3.ON DUPLICATE KEY UPDATE对于指定的主键或者唯一键,insert时发生冲突则进行update操作. 4.解决MySQL中问乱码问题,分 ...