Vue组件-组件组合
组件设计初衷就是要配合使用的,最常见的就是形成父子组件的关系:组件 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" --> |
因为它是一个字面量 prop,它的值是字符串 "1"
而不是一个数值。如果想传递一个真正的 JavaScript 数值,则需要使用 v-bind
,从而让它的值被当作 JavaScript 表达式计算:
<!-- 传递真正的数值 --> |
例子如下:
<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 中数据:
Prop 作为初始值传入后,子组件想把它当作局部数据来用;
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组件-组件组合的更多相关文章
- vue.js组件化开发实践
前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎么实现,技术选型自然 ...
- VUE.JS组件化
VUE.JS组件化 前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎 ...
- 如何抽象一个 Vue 公共组件
之前一直想写一篇关于抽象 Vue 组件的随笔,无奈一直没想到好的例子.恰巧最近为公司项目做了一个数字键盘的组件,于是就以这个为例聊聊如何抽象 Vue 的组件. 先上 Demo 与 源码.(demo最好 ...
- Vue 创建组件的方式
Vue 创建组件的方式 2018年08月07日 11:10:56 虔诚带着决然 阅读数:1015 版权声明:本文为博主原创文章,未经博主允许不得用做其他商业活动. https://blog.csd ...
- Vue.js 组件编码规范
本规范提供了一种统一的编码规范来编写 Vue.js 代码.这使得代码具有如下的特性: 其它开发者或是团队成员更容易阅读和理解. IDEs 更容易理解代码,从而提供高亮.格式化等辅助功能 更容易使用现有 ...
- 【06】Vue 之 组件化开发
组件其实就是一个拥有样式.动画.js逻辑.HTML结构的综合块.前端组件化确实让大的前端团队更高效的开发前端项目.而作为前端比较流行的框架之一,Vue的组件和也做的非常彻底,而且有自己的特色.尤其是她 ...
- 如何理解vue.js组件的作用域是独立的
vue.js组件的作用域是独立,可以从以下三个方面理解: 1.父组件模板在父组件作用域内编译,父组件模板的数据用父组件内data数据:2.子组件模板在子组件作用域内编译,子组件模板的数据用子组件内da ...
- Vue 子组件向父组件传参
直接上代码 <body> <div id="counter-event-example"> <p>{{ total }}</p> & ...
- vue.js 组件之间传递数据
前言 组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.如何传递数据也成了组件的重要知识点之一. 组件 组件与组件之间,还存在着不同的关 ...
随机推荐
- Intent.java分析
代码位于frameworks/base/core/java/anroid/Content/Intent.java Intent是对要进行操作的一种抽象描述.用action抽象操作,用data(andr ...
- Linux内核设计与实现 总结笔记(第三章)进程
进程管理 进程:处于执行期的程序. 线程:在进程中活动的对象 虚拟机制 虚拟处理器:多个进程分享一个处理器 虚拟内存:多个线程共享虚拟内存 一.进程描述符和任务结构 进程存放在双向循环链表中(队列), ...
- 提示”The following modules are missing or built with a different engine version”
一台机器使用自行编译版本引擎修改了工程后,另一台机器也使用自行编译版本引擎编辑该工程,有时会出现标题的提示 解决办法: 打开\Engine\Binaries\Win64\UE4Editor.modul ...
- 浅析java中的string
在学习java36讲的时候看到评论区有人提出的一个问题: String s1 = new String("do"); s1.intern(); String s2 = " ...
- (转)详解k8s组件Ingress边缘路由器并落地到微服务 - kubernetes
转:https://www.cnblogs.com/justmine/p/8991379.html 写在前面 Ingress 英文翻译 进入;进入权;进食,更准确的讲就是入口,即外部流量进入k8s集群 ...
- php面试专题---22、网站优化 总结
php面试专题---22.网站优化 总结 一.总结 一句话总结: 主要从前端.后端.数据库.资源四个方面开始发散 前端浏览器缓存和数据压缩前端优化(减少HTTP请求次数) 资源流量优化(防盗链处理)C ...
- 洛谷P1242 新汉诺塔(dfs,模拟退火)
洛谷P1242 新汉诺塔 最开始的思路是贪心地将盘子从大到小依次从初始位置移动到目标位置. 方法和基本的汉诺塔问题的方法一样,对于盘子 \(i\) ,将盘子 \(1\to i-1\) 放置到中间柱子上 ...
- cmath模块——复数域数学函数模块
cmath——复数域数学函数模块 转自:https://blog.csdn.net/zhtysw/article/category/7511293 该模块属于内置模块,随时可以调用.它提供了数学函数在 ...
- openstack——glance镜像服务
一.glance介绍: Glance是Openstack项目中负责镜像管理的模块,其功能包括虚拟机镜像的查找.注册和检索等. Glance提供Restful API可以查 ...
- Using Xmanager to connect to remote CentOS 7 via XDMCP
Gnome in CentOS 7 tries to use local hardware acceleration and this becomes a problem when trying to ...