组件
自定义组件的意思就是自定义tag标签,这个标签包含着一段html
代码
组件是可复用的 Vue
实例, 说白了就是一组可以重复使用的模板
和 JSTL
的自定义标签、Thymeleaf
的 th:fragment
有着异曲同工之妙,通常一个应用会以一棵嵌套的组件树的形式来组织:
例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
在Vue中,组件是最重要的组合部分,官方中定义组件为可复用的Vue实例,分为全局组件和局部组件,接下来通过实例来分别演示两种不同的组件。
第一个Vue组件
<div id="app">
<pan></pan>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
//先注册组件
Vue.component("pan",{
template:'<li>Hello</li>'
});
//再实例化Vue
var vm = new Vue({
el:"#app",
});
</script>
说明:
Vue.component()
:注册组件pan
:自定义组件的名字template
:组件的模板
props
传递参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue.component</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<mahe666 v-for="item in skills" v-bind:giao="item"></mahe666>
</div>
<!--
说明:
v-for="item in items":遍历Vue实例中定义的名为items的数组,并创建同等数量的组件
v-bind:panh="item":将遍历的item项绑定到组件中props定义名为item属性上;= 号左边的panh为props定义的属性名,右边的为item in items 中遍历的item项的值
-->
<script>
Vue.component("mahe666",{
props:['giao'],
template:'<li>{{giao}}</li>'
});
var app = new Vue({
el:"#app",
data:{
skills:["java","python","vue","html"]
},
})
//调用方法时,每次都需要讲行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销;
</script>
</body>
</html>
全局组件 与 局部组件
使用 Vue.component()
注册组件,需要提供2个参数:组件的标签名 和 组件构造器。
Vue.component()
内部会调用组件构造器,创建一个组件实例
注意:一个组件的template部分,必须要包裹在一个根容器中。
因为组件是可复用的Vue实例,所以它们也有data、computed、watch、methods以及生命周期钩子等。
- 组件模板的内容,可以写在一对反引号中(``),这样就可以不使用字符串拼接的形式了。
- 一个组件的data选项必须是一个函数,该函数返回一个对象。
<div id="app">
<mycomponent></mycomponent>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('mycomponent', {
template: `<div>
<h3>我是全局组件</h3>
<button @click="add">加</button>
</div>`,
data(){
return {
num:1
}
},
methods:{
add(){
this.num++;
}
}
});
var vm = new Vue({
el: '#app',
});
</script>
如果不需要全局注册,或者是让组件使用在其它组件内,可以用选项对象的components属性实现局部注册。
<div id="app">
<mycomponent></mycomponent>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let obj = {
template: `<div>
<h3>我是局部组件</h3>
<button @click="add">加</button>
</div>`,
data(){
return {
num:1
}
},
methods:{
add(){
this.num++;
}
}
};
var vm = new Vue({
el: '#app',
components:{ //声明局部组件
mycomponent:obj
}
});
</script>
组件模板
如果组件中的template内容过多,那么可以使用组件模板来声明template中的内容。
<div id="app">
<mycomponent></mycomponent>
</div>
<!-- 组件模板 -->
<template id="mytemplate">
<div>
<h3>我是局部组件</h3>
<button @click="add">加</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let obj = {
template: '#mytemplate', //使用选择器应用组件模板
data() {
return {
num: 1
}
},
methods: {
add() {
this.num++;
}
}
};
var vm = new Vue({
el: '#app',
components: { //声明局部组件
mycomponent: obj //组件名:组件实例
}
});
</script>
父子组件
当我们继续在组件中写组件,形成组件嵌套的时候,就是我们所说的父子组件了。
<div id="app">
<mycomponent></mycomponent>
</div>
<template id="mytemplate">
<div>
<h3>我是父组件</h3>
<!-- 在父组件中使用子组件 -->
<subcomponents></subcomponents>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let obj = {
template: '#mytemplate',
data() {
return {}
},
components:{ //声明子组件
subcomponents:{
template:`<div>我是子组件</div>`
}
}
};
var vm = new Vue({
el: '#app',
components: { //声明局部组件
mycomponent: obj //组件名:组件实例
}
});
</script>
父子组件通信
组件与组件之间是可以互相通信的。包括父子组件之间、兄弟组件之间等等,都可以互相通信。
在Vue中,组件实例的作用域是孤立的,默认情况下,父子组件的数据是不能共享的,也就是说,子组件是不能直接访问父组件的数据的。
为此,Vue给我们提供了一个数据传递的选项prop,用来将父组件的数据传递给子组件。
下面实例中,子组件获取父组件传递的数据的步骤为:
在子组件标签中,声明 msg 属性,属性值即为父组件向子组件传递的值。
在子组件中,使用props选项,声明接收父组件向子组件传递值的载体,即 'msg' 。
子组件中就可以使用 msg 获取父组件向子组件传递的值了。
也可以使用 v-bind 绑定子组件标签属性,这样就可以将父组件data数据传递个子组件了。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<component msg="mahe666"></component>
</div>
<template id="aaa">
<div>
hello {{msg}}
</div>
</template>
<script>
let component = {
template: '#aaa',
props: ['msg'],
}
var vue = new Vue({
el: '#app',
components: {
//注册组件
component
}
});
</script>
</body>
</html>
不一样的是,父组件想要获取子组件的数据时,需要子组件通过 emit
主动将自己的数据发送给父组件。
首先,我们需要在子组件中触发一个主动发送数据的事件,上面的例子中是一个点击事件
send
;其次,在点击事件中使用
emit
方法,这个emit
接收两个参数:传递数据的事件 和 需要传递的数据,这个传递数据的事件也是自定义的;然后在父组件中引用子组件,并在引用的子组件中使用
on
监听上一步传递数据的事件,上面的例子中是childmsg;最后在父组件中使用这个事件,这个事件带有一个参数,就是从子组件发送过来的数据。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<component @getnum="getNum"></component>
数据{{firstNum}} <br/>
</div>
<template id="aaa">
<div>
<button @click="counter">{{num}}</button>
</div>
</template>
<script>
let component = {
template: '#aaa',
data() {
return {
num:1
}
},
methods: {
counter() {
this.num++;
this.$emit('getnum',this.num)
}
}
}
var vm = new Vue({
el: '#app',
data: {
firstNum:0,
},
components: {
component
},
methods:{
getNum(num){
this.firstNum = num;
},
}
});
</script>
</body>
</html>