组件需要注册后才可以使用。

Vue.component('my-component',{

  template:'<div>这是组件内容</div>'  

});

局部注册组件

var Child = {
template:'<div>局部注册组件内容</div>'
} var app = new Vue({
el:"#app",
components: {
'my-component':Child
}
})

Vue组件模板在某些情况下会受到限制,比如table,ul,ol.select等,这时可以类似这样:

<table>
<tbody is="my-component"></tbody>
</table>

还可使用数据绑定,但data必须是函数:

Vue.component('my-component',{
template:'<div>{{message}}</div>',
data:function(){
return {
message:'局部注册内容,data方法return'
}
}
})

使用props传递数据

<my-component message="来自父组件的信息"></my-component>
Vue.component('my-component',{
props:['message'],
template:'<div>{{message}}</div>'
})

父组件动态数据:

<input type="text" v-model="message"/>
<my-component :message="message"></my-component>
Vue.component('my-component',{
props:['message'],
template:'<div>{{message}}</div>'
}) var app = new Vue({
el:"#app",
data:{
message:''
} })

当输入框输入时,子组件接收到的props "message" 也会实时响应,并更新组件模板。

注意:

如果直接传递数字,布尔值,数组,对象,而不是用v-bind,传递的是字符串。

<my-component message="[1,2,3]"></my-component>
<my-component :message="[1,2,3]"></my-component>
Vue.component('my-component',{
props:['message'],
template:'<div>{{message.length}}</div>'
})

此时上一个会输出字符串的长度7,下面才是输出数组的长度3。

单向数据流

父组件传递初始值进来,子组件作为初始值保存,在自己的作用域下可随意修改。

<div id="app">
<my-component :init-count="1"></my-component>
</div> <script type="text/javascript"> Vue.component('my-component',{
props:['initCount'],
template:'<div>{{count}}</div>',
data:function(){
return {
count:this.initCount+1
}
}
}) var app = new Vue({
el:"#app",
data:{
message:''
} })
</script>
<div id="app">
<my-component :width="100"></my-component>
</div> <script type="text/javascript"> Vue.component('my-component',{
props:['width'],
template:'<div :style="style">组件内容</div>',
computed:{
style:function(){
return {
width:this.width+"px",
background:'red'
}
}
}
}) var app = new Vue({
el:"#app",
data:{
message:''
} })
</script>

子组件传递数值到父组件:

<div id="app">
<p>总数:{{total}}</p>
<my-component @increase="handleGetTotal" @reduce="handleGetTotal"></my-component>
</div>
<script type="text/javascript">
Vue.component('my-component',{
template:'<div><button @click="handleIncrease">+1</button><button @click="handleReduce">-1</button></div>',
data:function(){
return {
counter: 0
}
},
methods:{
handleIncrease:function(){
this.counter++;
this.$emit('increase',this.counter);
},
handleReduce:function(){
this.counter--;
this.$emit('reduce',this.counter);
}
}
});
var app = new Vue({
el:"#app",
data:{
total:0
},
methods:{
handleGetTotal:function(total){
this.total=total
console.log(total)
}
} });

在子组件定义两个事件,改变自身数据的同时使用$emit来触发父组件的自定义事件名称,从而触发对应的方法,再把改变的数据通过方法传到父组件的方法,从而改变父组件的数据。

使用v-model

<div id="app">
<p>总数:{{total}}</p>
<my-component v-model="total"></my-component>
</div>
<script type="text/javascript">
Vue.component('my-component',{
template:'<div><button @click="handleIncrease">+1</button></div>',
data:function(){
return {
counter: 0
}
},
methods:{
handleIncrease:function(){
this.counter++;
this.$emit('input',this.counter);
}
}
});
var app = new Vue({
el:"#app",
data:{
total:0
} });
</script>

这次区别是$emit通知的是特殊的input,但是并没有在组件上使用@input,这是因为v-model,这也可以称作是一个语法糖。

因为上面的示例可以间接实现:

<my-component @input="total"></my-component>

v-model还可以用来创建自定义的表单输入组件,进行数据双向绑定:

<div id="app">
<p>总数:{{total}}</p>
<my-component v-model="total"></my-component>
<button @click="handleReduce">-1</button>
</div>
<script type="text/javascript">
Vue.component('my-component',{
props:['value'],
template:'<input :value="value" @input="updateValue" />',
methods:{
updateValue:function(event){
this.$emit('input',event.target.value);
}
}
});
var app = new Vue({
el:"#app",
data:{
total:0
},
methods:{
handleReduce:function(){
this.total--;
}
} });
</script>

子组件input改变value值后出发updateValue,通过$emit触发特殊的input事件,传值输入的value值,改掉父组件的total,父组件的handleReduce方法改变total后,由于是双向绑定,所以子组件的value值也随着改变。

这需要满足两个条件:

1.接收一个props的value值,

2.更新value触发特殊的input事件

非父子组件通信

在vue1.x中是采用$dispatch()和$broadcast()这两个方法。$dispatch()由于向上级派发事件,只要是它的父级,都可在vue实例的events选项内接收。

在vue2.x中废弃了上述两种方法。在vue2.x中推荐使用一个空的vue实例作为中央事件总线(bus),也就是一个中介。

如下:

<div id="app">
<p>信息:{{message}}</p>
<my-component></my-component>
</div>
<script type="text/javascript">
var bus = new Vue();
Vue.component('my-component',{
template:'<button @click="handleEvent"></button>',
methods:{
handleEvent:function(event){
bus.$emit('on-message','来自组件component的内容');
}
}
});
var app = new Vue({
el:"#app",
data:{
message:''
},
mounted:function(){
var _this = this;
bus.$on('on-message',function(msg){
_this.message=msg;
})
} });
</script>

定义一个空的vue实例当做中间人,在钩子函数mounted中监听了来自bus的事件on-message,在组件中会点击按钮通过bus把事件on-message发出去,此时app会接收到来自bus的事件。

除了中间介这种方式外,还有两种方法可实现组件间的通信:父链和子组件索引。

父链

子组件中使用this.$parent可直接访问父实例或组件,父组件也可以通过this.$children访问它所有子组件。

<div id="app">
<p>信息:{{message}}</p>
<my-component></my-component>
</div>
<script type="text/javascript">
Vue.component('my-component',{
template:'<button @click="handleEvent">通过$parent改变信息内容</button>',
methods:{
handleEvent:function(event){
this.$parent.message='子组件通过$parent改变了信息内容';
}
}
});
var app = new Vue({
el:"#app",
data:{
message:''
} });
</script>

子组件内通过this.$parent.message直接修改信息内容,正常使用不推荐使用。因为这样使得父子组件紧耦合,只看父组件,很难理解父组件状态,因为它可能被任意组件修改。最好还是通过props和$emit来通信

子组件索引

<div id="app">
<button @click="handleRef">通过red获取子组件实例</button>
<my-component ref="Mycom"></my-component>
</div>
<script type="text/javascript">
Vue.component('my-component',{
template:'<div>子组件</div>',
data:function() {
return {
message:'子组件内容'
}
}
});
var app = new Vue({
el:"#app",
methods:{
handleRef:function(){
var msg = this.$refs.Mycom.message;
console.log(msg)
}
} });
</script>

父组件内的内容通过this.$refs.Mycom找到子组件,并输出了子组件的内容。

使用slot分发内容

当需要让组件组合使用,混合父组件发的内容与子组件的模板时,就会用到slot,这个过程叫做内容分发。

slot用法

单个slot: 在子组件标签内的素有内容替代子组件的<slot>标签及它的内容。如下:

<div id="app">
<child-component>
<p>分发的内容</p>
<p>更多分发的内容</p>
</child-component>
</div>
<script type="text/javascript">
Vue.component('child-component',{
template:'<div><slot><p>如果没有父组件插入内容,我将默认出现</p></slot></div>',
});
var app = new Vue({
el:"#app",
});
</script>

当父组件没有插入分发的内容,即上述代码没有

<p>分发的内容</p>

<p>跟多分发的内容</p>

的时候,子组件将默认显示子组件里slot的内容,如果父组件里插入了分发的内容,则将替换掉子组件里slot标签里的全部内容。

具名slot

给slot元素指定一个name后可以分发多个内容,具名slot可以与单个slot共存。

如下:

<div id="app">
<child-component>
<h2 slot="header">标题</h2>
<p>正文内容</p>
<p>更多正文内容</p>
<div slot="footer">底部信息</div>
</child-component>
</div>
<script type="text/javascript">
Vue.component('child-component',{
template:`<div class="container">
<div class="header">
<slot name="header"></slot>
</div>
<div class="main">
<slot></slot>
</div>
<div class="footer">
<slot name="footer"></slot>
</div>
</div>`,
});
var app = new Vue({
el:"#app",
});
</script>

在父组件上面可以具名插入slot的name,然后子组件会更具name插入具体的内容。

作用域插槽

是一种特殊的slot使用一个可以复用的模板替换已渲染的元素。

<div id="app">
<child-component>
<template scope="props">
<p>来自父组件的内容</p>
<p>{{props.msg}}</p>
</template>
</child-component>
</div>
<script type="text/javascript">
Vue.component('child-component',{
template:`<div class="container">
<slot msg="来自子组件的内容"></slot>
</div>`,
});
var app = new Vue({
el:"#app",
});
</script>

子组件模板,在slot元素上有一个类似pros传递数据给组件的写法 msg="XXX",将数据传到了插槽。父组件使用了template且拥有一个scope="props"的特性,这里的props知识一个临时变量,通过临时变量props来访问来自子组件的数据msg。渲染的最终结果为:

<div id="app">
<div class="container">
<p>来自父组件的内容</p>
<p>来自子组件的内容</p>
</div>
</div>

作用域插槽具代表性的用例是列表组件,允许组件自定义应该如何渲染列表的每一页。

<div id="app">
<my-list :book="books">
<!--作用域插槽也可以是具名的slot-->
<template slot="book" scope="props">
<li>{{props.bookName}}</li>
</template>
</my-list>
</div>
<script type="text/javascript">
Vue.component('my-list',{
props:{
books:{
type:Array,
default:function(){
return [];
}
}
},
template:'<ul><slot name="book" v-for="book in books" :bookName="book.name"></slot></ul>',
});
var app = new Vue({
el:"#app",
data:{
books:[
{name:'js'},
{name:'css'},
{name:'html'}
] }
});
</script>

子组件my-list接收一个来自父级的prop数组books,并且将它在name为book的slot上使用v-for指令循环,同时暴露一个变量bookName。

访问slot

vue2.x提供了用来访问被slot分发的内容的方法$slots。

<div id="app">
<my-component>
<h2 slot="header">标题</h2>
<p>正文内容</p>
<div slot="footer">底部信息</div>
</my-component>
</div>
<script type="text/javascript">
Vue.component('my-component',{
template:`<div class="container">
<div class="header">
<slot name="header"></slot>
</div>
<div class="main">
<slot></slot>
</div>
<div class="footer">
<slot name="footer"></slot>
</div>
</div>`,
mounted:function(){
var header = this.$slots.header;
var main = this.$slots.default;
var footer = this.$slots.footer; console.log(footer[0].elm.innerHTML)
}
});
var app = new Vue({
el:"#app",
});
</script>

在子组件钩子函数中能用$slots得到对应的slot。

组件的高级用法

递归组件

组件可以在它的模板内调用自己,只要给组件设置name属性就可以。

<div id="app">
<my-component :count="1"></my-component>
</div>
<script type="text/javascript">
Vue.component('my-component',{
name:'my-component',
props:{
count:{
type:Number,
default:function(){
return 1;
}
}
},
template:'<div class="child"><my-component :count="count+1" v-if="count<3"></my-component></div>', });
var app = new Vue({
el:"#app",
});
</script>

设置name后就可以递归使用了,不过需要一个限制条件,不然会报错。

内联模板

vue提供了一个内敛模板的功能,在使用组件时,给组件标签使用inline-template特性,组件就会把它的内容当做模板,而不是把它当内容分发。

<div id="app">
<my-component inline-template>
<div>
<h2>父组件定义子组件模板</h2>
<p>{{message}}</p>
<p>{{msg}}</p>
</div>
</my-component>
</div>
<script type="text/javascript">
Vue.component('my-component',{
data:function(){
return {
msg:'子组件内容'
}
} });
var app = new Vue({
el:"#app",
data:{
message:'父组件内容'
}
});
</script>

渲染成:

<div>
<h2>父组件定义子组件模板</h2>
<p>父组件内容</p>
<p>子组件内容</p>
</div>

使用内联模板会导致作用域混淆,应避免使用。

动态组件

vue.js提供了一个特殊的元素<component>用来动态挂载不同的组件,使用is特性来选择挂载的组件。

<div id="app">
<component :is="currentView"></component>
<button @click="handleChangeView('A')">切换到A</button>
<button @click="handleChangeView('B')">切换到B</button>
<button @click="handleChangeView('C')">切换到C</button>
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
components:{
comA:{
template:'<div>A模板</div>'
},
comB:{
template:'<div>B模板</div>'
},
comC:{
template:'<div>C模板</div>'
},
},
data:{
currentView:'comA',
},
methods:{
handleChangeView:function (component){
this.currentView='com'+component
}
}
});
</script>

动态地改变currentView就可以切换视图。

异步组件

当工程足够大,使用组件足够多时,是时候考虑下性能了,因为一开始把所有组件都加载时时一笔开销。vue.js允许将组件定义为一个工厂函数,动态地解析组件。

<div id="app">
<my-component></my-component>
</div>
<script type="text/javascript">
Vue.component('my-component',function(resolve,reject){
setTimeout(()=>{
resolve({
template:'<div>我是异步渲染的</div>'
})
},2000)
});
var app = new Vue({
el:"#app",
});
</script>

$nextTick

当v-if,动态切换显示时,直接去取div的内容时获取不到的,因为此时div还没有被创建出来。这里涉及到一个vue的重要概念:异步更新队列。

vue在观察到数据变化时并不是直接更新DOM,而是开启一个队列,并缓冲在同一事件循环中发生的数据变化。

$nextTick就是用来知道DOM什么时候更新好的。

X-template

没有使用webpack,gulp等工具,组件内容复杂,如果都在javascript中拼接字符串,效率很低,vue提供了另一种定义模板的方式,在script标签使用text/template类型,指定一个ID,将这个id赋给template。

<div id="app">
<my-component></my-component>
<script type="text/x-template" id="my-component">
<div>这是组件内容</div>
</script>
</div>
<script type="text/javascript">
Vue.component('my-component',{
template:"#my-component"
});
var app = new Vue({
el:"#app",
});
</script>

vue的初衷不是滥用它,因为它将模板和组件的其他定义隔离了。

vue.js 精学组件记录的更多相关文章

  1. vue.js 精学记录

    v-bind:class使用的方式: 1.对象与法::class="{'active':isActive}" 此时当isActive为true时,会拥有active 2.数组语法: ...

  2. 转: Vue.js——60分钟组件快速入门(上篇)

    转自: http://www.cnblogs.com/keepfool/p/5625583.html Vue.js——60分钟组件快速入门(上篇)   组件简介 组件系统是Vue.js其中一个重要的概 ...

  3. Vue.js学习 Item11 – 组件与组件间的通信

    什么是组件? 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能.在有 ...

  4. vue.js相关UI组件收集

    内容 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 ###UI组件 element ★9689 - 饿了么出品的Vue2的web UI工具套件 Vux ★6927 - 基于Vu ...

  5. Vue.js 的精髓——组件

    开篇:Vue.js 的精髓——组件 写在前面 Vue.js,无疑是当下最火热的前端框架 Almost,而 Vue.js 最精髓的,正是它的组件与组件化.写一个 Vue 工程,也就是在写一个个的组件. ...

  6. Vue.js的动态组件模板

    组件并不总是具有相同的结构.有时需要管理许多不同的状态.异步执行此操作会很有帮助. 实例: 组件模板某些网页中用于多个位置,例如通知,注释和附件.让我们来一起看一下评论,看一下我表达的意思是什么.评论 ...

  7. Vue.js——60分钟组件快速入门(上篇)

    组件简介 组件系统是Vue.js其中一个重要的概念,它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件树: 那么什么是组件呢?组件可以扩展HTML ...

  8. Vue.js——60分钟组件快速入门(下篇)

    概述 上一篇我们重点介绍了组件的创建.注册和使用,熟练这几个步骤将有助于深入组件的开发.另外,在子组件中定义props,可以让父组件的数据传递下来,这就好比子组件告诉父组件:"嘿,老哥,我开 ...

  9. vue-schart : vue.js 的图表组件

    介绍 vue-schart 是使用vue.js封装了sChart.js图表库的一个小组件.支持vue.js 1.x & 2.x 仓库地址:https://github.com/lin-xin/ ...

随机推荐

  1. Webpack学习-工作原理(上)

    对于webpack的认识始终停留在对脚手架的使用,不得不说脚手架既方便又好用,修改起来也方便,只需要知道webpack中各个配置项的功能,于是对于我们来说,webpack始终就是一个黑盒子,我们完全不 ...

  2. C# Winform 通过Socket实现客户端和服务端TCP通信

    操作界面如下: 1.声明Socket 第一个参数:寻址方式,第二个参数:传输数据的方式,第三个参数:通信协议 Socket socket = new Socket(AddressFamily.Inte ...

  3. springboot秒杀课程学习整理1-4

    1)商品模型设计 (应该是先设计商品的model,然后才是数据库表) 模型字段(id,title,price(double),stock(库存),description,sales,imgUrl) 创 ...

  4. unity 中UGUI制作滚动条视图效果(按钮)

    1.在unity中创建一个Image作为滚动条视图的背景: 2.在Image下创建一个空物体,在空物体下创建unity自带的Scroll View组件: 3.对滑动条视图的子物体进行调整: 4.添加滚 ...

  5. oracle权限列表

    alter any cluster 修改任意簇的权限 alter any index 修改任意索引的权限 alter any role 修改任意角色的权限 alter any sequence 修改任 ...

  6. 常用类-API文档-Integer

    package IntegerTest;import java.util.Base64.Decoder; public class test01 { /** * 包装类的基本数据类型 * int =& ...

  7. jq后加标签的事件(live事件)

    在使用中  live可以对未来元素起作用(比如:js后加的div等)   live在jq1.9以上版本已经废除 原:$('#del').live('click',function(){}) 改:$(' ...

  8. java基础知识—数组

    1.数组:是一个变量,存储相同数据类型的一组数据. 2.数据的优点:减少代码量.易查找. 3.数组的使用步骤: 1)声明数组:int scores []: 2)开辟空间:scores = new in ...

  9. linux发布环境初始化脚本

    #参数配置 homeDir=$(pwd) tomcatDir=$homeDir/tomcat logDir=$homeDir/tomcat/logs backUpDir=$homeDir/backup ...

  10. [AutoMapper]反射自动注册AutoMapper Profile

    AutoMapper 帮我我们方便管理物件跟物件之间属性值格式转换 模型转换 这里有两个类别 UserInfoModel 当作我们从DB捞取出来模型资料 public class UserInfoMo ...