1. 组件
a. 什么是组件
组件化开发
我们可以很直观的把一个复杂的页面分割成若干个独立的组件,每个组件包含自已的逻辑和样式,再将这些独立的组件组合成一个复杂的页面。这样就降低了逻辑复杂度,又实现了代码复用。
组件开发的好处
提高开发效率
方便重复使用
便一协同开发
更容易被管理和维护
组件分类
页面级组件:
1、一个页面是一个组件
2、将可复用的部分抽离出来-基础组件
根据作用划分:全局组件和局部组件
全局组件:可以声明一次在任何地方使用。
局部组件:必须告诉这个组件属于谁。
什么时侯用:
一版写插件时全局组件使用的多些
2. 全局组件
要注册一个全局组件,你可以使用 Vue.component(tagName, options)
全局组件在注册之后,便可以在父实例的模块中以自定义元素 <my-component></my-component>的形式使用。
要确保在初始化根实例 之前 注册了组件:
组件中的数据必须是函数类型,返回一个实例做为组件的数据。
步骤:
<body>
<div id="app">
<!-- 自定义元素 <my-component></my-component> 的形式-->
<my-div></my-div>
</div>
<body>
<script src="js/vue.js"></script>
<script>
// 定义全局组件
Vue.component('myDiv', {
<!--template中只能识别一个元素,所以要将所写的页面元素都要放在一个盒子元素里-->
template: '<h1>my first component</h1>'
});
// 创建根实例
new Vue({
el: '#app'
})
</script>
注意:
html中的自定义标签名不能用驼峰命名法
3. 局部组件
不必在全局注册每个组件。通过使用组件实例选项注册,可以使组件仅在另一个实例/组件的作用域中可用:
步骤:1,创建一个组件、2,注册个组件 、3引用这个组件
<body>
<div id="app">
<my-div></my-div>
</div>
</body>
<script src="js/vue.js"></script>
<script>
// 定义子组件child
var child = {
template: '<h1>this is a child component</h1>'
};
var vm = new Vue({
el: '#app',
/* 声明组件child*/
components:{'myDiv': child}
})
</script>
另外一种写法
<div id="app">
<!--1,创建一个组件、2,注册个组件 、3引用这个组件--> {{msg}}
<child></child>
<children></children>
</div>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el:'#app',
data:{
msg:'我是父级'
},
components:{
// child:childs
child:{
template:'<div><h1>我是子组件<span>我是一人</span></h1>14323232</div>'
},
children:{
template:'<h1>我是子组件们</h1>'
}
}
})
</script>
4. 组件注意点
DOM模板解析说明
当使用 DOM 作为模版时(例如,将 el 选项挂载到一个已存在的元素上), 你会受到 HTML的一些限制,因为 Vue 只有在浏览器解析和标准化 HTML 后才能获取模版内容。尤其像这些元素 <ul>,<ol>,<table> ,<select> 限制了能被它包裹的元素, 而一些像 <option>这样的元素只能出现在某些其它元素内部。
- 定义自定义组件时,应当尽量符合W3C的规定,
- 在VUE2.0中,VUE官方做了一些容错处理,但是在一些浏览器中,可能会出错
- 那么VUE建议大家使用is属性来完成书写
eg:
<body>
<div id="app">
<table>
//用is属性完成书写时,my-div在table内
<tr is="my-div"></tr>
//如果不用则table和my-div是同一级的
<my-div></my-div>
</table>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
Vue.component('myDiv', {
template: '<td>my first component</td>'
});
new Vue({
el: '#app',
data: {}
})
</script>
</body>
5. data
组件里的data必须是函数
通过Vue构造器传入的各种选项大多数都可以在组件里用。 data 是一个例外,它必须是函数。实际上,如果你这么做:
Vue.component('my-component', {
template: '<span>{{ message }}</span>',
data: {
message: 'hello'
}
})
那么 Vue 会停止,并在控制台发出警告,告诉你在组件中 data
必须是一个函数。理解这种规则的存在意义很有帮助,让我们假设用如下方式来绕开Vue的警告:
<div id="example-2">
<simple-counter></simple-counter>
<simple-counter></simple-counter>
<simple-counter></simple-counter>
</div>
var data = { counter: 0 }
Vue.component('simple-counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
// 技术上 data 的确是一个函数了,因此 Vue 不会警告,
// 但是我们返回给每个组件的实例的却引用了同一个data对象
data: function () {
return data
}
})
new Vue({
el: '#example-2'
})
由于这三个组件共享了同一个 data , 因此增加一个 counter会影响所有组件!这不对。我们可以通过为每个组件返回全新的 data 对象来解决这个问题:
data: function () {
return {
counter: 0
}
}
定 义组 件私有 变 量数据
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue</title>
</head>
<body>
<div id="app">
<my-div></my-div>
</div>
<script src="js/vue.js"></script>
<script>
Vue.component('myDiv', {
template: '<h1>my first component {{ str }}</h1>',
/*定义组件私有变量,data必须为函数*/
data: function() {
return {
str: 'it`s my data'
}
}
});
// 创建根实例
new Vue({
el: '#app'
})
</script>
</body>
</html>
6. 传值
Vue 组件的数据传递
组件意味着协同工作,通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B。它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件。
然而,在一个良好定义的接口中尽可能将父子组件解耦是很重要的。这保证了每个组件可以在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性。
在 Vue 中,父子组件的关系可以总结为 props down, events up 。父组件通过 向下传递数据给子组件,子组件通过 events 给父组件发送消息。
a. props 的作用
组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。可以使用props 把数据传给子组件。
prop 是父组件用来传递数据的一个自定义属性。子组件需要显式地用 props 选项 声明 “prop”:
<body>
<div id="app">
父亲{{qian}}
<son v-bind:hand='qian'></son>
</div>
<script src="js/vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
data:{
qian:'300'
},
components:{
son:{
template:'<div>儿子收到{{hand}}</div>',
props:['hand'],
}
})
</script>
</body>
使用v-bind绑定数据,当父组件的数据放生变化时,子组件的数据也会放生改变父组件把数据传到子组件当中,用props 接收。
b. 子给父传值
Vue是单向数据流的,允许props 传递数据给子组件,如果子组件想传值个父组件,如果子组件想传值个父组件,就得通过事件的方式
过程:给父亲绑定一些事件,儿子触发这个事件,将参数传递过去
通过自定义事件来调用父级的方法,把给父元素传的值作为参数
使用 $on(eventName) 监听事件
使用 $emit(eventName) 触发事件
<body>
<div id="app">
父亲{{qian}}
<!--songsay自定义事件它的函数变成了 thing函数-->
<son v-bind:hand='qian' v-on:sonsay='thing'></son>
</div>
<script src="js/vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
data:{
qian:'300'
},
methods:{
thing:function(val){
this.qian=val
}
},
components:{
son:{
template:"<div>儿子收到{{hand}}<button @click='say'>不够要900</button></div>",
props:['hand'],
methods:{
say:function(){
this.$emit('sonsay',900)
}
}
}
}
})
</script>
</body>
有时候,你可能想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
<my-div v-on:click.native="doTheThing"></my-div>
自定 义 事件,把子 组 件的 值传给 父 组 件的方法
7. 使用slot分发内容
有时候,组件里面也有自己的内容,如:
<my-component>
<p>这是一些内容</p>
</my-component>
最终结果p标签是没办法显示出来的
为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为内容分发 ,使用特殊的 <slot> 元素作为原始内容的插槽。
单个slot
<body>
<div id="demo">
<div>
<h1>我是父组件的标题</h1>
<my-component>
<p>这是一些初始内容</p>
<p>这是一些初始内容</p>
</my-component>
</div>
</div>
<script src="js/vue.js"></script>
<script>
/*定义全局组件*/
Vue.component('myComponent', {
template: '<div><h2>这是子组件标题</h2><slot>默认值</slot></div>'
})
new Vue({
el: '#demo',
data: {}
})
</script>
</body>
具名slot
<slot> 元素可以用一个特殊的属性 name 来配置如何分发内容。多个 slot 可以有不同的名字。slot 将匹配内容片段中有对应 slot 特性的元素。
仍然可以有一个匿名 slot ,它是默认 slot,作为找不到匹配的内容片段的备用插槽。如果没有默认的 slot ,这些找不到匹配的内容片段将被抛弃。
<body>
<div id="demo">
<my-component>
<h1 slot="header">这里可能是一个页面标题</h1>
<p>主要内容的一个段落。</p>
<p>另一个主要段落。</p>
<p slot="footer">这里有一些联系信息</p>
</my-component>
</div>
<script src="js/vue.js"></script>
<script>
/*定义全局组件*/
Vue.component('myComponent', {
template: '<div class="container"><header><slot name = "header" > < /slot></header > < main > < slot > < /slot></main > < footer > < slot name = "footer" > < /slot></footer > < /div>'
})
new Vue({
el: '#demo',
data: {}
})
</script>
</body>
8. 动态组件
通过使用保留的 <component> 元素,动态地绑定到它的 is
特性,我们让多个组件可以使用同一个挂载点,并动态切换:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="demo">
<input type="text" v-model="currentView" />
<my-component v-bind:is="currentView"></my-component>
</div>
<script src="js/vue.js"></script>
<script>
new Vue({
el: '#demo',
data: {
currentView:'home'
},
components:{
home:{
template:'<h1>这是h1标签</h1>'
},
about:{
template:'<h2>这是h2标签</h2>'
},
contact:{
template:'<h3>这是h3标签</h3>'
}
}
})
</script>
</body>
</html>
如果把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。为此可以添加一个 keep-
alive 指令参数
<keep-alive>
<my-component v-bind:is="currentView"></my-component>
</keep-alive>