05 Vue组件
目录
一、组件的概念
每一个组件都是一个vue实例
每个组件均具有自身的模板template,根组件的模板就是挂载点
每个组件模板只能拥有一个根标签
子组件的数据具有作用域,以达到组件的复用
二、根组件
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<p>{{ msg }}</p>
</div>
</body>
<script src="Vue_js/vue.js"></script>
<script>
/**
* 1、组件:由html、css、js三部分组成的独立单位,可以类似于变量,重复使用
* 2、组件其实就是vue实例(对象),一个组件就是一个vue实例(对象)
* 3、new Vue()产生的也是实例(对象),所以也是组件,我们称之为 根组件
* 一个页面建议只出现一个根组件(项目开发模式下,一个项目建议只出现一个根组件)
* 4、组件的html页面结构有 template 实例成员提供
* template提供的html结构是用来构虚拟DOM
* 真实DOM最终会被虚拟DOM替换
* 根组件一般不提供template,就由挂载点el来提供构建虚拟DOM的页面结构,根组件如果提供了template,还需要设置挂载点作为替换占位
* template模板有且只有一个根标签
*/
let c1 = '';
new Vue({
el: '#app',
data: {
msg: '12345', // 此时msg只会渲染Vue实例中自定义的虚拟的dom
c1: 'red'
},
template: `
<div id="app">
<p :style="{color: c1}">{{ msg }}</p>
<p @click="clickAction">{{ msg }}</p>
</div>
`,
methods: {
clickAction() {
this.msg='56789'
}
}
})
</script>
</html>
三、子组件
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>子组件</title>
</head>
<body>
<!--根组件的template-->
<div id="app">
<!--在根组件template中加载的组件,称之为根组件的子组件-->
<my-tag></my-tag>
<my-tag></my-tag>
<my-tag></my-tag>
<!--这里是我们定义的全局组件-->
<tag></tag>
</div>
</body>
<script src="js/vue.js"></script>
<script>
// 1、定义组件
// 2、注册组件
// 3、使用组件
// 如何定义子组件:组件就是一个普通对象,内部采用vue语法结构,被vue注册解释后,就会成为vue组件
let myTag = {
template: `
<div>
<h3>子组件</h3>
<p>我是自定义的子组件</p>
</div>
`,
};
// 了解:全局组件,不要注册就可以直接使用
Vue.component('tag', {
template: `
<div>
<h3>全局组件</h3>
<p>我是自定义的全局组件</p>
</div>
`,
});
new Vue({
el: '#app',
// 将上面自定义的dom对象,在Vue实例中注册
components: {
// 'my-tag': myTag,
// myTag: myTag,
myTag,
}
})
</script>
</html>
四、局部组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
user-select:none ;
}
.wrap{
width:calc(200px*4 + 100px);
margin: auto auto;
}
.imgs{
width: 200px;
height: 250px;
background-color: #dca7a7;
margin: 10px;
display: inline-block;
text-align: center;
}
img{
width: 200px;
}
</style>
</head>
<body>
<div id="app">
<div class="wrap">
<mytag></mytag>
<mytag></mytag>
<mytag></mytag>
<mytag></mytag>
</div>
</div>
</body>
<script src="Vue_js/vue.js"></script>
<script>
let mytag = {
template:`
<div class="imgs">
<img src="img/dog.jpg" alt="">
<p>品种:二哈</p>
// 这里的count是子组件中的定义的,所以要提前在子组件中声明,
<p @click="clickEvent" style="cursor: pointer">点击:{{count}}次</p>
</div>
`,
// 当子组件中有位置的变量的时候,会自动调用data这个方法
// 子组件中声明子组件的方式,data() 内部会返回count的值
data(){
return {
count:0
}
},
methods:{
clickEvent(){
this.count++
}
}
};
new Vue({
el:'#app',
components:{
mytag,
}
})
</script>
</html>
五、父子组件间传递数据
1. 父组件向子组件传递数据
通过绑定属性的方式进行数据传递
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
user-select:none ;
}
.wrap{
width:calc(200px*4 + 100px);
margin: auto auto;
}
.box{
width: 200px;
height: 300px;
background-color:#dca7a7;
margin:10px;
float: left;
text-align: center;
}
img{
width: 200px;
border-radius: 50%;
}
</style>
</head>
<body>
<div id="app">
<div class="wrap" >
<!--在根组件中用子组件,-->
<!--:pict就是用来标志,在子组件中接收的是哪一个值,他就是把父级组件中对应的每一次循环的list的dic传到子集组件-->
<mytag V-for="dic in list" :pict="dic"></mytag>
</div>
</div>
</body>
<script src="Vue_js/vue.js"></script>
<script>
// 定义一个全局的数组对象
let list = [
{title:'图片一号',img:'img/1.jpg'},
{title:'图片二号',img:'img/2.jpg'},
{title:'图片三号',img:'img/3.jpg'},
{title:'图片四号',img:'img/4.jpg'},
{title:'图片一号',img:'img/1.jpg'},
{title:'图片二号',img:'img/2.jpg'},
{title:'图片三号',img:'img/3.jpg'},
{title:'图片四号',img:'img/4.jpg'},
];
//自定义的子组件
let mytag = {
// prop 它就是利用反射的机制来接收父级组件传递过来的pict的值,通过字符串的形式
props:['pict'],
// 子组件在内部用了两个自己没有定义的数据属性(pict.img/pict.title)
template:`
<div class="box">
<img :src="pict.img" alt="">
<p>{{pict.title}}</p>
<p @click="clickEvent" style="cursor:pointer">点击:{{count}}次</p>
</div>
`,
//这是子组件的count数据的申明
// 固定语法:如果不是从父级组件传递来的数据,那就需要这样写
data(){
return{
//给count的初始值为0
count:0
}
},
//这是子组件中的事件发生触发用的
methods:{
clickEvent(){
this.count++
}
}
};
// 这里是根组件
new Vue({
el:'#app',
data:{
// 将上面全局的数组数据加载到Vue实例中
list,
},
components:{
mytag,
}
})
</script>
</html>
2. 子组件向父组件传递数据
通过发送事件请求的方式进行数据传递
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h2>{{msg}}</h2>
<!--这里的send_msg 就是我们自己注册的一个事件,当遇到子集组件中的this.emit的时候,会自动触发-->
<!--同时也需要在父级组件中去注册这个事件,methods中-->
<mytitle @send_msg="changeMsg"></mytitle>
</div>
</body>
<script src="Vue_js/vue.js"></script>
<script>
// 定义一个子组件
let mytitle={
// 给子组件的input标签设置v-model 监听事件
template:`
<input type="text" v-model="msg">
`,
// 先给msg一个初始值
data(){
return {
msg:''
}
},
// v-model的监听事件
watch:{
// 也就是我们设设置监听的msg变量
msg(){
// 当msg的值开始改变时,触发这个函数方法
// this.$emit 就是用来触发挂载点根模板的事件的,然后顺便把msg的值传过去
this.$emit('send_msg',this.msg)
}
}
};
new Vue({
el:'#app',
data:{
msg:'我正在等待接收子组件的值'
},
components:{
mytitle,
},
// 挂载点模板中的事件,用来接收自己模板的传送的数据的
methods:{
changeMsg(msg){
if (msg){
this.msg = msg
}
}
}
})
</script>
</html>
2. 平行组件之间传递数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>平行组件传值</title>
</head>
<body>
<div id="app">
<app1></app1>
<app2></app2>
</div>
</body>
<script src="Vue_js/vue.js"></script>
<script>
// 首先实例化一个公共得全局得Vue对象
let Bus = new Vue();
// 这里是第一个组件
Vue.component('app1', {
data() {
return {
msg: '我是平行组件的数据'
}
},
// 这个是第一个组件模板,他有一个点击事件,点击触发一个事件,讲自己的数据传递给与自己统计的组件
template:`<button @click="clickEvent">传递</button>`,
methods:{
clickEvent(){
// 这时候就用到了在上面定义的一个全局的Vue的Bus对象
// Bus.$emit('触发的一个事件名',传递过去的数据参数)
Bus.$emit('textmsg',this.msg)
}
}
});
// 这是第二个组件
Vue.component('app2', {
data() {
return {
text:'',
}
},
template:`<p">{{text}}</p>`,
// created() 这个方法是在当前组件呗创建的时候会自动调用
// 所以在创建之前,我们可以对该组件的数据进行处理
created(){
// 这里又调用了上面定义的全局的Bus对象的绑定的那个方法
// .$on('自己组件的一个方法,当其他组件向这个方法传数据的时候,会调用,')
// 并接收传过来的数据
Bus.$on('textmsg',function (val) {
console.log(val);
})
}
});
new Vue({
el: '#app',
})
</script>
</html>
六、slot内容分发
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>slot内容分发</title>
</head>
<body>
<div id="app">
<!--<mytag>我要替换</mytag>-->
<!--<mytag>我要替换</mytag>-->
<mytag>我要替换</mytag>
</div>
</body>
<script src="Vue_js/vue.js"></script>
<script>
let mytag = {
// slot就是说明p标签的文本内容可以在使用这个子组件的时候被替换
template:`
<!--<p>我是不可以被其他值替换掉的</p>-->
<p><slot>jfgj</slot></p>
`
};
new Vue({
el: '#app',
components:{
mytag,
}
})
</script>
</html>
七、组件的过滤器
过滤器就是给一个值进行额外的操作
1. 全局过滤器
Vue.filter('过滤器名',function([使用过滤器的数据变量]参数1,参数2,参数3){
一系列操作
返回·····
})
// 全局过滤器也可以写很多个
2. 局部过滤器
// 过滤器的参数,第一个val是使用这个过滤器的数据变量,后面所有的参数都是在时候过滤器的时候,手动传过来的
// 同样可以有多个过滤器的方法
filters: {
stringdate([使用过滤器的数据变量]参数1,参数2,参数3) {
一系列操作
返回······
}
}
3. 案例
以下是一个通过过滤器处理时间的案例
在这里我们会介绍一个moment.js的使用,这个moment.js他是一个专门用来处理时间格式的
详情http://momentjs.cn/,点击直接进行以下操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>全局过滤器</title>
</head>
<body>
<div id="app">
<mytag></mytag>
</div>
</body>
<script src="Vue_js/vue.js"></script>
//这里我是把这个js文件和Vue.js的文件放在一个文件夹中的,引入方式就是这样
<script src="Vue_js/moment.js"></script>
<script>
// 组件的全局过滤器
Vue.filter('string',function (time,str) {
// moment是一个处理事件的库
return moment(time).format(str)
});
let mytag = {
data() {
return {
time: new Date(),
ctime:new Date(),
}
},
template: `
<div>
<p>hello World</p>
// 这里使用的是全局过滤器
<p>{{time|string('YYYY-MM')}}</p>
// 这里使用的是局部过滤器
<p>{{ctime|stringdate('YYYY-MM-DD')}}</p>
</div>
`,
// 这是局部过滤器,里面可以写多个过滤器
// 过滤器的参数,第一个val是使用这个过滤器的数据变量,后面所有的参数都是在时候过滤器的时候,手动传过来的
filters: {
stringdate(ctime, str) {
return moment(ctime).format(str)
}
}
};
new Vue({
el: "#app",
components: {
mytag,
}
})
</script>
</html>