定义
为了拆分vue实例的代码量,能够让我们以不同的组件,来划分不同的功能模块,将来需要功能,就可以去调用对应的组件;
组件化和模块化的区别:
1、模块化:是从代码逻辑的角度进行划分的;
2、组件化:是从UI界面的角度进行划分的;方便ui组件的重用;
方式1
使用过程:
- 使用vue.extend 来创建全局的vue组件(通过template属性,指定了组件要展示的html结构)
- 使用vue.component(‘组件的名称’,创建出来的组件模板对象)
- 使用组件,以html标签的的形式,引入到页面中(如果模板的命名为驼峰方式,在使用时需要修改为-连接;如myCom my-com);
<body>
<div class = "app ">
<m_com></m_com>
</div>
</body>
<script type="text/javascript">
var com1 = Vue.extend({
template:'<h3>h3模板组件</h3>'
})
Vue.component('m_com',com1);
var vm = new Vue({
el:'.app'
})
</script>
同样可以将定义的两步合并:
Vue.component('m_com',Vue.extend({
template:'<h3>h3模板组件</h3>'
}));
//第一个参数,引用的标签的名称
//第二个参数,创建的组件,
方式2
以上形式的缩略:
Vue.component('m_com',{
template:'<h3>h3模板组件</h3>'
});
注意:
根元素必须只有一个:
Vue.component('m_com',{
template:'<div><h3>h3模板组件</h3><h2>h2</h2></div>'
});
最外层的div如果舍弃的话,将会报错
方式3
在被控制的app的外面 使用template元素,定义组件的模板结构
<body>
<div class = "app ">
<m_com></m_com>
</div>
<template id="temp1">
<div>
<h1>外围定义的组件结构</h1>
<h2>可以使用</h2>
</div>
</template>
</body>
<script type="text/javascript">
Vue.component('m_com',{
template:'#temp1'
});
var vm = new Vue({
el:'.app'
})
</script>
私有组件
在vue实例内部定义私有组件
var vm = new Vue({
el:'.app',
components:{
//定义实例内部私有组件
com4:{
template:'<h1>私有组件</h1>'
}
}
})
template的值同样也可以是在app实例外部的template标签的id。
组件中的数据
- 组件可以有自己的data数据
- 组件中的data不能为对象,必须为一个方法
- 组件中的data必须返回一个对象
- 组件中的数据使用方式和实例中的一样
<body>
<div class = "app ">
<m_com></m_com>
</div>
<template id="temp1">
<div>
<h1>外围定义的组件结构</h1>
<h2>{{msg}}</h2>
</div>
</template>
</body>
<script type="text/javascript">
Vue.component('m_com',{
template:'#temp1',
data:function(){
return {
msg:"组件中的data"
}
}
});
var vm = new Vue({
el:'.app',
})
</script>
data中数据为了不影响其他组件使用的对象数据,所以将数据以函数返回对象的方式实现。
例如计数组件:
<template id="count">
<div>
<input type="button" value="+1" @click="increace" name="">
<h2>{{count}}</h2>
</div>
</template>
<script type="text/javascript">
Vue.component('counter',{
template:"#count",
data:function(){
return {
count:"0"
}
},
methods:{
increace(){
this.count++;
}
}
})
</script>
组件切换
v-if和v-else
<body>
<div class = "app ">
<a href="" @click.prevent="flag=true">登录</a>
<a href="" @click.prevent="flag=false">注册</a>
<login v-if="flag"></login>
<register v-else="flag"></register>
</div>
<template id="login">
<div>
<h1>登录</h1>
</div>
</template>
<template id="register">
<div>
<h2>注册</h2>
</div>
</template>
</body>
<script type="text/javascript">
Vue.component('login',{
template:'#login',
data:function(){
return {
}
}
});
Vue.component('register',{
template:"#register",
data:function(){
return {
}
}
})
var vm = new Vue({
el:'.app',
data:{
flag:true,
}
})
</script>
component标签
- vue提供的component元素,展示对应名称的组件;
- component是一个占位符,:is属性为要展示的组件的名称
<body>
<div class = "app ">
<a href="" @click.prevent="comName='login'">登录</a>
<a href="" @click.prevent="comName='register'">注册</a>
<component :is="comName"></component>
</div>
<template id="login">
<div>
<h1>登录</h1>
</div>
</template>
<template id="register">
<div>
<h2>注册</h2>
</div>
</template>
</body>
<script type="text/javascript">
Vue.component('login',{
template:'#login'
});
Vue.component('register',{
template:"#register"
})
var vm = new Vue({
el:'.app',
data:{
comName:"login",
}
})
</script>
切换的动画
通过component的mode属性设置组件的切换的模式
<style type="text/css">
.v-enter,
.v-leave-to{
opacity:0;
transform:translateX(150px);
}
.v-enter-active,
.v-leave-active{
transition:all 0.5s ease;
}
</style>
<transition mode="out-in">
<component :is="comName"></component>
</transition>
组件父子数据传递
- 默认vue实例中定义的私有组件中,无法访问vue实例data中的数据和methods
- 父组件通过属性绑定的方式,把数据传递给子组件;
- 需要在子组件props中把父组件传递的属性先定义一遍,才能使用(最好不用大写),props里面的数据都是父中传递的
- 子组件data是子组件私有的数据,可读可写
- props中的数据只能读
<body >
<div class = "app ">
<com1 v-bind:parentmsg="msg"></com1>
</div>
<template id="forcom1">
<h1>子组件:{{parentmsg}}</h1>
</template>
</body>
<script type="text/javascript">
var vm = new Vue({
el:'.app',
data:{
msg:"父中的数据",
},
components:{
com1:{
data(){
return{
msg:"123"
}
},
template:"#forcom1",
// template:'<h1>子组件:{{parentmsg}}</h1>',
props:['parentmsg'],
methods:{}
}
}
})
</script>
父组件传递方法
- 父组件传递方法,使用v-on:的方式绑定(也可简写@)
- 子组件通过$emit()出发父传递的方法
- $emit()方法的第一个参数为父组件绑定的名称,之后的参数为传递给函数的参数;
- 子组件可以通过传参的方式向父组件传递数据;
<body >
<div class = "app ">
<com1 v-on:parentfunc="show"></com1>
</div>
<template id="forcom1">
<input type="button" value="show" @click="click" name="">
</template>
</body>
<script type="text/javascript">
var vm = new Vue({
el:'.app',
data:{
msg:"父中的数据",
sonData:{}
},
methods:{
show(msg,data){
console.log("父组件的函数" + msg);
this.sonData = data;
console.log(this.sonData);
}
},
components:{
com1:{
data(){
return {
name:"Tom",
id:1,
ability:{
des:10,
life:100
}
}
},
template:"#forcom1",
methods:{
click(){
this.$emit('parentfunc',123,this.ability);
}
}
}
}
})
</script>
结果:
组件练习
<link rel="stylesheet" type="text/css" href="./bootstrap.css">
<body >
<div class = "app ">
<com1 v-on:parentfunc="load"></com1>
<ul class="list-group" v-for="(item,index) in list" :key="item.id">
<li class="list-group-item">
<span class="badge">评论人:{{item.user}}</span>
{{item.content}}
</li>
</ul>
</div>
<template id="forcom1">
<div>
<div class="form-group">
<label>评论人:</label>
<input type="text" class="form-control" name="" v-model="user">
</div>
<div class="form-group">
<label>评论内容:</label>
<textarea class="form-control" v-model="content"></textarea>
</div>
<div class="form-group">
<input type="button" name="" value="发表评论" class="btn btn-primary" @click="click">
</div>
</div>
</template>
</body>
<script type="text/javascript">
var vm = new Vue({
el:'.app',
data:{
list:[
{id:Date.now()+1,user:'Trump',content:'fake news'},
{id:Date.now()+2,user:'Biden',content:'please,emm'},
{id:Date.now()+3,user:'King',content:'i have a dream'},
]
},
methods:{
load(){
var list = JSON.parse(localStorage.getItem('cmts') || '[]');
this.list = list;
}
},
components:{
com1:{
data(){
return {
user:"",
content:""
}
},
template:"#forcom1",
methods:{
click(){
var newContent = {id:Date.now(),user:this.user,content:this.content};
var list = JSON.parse(localStorage.getItem('cmts') || '[]');
list.unshift(newContent);
localStorage.setItem('cmts',JSON.stringify(list));
this.user = this.content = "";
this.$emit('parentfunc');
}
}
}
},
created(){
this.load();
}
})
</script>
效果:
获取Dom元素
可通过引用获取dom元素,为标签的ref属性赋值string,通过$refs.string获取对应的标签dom;
<body >
<div class = "app ">
<com1 ref="com1t"></com1>
<input type="button" value="get" @click="getEle" name="">
<h1 ref="myh1">h1标签</h1>
</div>
<template id="forcom1">
<input type="button" value="show" name="">
</template>
</body>
<script type="text/javascript">
var vm = new Vue({
el:'.app',
data:{
},
methods:{
getEle(){
console.log(this.$refs.myh1.innerText);
console.log(this.$refs.com1t.name);
this.$refs.com1t.hello();
}
},
components:{
com1:{
data(){
return {
name:"tom"
}
},
methods:{
hello(){
console.log("hello")
}
},
template:"#forcom1",
}
}
})
</script>
同样也可以通过ref属性获取组件,并访问组件中的数据及方法。