组件的出现是为了拆分Vue实例的代码量,以不同的组件来划分不同的功能模块,需要什么功能直接调用对应组件即可
组件化和模块化的区别:
模块化是从代码逻辑的角度进行划分,方便代码分层开发,保证每个功能模块的职能单一
组件化是从UI界面的角度进行划分,前端的组件化是为了方便UI组件的重用
定义全局组件
定义全局组件都是要用Vue.component来定义,只是模板创建上有些不同所以有三种方式
方式1,模板的创建使用Vue.extend
<body>
<div id="app">
<my-temp></my-temp>
</div>
<script>
var template = Vue.extend({
//通过template属性指定了组件要展示的html结构
template:'<h3>Hello</h3>'
})
//Vue.component('组件名',创建出来的组件模板对象)
Vue.component('myTemp',template)
var vm = new Vue({
el:'#app'
})
</script>
</body>
如果使用Vue.component定义全局组件时,组件名使用了驼峰命名,则在引用组件时大写的驼峰要改为小写,并且使用-连接,如果不使用驼峰,则直接使用
组件的使用就是直接当作标签来用
//Vue.component('组件名',创建出来的组件模板对象)
Vue.component('myTemp',Vue.extend({
template:'<h3>Hello</h3>'
}))
方式2,用一个对象代替Vue.extend
不管是哪种方式创建的组件,template属性指向的模板内容,必须有且只有一个根元素
//Vue.component('组件名',创建出来的组件模板对象)
Vue.component('myTemp',{
template:'<div><h3>Hello</h3><p>Hi</p></div>'
})
方式3,模板写在script标签内没有书写提示,可把模板抽出来放在template标签内(只能是放在template标签内),注意template标签要放在el控制的范围外
<body>
<div id="app">
<my-temp></my-temp>
</div>
<template id="temp">
<div>
<h3>Hello</h3>
<p>Hi</p>
</div>
</template>
<script>
//Vue.component('组件名',创建出来的组件模板对象)
Vue.component('myTemp',{
template:'#temp' //template元素的选择器
})
var vm = new Vue({
el:'#app',
})
</script>
</body>
定义私有组件
全局组件可以被所有的Vue实例使用,而私有组件在实例内部定义只能被该实例使用,套路和私有过滤器、私有指令一样,在构造函数里有个components属性
var vm = new Vue({
el:'#app',
components:{
login:{
template:'<h1>Hello~</h1>'
}
}
})
组件的data
组件的data必须是一个方法,并且方法要返回一个对象,data定义后使用方式和实例的data一模一样
Vue.component('myTemp',{
template:'<h1>Hello,{{ msg }}</h1>',
data:function () {
return {
msg:'这是组件data中的数据'
}
}
})
组件切换
方式1,使用v-if和v-else,缺点是只能切换两个组件
<body>
<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>
<script>
Vue.component('login',{
template:'<h3>登录界面</h3>'
})
Vue.component('register',{
template:'<h3>注册界面</h3>'
})
var vm = new Vue({
el: '#app',
data:{
flag:false
}
})
</script>
</body>
方式2,使用Vue提供的component标签实现组件切换,component标签是个占位符,将:is属性设置为对应的组件名后,该组件会替换component标签
<body>
<div id="app">
<a href="#" @click.prevent="comName='fruit'">水果</a>
<a href="#" @click.prevent="comName='sock'">零食</a>
<a href="#" @click.prevent="comName='cartoon'">漫画</a>
<component :is="comName"></component><!--注意comName是个变量,不是字符串'comName'-->
</div>
<script>
Vue.component('fruit',{
template:'<h3>西瓜葡萄木菠萝</h3>'
})
Vue.component('sock',{
template:'<h3>薯片辣条棒棒糖</h3>'
})
Vue.component('cartoon',{
template:'<h3>火影死神海贼王</h3>'
})
var vm = new Vue({
el: '#app',
data:{
comName:'fruit'
}
})
</script>
</body>
实现组件切换的动画效果很简单,只需要把component用transition标签包起来即可,其他照旧
mode为切换模式,out-in表示要等当前组件离开了,下一个组件才进入
组件传值
父组件向子组件传值,Vue实例对象可看成是一个组件,里面定义的私有组件是其子组件,子组件无法访问父组件data里的数据和methods里的方法
这时候父组件可以在引用子组件时,通过属性绑定(v-bind)的形式,把数据传递到子组件内部
<body>
<div id="app">
<son v-bind:parentmsg="msg"></son>
</div>
<script>
new Vue({
el: '#app',
data: {
msg: '力量'
},
components: {
son: {
template: '<div>请赐予我力量 {{ parentmsg }}</div>',
//把父组件的自定义属性在props数组中定义一下,才能使用这个数据
//props数组里的数据都是通过父组件传递来的
props: ['parentmsg']
}
}
})
</script>
这里有个坑,parentmsg用驼峰写法的话会报错,所以可用parentmsg或parent-msg,不可用parentMsg
子组件中的data数据是子组件私有的,子组件可以直接使用,props数据是父组件传递的,子组件通过ajax请求回来的数据都可放在自己的data身上
另外data数据是可读可写的,props数据是只读
若父组件要向子组件传递方法,麻烦,要用事件绑定机制,之后定义一个子组件自己的方法,在这方法内调用父组件传来的方法
<body>
<div id="app">
<son @func="show"></son><!--事件绑定,把父组件方法传递给子组件-->
</div>
<template id="temp">
<div>
<input type="button" value="触发父组件传来的func方法" @click="myclick" >
</div>
</template>
<script>
new Vue({
el: '#app',
methods:{
show(){
console.log('父组件的方法')
}
},
components: {
son: {
template: '#temp',
methods:{
myclick(){
//当点击子组件的按钮的时候,调用emit方法触发父组件传递过来的func方法,
this.$emit('func')
}
}
}
}
})
</script>
</body>
调用父组件方法时可以传参,this.$emit('func',arg) 第二个参数开始就是要传给父组件方法的数据,同时show要写形参
要把子组件data里的数据传给父组件方法,用this.来获取子组件data数据
Vue实例中还有个render方法,可将模板渲染到页面,component是将模板渲染到el控制的区域内,而render是替代整个el指定的区域
<body>
<div id="app">
</div>
<script>
var login = {
template:'<h3>登录</h3>'
}
new Vue({
el: '#app',
data:{},
methods:{},
render:function (createElements) { //createElements是个方法,可把指定组件模板渲染为html结构
return createElements(login)
}
})
</script>