============================================================
component(组件)
ES6新语法:
`在这里写字符串可以直接换行`(tab上面的键)
组件最基本的使用:
1、创建组建构造器对象
2、注册组件
3、使用组件
组件化开发体验:
template 后面要接字符串
。
Vue.component(‘自定义标签名’,组件构造器对象名),
注册的是全局组件,意味着可以在多个vue的实例下面使用
<body>
<div id="app">
<my_cpn></my_cpn>
</div>
<div id="app1">//不在这个实例内部注册所以不能调用
<my_cpn></my_cpn>
</div>
<script>
//1、创建组件构造器对象
const cpnc=Vue.extend({
template : `
<div>
<h2>我是标题</h2>
<p>我是内容,5555</p>
<p>我也是内容,88888</p>
</div>
`
})
//2、注册组件(全局组件)
// Vue.component('my_cpn',cpnc)
const vm=new Vue({
el:'#app',
data:{
message:'dfsdfdsfds'
},
components:{//要加s
my_cpn:cpnc
}//注册局部组件
})
const vm2=new Vue({
el:'#app1',
})
</script>
</body>
子组件和父组件:
<body>
<div id="app">
<my_cpn></my_cpn>
</div>
</div>
<script>
//1、创建组件构造器对象
const cpnc1=Vue.extend({//子组件
template : `
<div>
<h2>我是标题</h2>
<p>我是内容,5555</p>
<p>我也是内容,88888</p>
</div>
`
})
const cpnc2=Vue.extend({//父组件
template : `
<div>
<h2>我是标题2</h2>
<p>我是内容2,2222</p>
<p>我也是内容2,2222222</p>
<diy></diy>
</div>
`,
components:{//因为第一个组件注册在了第二个组件构造器里面
diy:cpnc1
}
})
//2、注册组件(全局组件)
// Vue.component('my_cpn',cpnc)
//root,根组件
const vm=new Vue({
el:'#app',
data:{
message:'dfsdfdsfds'
},
components:{
my_cpn:cpnc2
}//注册局部组件
})
</script>
</body>
注册组件的语法糖:推荐使用
1、Vue为了简化这个过程,提供了注册的语法糖
2、主要省去了调用Vue.extend()的步骤,但是vue源码内部还是会使用extend方法,
而是可以直接使用一个对象来代替。
const vm=new Vue({
el:'#app',
data:{
message:'dfsdfdsfds'
},
components:{
my_cpn:{
template : `
<div>
<h2>我是标题2</h2>
<p>我是内容2,2222</p>
<p>我也是内容2,2222222</p>
<diy></diy>
</div>
`,
}
}//注册局部组件语法糖写法
})
template分离写法:
1、使用<template id="cpn2"></template>
标签
<template id="cpn2">
<div>
<h2>我是标题2</h2>
<p>我是内容2,2222</p>
<p>我也是内容2,2222222</p>
<diy></diy>
</div>
</template>
<script>
//2、注册组件(全局组件)
// Vue.component('my_cpn',cpnc)
const vm=new Vue({
el:'#app',
data:{
message:'dfsdfdsfds'
},
components:{
my_cpn:
{
template : '#cpn2'
}
}//注册局部组件
})
</script>
2、使用<script type="text/x-template" id="cpn2"></script>
标签
<script type="text/x-template" id="cpn2">
<div>
<h2>我是标题2</h2>
<p>我是内容2,2222</p>
<p>我也是内容2,2222222</p>
<diy></diy>
</div>
</script>
<script>
//2、注册组件(全局组件)
// Vue.component('my_cpn',cpnc)
const vm=new Vue({
el:'#app',
data:{
message:'dfsdfdsfds'
},
components:{
my_cpn:
{
template : '#cpn2'
}
}//注册局部组件
})
</script>
============================================================
组件不能访问vue实例中的data:
想存放组件中的数据,最好放在组件自己的data属性中:
1、组件对象有自己的data属性(也可以有methods等属性)
2、与实例的data属性不同,组件对象的属性必须是一个函数
3、而且这个属性是函数会返回一个栈空间,栈空间内部会创建很多变量
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
为什么设计组件的data要使用函数而不是对象?
1、因为函数是会返回一个栈空间,栈空间内部会创建很多变量,每个栈空间的内存地址不一样,当数据改变时,每个组件之间不会相互影响。
2、如果使用像实例一样的对象类型的话,会导致组件指向的都是同一个内存地址,当数据发生改变时会导致连锁反应,所有组件一起变化,后果影响很大。
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
用组件化开发实现计数器的复用:
<body>
<div id="app">
<computed_number></computed_number>//组件的调用
<computed_number></computed_number>
<computed_number></computed_number>
</div>
<template id="cpn">//模板分离写法
<div>//记得加上div标签封装
<h2>计算结果:{{count}}</h2>
<button @click="add()">+</button>
<button @click="sub()">-</button>
</div>
</template>
<script>
//注册全局组件
Vue.component('computed_number',{//用逗号
template:'#cpn',//用template绑定模板ID
data(){
return{//组件内部的data必须是函数,且值是返回值
count:0
}
},
methods: {//组件内部的方法
add(){
this.count++
},
sub(){
this.count--
}
},
})
const vm=new Vue({
el:'#app',
})
</script>
</body>
===============================================================
父子组件之间的通信:
1、通过props向子组件传递数据
2、通过事件向父组件发送消息
常用写法:
props:['cmovies']
//props是属性properties的简写,里面的是变量,用于接收父组件的数据
props:{
cmovies:Array}
//写成对象类型,可以进行类型验证
props:{
comvies:{
type:String,
default:’aaa‘,
required:true}//required:属性为true时要传进来值才能用
}
//当传入类型时字符串时可以直接写默认值
comvies:{
type:Array,
default(){
return [ ]
}}
//但是当数据类型是对象或者数组时,默认值必须是一个函数
//把接收值也写成对象类型,可以设置未处理时默认值
// !!!当传入类型时字符串时可以直接写默认值,但是当数据类型是对象或者数组时,默认值必须是一个函数
================================================================
以根组件为父组件,实现数据的传递:
<body>
<div id="app">
<mycpn :cmovies='movies'></mycpn>//外层绑定数据
</div>
<template id="mytemp">
<div>
<ul>
<li v-for="item in cmovies">{{item}}</li>
//模板写逻辑
</ul>
</div>
</template>
<script>
const cpn ={
template:'#mytemp',
//props:['cmovies']//props是属性properties的简写,里面的是变量,用于接收父组件的数据
//props:{
//cmovies:Array//写成对象类型,可以进行类型验证
//}
props:{
comvies:{
type:String
default:’‘//把数据也写成对象类型,可以设置未处理时默认值
}
}
const vm=new Vue({
el:'#app',
data:{
movies:['海贼王','海尔兄弟','海天堂','海王','海的味道']
},
components:{//记得加S
'mycpn':cpn
}
})
</script>
</body>
props更多写法:
===================================================================
父传子(props中的驼峰标识):
//当使用驼峰标识的时候要将大写字母改小写并且加上-。
写模板的时候要使用外层div包起来
<body>
<div id="app">
<submessage :sub-message="message"></submessage>
//当使用驼峰标识的时候要将大写字母改小写并且加上-
</div>
<template id="submessage">
<div>
<h2>{{subMessage}}</h2>
</div>
</template>
<script>
const SB={
template:'#submessage',
props:{
subMessage:{//这里就是需要绑定值的地方
type:Object,
default(){
return{}
}
}
}
}
const vm=new Vue({
el:'#app',
data:{
message:{
name:'小李',
age:'18',
height:175
}
},
components:{
'submessage':SB
}
})
</script>
</body>
====================================================================
组件通信:子传父:
categories(类别的意思)
$emit(发射的意思)
子传父:按钮例子
看注释:
<body>
<div id="app">
<btntest @diy-click="show"></btntest>//通过监听子组件的事件是否触发,来调用函数show,默认会传子组件发射的值,没有浏览器的event值
</div>
<template id="jingdong">
<div>
<button v-for="item in categories" @click="diyclick(item)">{{item.name}}</button>//模板接收到点击事件会触发diyclick(item)函数
</div>
</template>
<script>
const SB={
template:'#jingdong',
data(){//自组件的数据
return{
categories:[
{id:'111',name:'热门推荐'},
{id:'222',name:'数码产品'},
{id:'333',name:'母婴产品'},
{id:'444',name:'床上用品'}
]
}
},
methods:{
diyclick(item){
this.$emit('diy-click',item)
//模板因事件调用函数后会发射个自定义事件'diy-click',以及数据item
}
}
}
const vm=new Vue({
el:'#app',
data:{
},
components:{
'btntest':SB
},
methods:{
show(item){//最后被调用弹出item.name
alert(item.name)
}
}
})
</script>
</body>
===================================================================
模板内使用双向绑定v-model的时候不要直接绑定props的值,
因为还没赋值,要绑定注册子组件内data()的值
父子双向绑定实例:
看注释:
<body>
<div id="app">
<shuangxiang :number1="num1"
:number2="num2"
@numchange1="fathernumchange1"
@numchange2="fathernumchange2">//监听子组件发射的事件
</shuangxiang>
<p>结果1父data:{{num1}}</p>
<p>结果2父data:{{num2}}</p>
</div>
<template id="cmodel">
<div>
<p>结果1props:{{newnumber1}}</p>
<input type="text" :value="newnumber1" @input="numinput1">//这里要拆分v-model来获取event值
<p>结果2props:{{newnumber2}}</p>
<input type="text" :value="newnumber2" @input="numinput2">
</div>
</template>
<script>
const vm=new Vue({
el:'#app',
data:{
num1:0,
num2:1
},
methods:{
fathernumchange1(value){
this.num1=parseInt(value)//要把结果进行类型转换
},
fathernumchange2(value){
this.num2=parseInt(value)//一样
}
},
components:{
'shuangxiang':{
template:'#cmodel',
props:{
number1:Number,//第二个值只是限制类型的作用,这里相当于声明
number2:Number
},
data(){//记得要用data重新做一次赋值,否则会报错
return{
newnumber1:this.number1,
newnumber2:this.number2
}
},
methods: {
numinput1(event){
this.newnumber1=event.target.value
this.$emit('numchange1',this.newnumber1)
//当模板中监听到input事件时获取他的value,且发射一个事件给父组件来修改父组件的data值
},
numinput2(event){
this.newnumber2=event.target.value
this.$emit('numchange2',this.newnumber2)
//当模板中监听到input事件时获取他的value,且发射一个事件给父组件来修改父组件的data值
}
},
}
}
})
</script>
</body>
逻辑图:
父子组件的访问方式:
1、$children [index]
直接获取index所在的子组件,不常用
2、$refs
可以通过类似id一样给子组件赋一个ref=“”值来实现单独获取,常用90%
3、$parent
直接获取父组件数据,不常用
3、$root
直接获取根组件vue实例的数据,不常用
用法类似,调用时直接类似 this.$root.name