[Vue] : 组件
定义Vue组件
什么是组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可;
组件化和模块化的不同:
- 模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;
- 组件化: 是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用;
全局组件定义的三种方式
- 使用
Vue.extend
配合Vue.component
方法:
- 1.1 使用
Vue.extend
来创建全局的Vue组件 - 1.2 通过
template
属性,指定了组件要展示的HTML结构,模板内容必须有且只能有唯一的一个根元素。 - 1.3 使用
Vue.component('组件的名称', 创建出来的组件模板对象)
var com1 = Vue.extend({
template: '<h1>这是通过Vue.extend()方式创建的组件</h1>'
})
Vue.component('myCom1', com1)
- 1.4 如果要使用组件,直接把组件的名称,以 HTML 标签的形式,引入到页面中即可
- 1.5 如果使用
Vue.component
定义全局组件的时候,组件名称使用了驼峰命名,则在引用组件的时候,需要把大写的驼峰改为小写的字母,两个单词之前,使用-
链接 - 1.6 如果不使用驼峰,则直接拿名称来使用即可
<div id="app">
<my-com1></my-com1>
</div>
也可以直接写成
Vue.component('myCom1', Vue.extend({
template: '<h1>这是通过Vue.extend()方式创建的组件</h1>'
}))
- 直接使用 Vue.component 方法:
Vue.component('myCom2', {
template: '<h1>第二个参数直接传个对象</h1>'
})
- 也可以改为
var tmpObj = {
template: '<h1>第二个参数直接传个对象</h1>'
}
Vue.component('myCom2', tmpObj)
- 在 被控制的 #app 外面,使用 template 元素,定义组件的HTML模板结构
<template id="tmpl">
<div>
<h1>通过 template 在组件外部定义的模板</h1>
<h4>哈哈</h4>
</div>
</template>
同时,需要使用 Vue.component 来定义组件:
Vue.component('myCom1', {
template: '#tmpl'
})
注意: 组件中的DOM结构,有且只能有唯一的根元素(Root Element)来进行包裹!
定义私有组件
定义实例内部私有组件,子组件内部还可以继续定义子组件
var vm = new Vue({
el: '#app',
data: {
},
components: {
login: {
template: '<div><h1>登录</h1><child-com></child-com></div>',
components: {
childCom: {
template: '<h3>登录子组件的子组件</h3>'
}
}
}
}
})
也可将模板写在html结构中,实例内部写成template: '#login'
或者将模板对象定义到实例外部,内部通过'组件的名称': 组件的模板对象
的方式定义私有组件。如果组件名称与组件模板对象同名,可以简写。
var login = {
template: '<h1>1234</h1>'
}
var vm = new Vue({
el: '#app',
components: {
// '组件的名称': 组件的模板对象
// 'mylogin': login
login
}
})
在组件内部
<template id="login">
<h1>登录</h1>
</template>
组件中data
和methods
- 在组件中,
data
需要被定义为一个方法,这个方法内部必须返回一个对象。 - 组件中 的data 使用方式,和实例中的 data 使用方式完全一样。
Vue.component('account', {
template: '#tmpl',
data() {
return {
msg: '大家好!'
}
},
methods:{
login(){
alert('点击了登录按钮');
}
}
});
计数器示例
注意:data
如果return dataObj
,会导致多个计数器共用dataObj
对象,因此需要return { count: 0 }
,才能保证各个计数器之间互不影响
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="lib/vue-2.4.0.js"></script>
</head>
<body>
<div id="app">
<counter></counter>
<hr>
<counter></counter>
</div>
<template id="tmpl">
<div>
<input type="button" value="+1" @click="increment">
<h3>{{count}}</h3>
</div>
</template>
<script>
var dataObj = { count: 0 }
Vue.component('counter', {
template: '#tmpl',
data() {
// return dataObj
return { count: 0 }
},
methods: {
increment() {
this.count++
}
}
})
var vm = new Vue({
el: '#app'
})
</script>
</body>
</html>
切换组件
定义登录和注册组件
Vue.component('login', {
template: '<h3>登录组件</h3>'
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
通过flag
配合v-if v-else
切换组件
<div id="app">
<a href="#" @click.prevent="flag=true">登录</a>
<a href="#" @click.prevent="flag=false">注册</a>
<login v-if="flag"></login>
<register v-else></register>
</div>
使用:is
属性来切换组件
使用component
标签,来引用组件,并通过:is
属性来指定要加载的组件
<div id="app">
<a href="#" @click.prevent="comName='login'">登录</a>
<a href="#" @click.prevent="comName='register'">注册</a>
<component :is="comName"></component>
</div>
组件切换的动画效果
- 使用
transition
包裹要实现动画的组件 - 定义
v-enter, v-leave-to, v-enter-active, v-leave-active
样式 - 设置
transition
mode
属性设置组件切换时候的模式,否则两个动画会同时执行
<div id="app">
<a href="#" @click.prevent="comName='login'">登录</a>
<a href="#" @click.prevent="comName='register'">注册</a>
<transition mode="out-in">
<component :is="comName"></component>
</transition>
</div>
父组件向子组件传值
- 父组件可以在引用子组件的时候, 通过属性绑定
v-bind:
的形式, 把需要传递给子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用。
<div id="app">
<com1 v-bind:parentmsg="msg"></com1>
</div>
- 子组件一定要使用
props
属性来定义父组件传递过来的数据
var vm = new Vue({
el: '#app',
data: {
msg: '这是父组件的数据'
},
components: {
com1: {
template: '<h1>子组件 -- {{parentmsg}}</h1>',
props: ['parentmsg']
}
}
})
子组件中的data
中的数据和props
中的数据的区别:
- 子组件中的
data
数据,并不是通过 父组件传递过来的,而是子组件自身私有的,组件中的所有props
中的数据,都是通过父组件传递给子组件的 data
上的数据,都是可读可写的;props
中的数据,都是只读的,无法重新赋值
父组件向子组件传递方法
- 父组件向子组件传递方法,使用的是
v-on
事件绑定机制; - 子组件在自定义的
myclick
方法中,通过this.$emit('事件属性')
的方式调用父组件传递过来的方法
<body>
<div id="app">
<!-- 用func接收父组件的show方法 -->
<com2 @func="show"></com2>
</div>
<!-- 定义了子组件模板 -->
<template id="tmpl">
<div>
<h1>这是子组件</h1>
<input type="button" value="子组件按钮,点击调父组件show方法" @click="myclick">
</div>
</template>
<script>
// 定义了一个字面量类型的组件模板对象
var com2 = {
template: '#tmpl',
methods: {
myclick() {
this.$emit('func')
}
}
}
var vm = new Vue({
el: '#app',
methods: {
show() {
console.log('这是父组件的show方法')
}
},
components: {
com2
}
})
</script>
</body>
子组件向父组件传值
- 原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在调用方法的时候当作参数传递进去;
- 父组件将方法的引用传递给子组件,其中,
getMsg
是父组件中methods
中定义的方法名称,func
是子组件调用传递过来方法时候的方法名称 - 子组件内部通过
this.$emit('方法名', 要传递的数据)
方式,来调用父组件中的方法,同时把数据传递给父组件使用
<div id="app">
<com2 @func="getMsg"></com2>
</div>
<!-- 定义了子组件模板 -->
<template id="tmpl">
<div>
<h1>这是子组件</h1>
<input type="button" value="按钮" @click="myclick">
</div>
</template>
<script>
// 定义了一个字面量类型的组件模板对象
var com2 = {
template: '#tmpl',
data() {
return {
sonMsg: { id: 1, name: '张三' }
}
},
methods: {
myclick() {
this.$emit('func', this.sonMsg)
}
}
}
var vm = new Vue({
el: '#app',
data: {
parentMsg: null
},
methods: {
getMsg(data) {
this.parentMsg = data
console.log(this.parentMsg)
}
},
components: {
com2
}
})
</script>
使用 this.$refs
来获取DOM
元素和组件
- 获取DOM元素
<h3 ref="myh3">这是一个H3</h3>
在Vue实例中,使用this.$refs.myh3
获取到DOM元素,与document.getElementById('myh3')
等效
- 获取组件
<div id="app">
<input type="button" value="获取组件" @click="getElement">
<com1 ref="mycom"></com1>
</div>
<template id="tmpl">
<div>
<h3>子组件</h3>
</div>
</template>
<script>
var com1 = {
template: '#tmpl',
data(){
return {
msg:'子组件的msg'
}
},
methods: {
show(){
console.log('子组件的show方法')
}
}
}
var vm = new Vue({
el: '#app',
data: {
},
methods:{
getElement() {
// 获取子组件的data数据
console.log(this.$refs.mycom.msg)
// 调用子组件的方法
this.$refs.mycom.show()
}
},
components:{
com1
}
})
</script>
http://www.cnblogs.com/moon1992/