1、组件的使用方法
- 全局注册
Vue.component('my-component', {
template: '<div>我是一个组件</div>'
})
var app = new Vue({
el: '#app',
data: {
},
})
优点:所有的vue实例都可以用
缺点:权限太大,容错率降低
- 局部注册
var bpp = new Vue({
el: '#bpp',
components: { //注意这里的components是复数
'bpp-component': {
template: '<div>我是bpp里面的组件</div>'
}
},
data: {
}
- vue组件的模板在某些情况下会受到html标签的限制,比如
<table>
中只能有<tr>
,<td>
这些元素,所以直接在table中使用组件是无效的,此时可以使用is
属性来挂载组件
<table>
<tbody is="my-component"></tbody>
</table>
2、组件使用的小技巧
1、组件名字推荐使用小写字母加-进行命名,(必须)小写child, 或者my-componnet命名组件,不能出现大写形式。
2、 template中的内容必须被一个DOM元素包括 ,也可以嵌套使用
3、 在组件的定义中,除了template之外还有其他选项如:data、computed、methods
4、组件里面的data必须是一个方法形式
需求:实现两个按钮各自点击能实现加1,互不影响
<div id='app'>
<my-component></my-component>
<my-component></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'my-component': {
template: '<button @click="count++">{{count}}</button>',
data: function () {
return {
count: 0
}
}
},
}
})
</script>
3、使用props
传递数据(父亲向儿子传递数据)
- 在组件中使用
props
来从父亲组件接收参数,注意,在props
中定义的属性,都可以在组件中直接使用
<div id='app'>
<h5>我是父组件</h5>
<my-component msg='我是来自父组件内容'></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components:{
'my-component':{
props:['msg'],
template:'<div>{{msg}}</div>'
}
}
})
</script>
-
props
来自父级,而组件中data中return的数据就是组件自己的数据,两种情况作用域就是组件本身,可以在template
,computed
,methods
中直接使用。
3、可以使用v-bind
动态绑定父组件来的内容
<div id="app" style="border:1px solid red;height:150px">
<h5>我是父组件</h5>
<input type="text" v-model='parentmsg' style="border-bottom:10px">
<my-component v-bind:msg="parentmsg"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
parentmsg: '今天的太阳真热'
},
components: {
'my-component': {
props: ['msg'],
template: '<div style="border:1px solid green;height:50px">{{msg}}</div>'
}
}
})
</script>
image.png
3.props
的值有两种,一种是字符串数组,一种是对象,本节先只讲数组
<div id="app" style="border:1px solid red;height:150px">
<h5>我是父组件</h5>
<my-component msg=[3,6,9]></my-component>
<my-component :msg=[3,6,9]></my-component> //利用v-bind进行绑定
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'my-component': {
props: ['msg'],
template: '<div style="border:1px solid green;height:30px">
{{msg}}--{{msg.length}}</div>'
}
}
})
</script>
image.png
能看出来利用
v-bind
进行数组数据传输和没有v-bind
的区别,所以当我们进行数组数据传递时要绑定v-bind
,才能确保数组长度没有发生改变。
4、单向数据流
1、解释
: 通过 props 传递数据是单向的了, 也就是父组件数据变化时会传递给子组件,但是反过来不行。
2、目的
: 是尽可能将父子组件解稿,避免子组件无意中修改了父组件的状态。
3、应用场景
: 业务中会经常遇到两种需要改变 prop 的情况
场景一
:是父组件传递初始值进来,子组件将它作为初始值保存起来,在自己的作用域下可以随意使用和修改。这种情况可以在组件 data 内再声明一个数据,引用父组件的 prop
步骤一:注册组件
步骤二:将父组件的数据传递进来,并在子组件中用props接收
步骤三:将传递进来的数据通过初始值保存起来
<div id="app">
<my-component msg='我是父组件传递的数据'></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'my-component': {
props: ['msg'],
template: '<div>{{count}}</div>',
data: function () {
return {
//props中的值可通过this.xxx来获取
count: this.msg
}
}
}
}
})
</script>
场景二
:就是 prop 作为需要被转变的原始值传入。这种情况用计算属性就可以了
步骤一:注册组件
步骤二:将父组件的数据传递进来,并在子组件中用props接收
步骤三:将传递进来的数据通过计算属性进行重新计算
<div id="app">
<input type="text" v-model="width">
<my-component :width="width"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
width: 0
},
components: {
'my-component': {
props: ['width'],
template: '<div :style="style"></div>',
computed: {
style: function () {
return {
width: this.width + "px",
height: '30px',
background: 'red'
}
}
}
}
}
})
</script>
image.png
5、数据验证
vue组件中的camelCased(驼峰式)命名与kebab-case(短横线命名)规则
1、在html中, myMessage 和 mymessage 是一致的,,因此在组件中的html中使用必须使用kebab-case(短横线)命名方式。在html中不允许使用驼峰!!!!!!
2、在组件中, 父组件给子组件传递数据必须用短横线。在template中,必须使用驼峰命名方式,若为短横线的命名方式。则会直接保错。
3、 在组件的data中,用this.XXX引用时,只能是驼峰命名方式。若为短横线的命名方式,则会报错。
1、验证Number
类型
<div id="app">
<my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'my-component': {
props: {
a: Number,
},
template: '<div>{{a}}</div>',
},
},
data: {
a: 1,
}
})
</script>
2、验证String
类型
<div id="app">
<my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'my-component': {
props: {
a: String,
},
template: '<div>{{a}}</div>',
},
},
data: {
a: 'abc',
}
})
</script>
3、验证String
或Number
类型
<div id="app">
<my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'my-component': {
props: {
a: [Number,String]
},
template: '<div>{{a}}</div>',
},
},
data: {
a: 2, //或者改成字符串a:'qwe'都不会报错
}
})
</script>
4、验证Boolean
类型
<div id="app">
<my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'my-component': {
props: {
a: {
type:Boolean,
default:true, //布尔值,如果没有定义,默认值就是 true
},
},
template: '<div>{{a}}</div>',
},
},
data: {
a: true,
}
})
</script>
5、验证Number
类型是必传的
<div id="app">
<my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'my-component': {
props: {
a: {
type:Number,
required:true,
},
},
template: '<div>{{a}}</div>',
},
},
data: {
a: 111,
}
})
</script>
6、验证Array
类型
<div id="app">
<my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'my-component': {
props: {
a: {
type:Array,
default:function(){
return [555] //默认为数值[555]
}
},
},
template: '<div>{{a}}</div>',
},
},
data: {
a: [444],
}
})
</script>
7、验证Function
类型
<div id="app">
<my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'my-component': {
props: {
a: {
type:Function,
},
},
template: '<div>{{a}}</div>',
},
},
data: {
a: console.log(),
}
})
</script>
8、自定义一个验证函数
<div id="app">
<my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'my-component': {
props: {
a: {
validator:function(value){ //validator验证器名字
return value>22
}
},
},
template: '<div>{{a}}</div>',
},
},
data: {
a: 33,
}
})
</script>
6、组件通信
组件关系可分为父子组件通信、兄弟组件通信、跨级组件通信
6.1 自定义事件—子组件给父组件传递数据
使用v-on 除了监昕 DOM 事件外,还可以用于组件之间的自定义事件。JavaScript 的设计模式--观察者模式, dispatchEvent
和 addEventListener
这两个方法。 Vue 组件也有与之类似的一套模式,子组件用$emit()
来触发事件,父组件用$on()
来监昕子组件的事件 。
第一步:自定义事件
第二步: 在子组件中用$emit触发事件,第一个参数是事件名,后边的参数是要传递的数据
第三步:在自定义事件中用一个参数来接受来自子组件数据
<!-- 需求:通过加、减按钮实现子组件给父组件传递数据 -->
<div id="app">
你现在的总余额是{{total}}元
<son-component @change='handleTotal'></son-component> //change是自定义事件
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'son-component': {
template: '<div>\
<button @click=handleincrease>+</button>\
<button @click=handleruduce>-</button>\
</div>',
data: function () {
return {
count: 1000
}
},
methods: {
handleincrease: function () {
this.count = this.count + 1000,
this.$emit('change', this.count)
},
handleruduce: function () {
this.count = this.count - 1000,
this.$emit('change', this.count)
}
}
},
},
data: {
total: 1000,
},
methods: {
handleTotal: function (value) {
this.total = value
}
}
})
</script>
6.2 在组件中使用v-model
对比6.1中的例子使用v-model实现需求
<!-- 需求:通过加、减按钮实现子组件给父组件传递数据 -->
<div id="app">
你现在的总余额是{{total}}元
<son-component v-model='total'></son-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
components: {
'son-component': {
template: '<div>\
<button @click=handleincrease>+</button>\
<button @click=handleruduce>-</button>\
</div>',
data: function () {
return {
count: 1000
}
},
methods: {
handleincrease: function () {
this.count = this.count + 1000,
this.$emit('input', this.count)
},
handleruduce: function () {
this.count = this.count - 1000,
this.$emit('input', this.count)
}
}
},
},
data: {
total: 1000,
},
})
</script>
v-model 其实是一个语法糖,这背后其实做了两个操作
**v-bind 绑定一个 value 属性,实现动态更新
**v-on 指令给当前元素绑定 input 事件,指定触发事件名
要使用v-model,要做到:接收一个 value 属性,在有新的 value 时触发 input 事件
6.3 非父组件之间的通信
有时候两个组件也需要通信(非父组件),在简单的场景下,可以使用空的Vue实例作为中央事件总线进行。
1
var bus=new Vue()
2
//触发组件A中的事件
bus.$emit('id-selected',2)
3
//在组件B创建的钩子中监听事件
bus.$on('id-selected',function(){
.....
})
image.png
1、点击a组件向b组件传递数据(非父组件)
<div id="app">
<my-acomponent></my-acomponent>
<my-bcomponent></my-bcomponent>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
Vue.component('my-acomponent',{
template:'<div><button @click="handle">点我向b组件传递数据</button></div>',
data:function(){
return{
a:'我是来自a组件内容'
}
},
methods:{
handle:function(){
this.$root.bus.$emit('lalala',this.a)
}
}
})
Vue.component('my-bcomponent',{
template:'<div></div>',
created:function( ){
this.$root.bus.$on('lalala',function(value){
alert(value)
})
}
})
var app = new Vue({
el: '#app',
data: {
bus:new Vue(),
},
})
</script>
注意:这里通过this.$root
访问是根父组件的内容,而通过this.parent
访问的事最近一级父组件内容
2、点击子组件按钮修改父组件内容
<div id="app">
<my-acomponent></my-acomponent>
{{msg}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
Vue.component('my-acomponent',{
template:'<div><button @click="handle">点击我修改父亲的数据</button></div>',
methods:{
handle:function(){
this.$parent.msg='数据已修改'
}
}
})
var app = new Vue({
el: '#app',
data: {
msg:'数据未修改',
},
})
</script>
注意:这里通过this.parent
访问的事最近一级父组件内容
3、在父组件中拿到子组件的数据
Vue提供了为子组件提供索引的方法,用特殊的属性ref为其增加一个索引
<div id="app">
<my-acomponent ref='a'></my-acomponent>
<my-bcomponent ref='b'></my-bcomponent>
<button @click='getchilddata'>点击我拿到子组件的数据</button>
{{formchild}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
Vue.component('my-acomponent',{
template:'<div></div>',
data:function(){
return{
msg:'我是a中的msg'
}
},
})
Vue.component('my-bcomponent',{
template:'<div></div>',
data:function(){
return{
msg:'我是b中的msg'
}
},
})
var app = new Vue({
el: '#app',
data: {
formchild:'还未拿到数据'
},
methods:{
getchilddata:function(){
this.formchild=this.$refs.a.msg //注意这里是refs不是ref
}
}
})
</script>
注意:如果父组件有多个子组件不能通过this.$child
来获取子组件内容,而是通过给子组件添加索引,通过this.refs
获取
7、使用slot分发内容
7.1、什么是slot(插槽)
为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为内容分发。Vue.js 实现了一个内容分发 API,使用特殊的
slot
元素作为原始内容的插槽。
7.2、 编译的作用域
在深入内容分发 API 之前,我们先明确内容在哪个作用域里编译。假定模板为:
<child-component>
{{ message }}
</child-component>
message 应该绑定到父组件的数据,还是绑定到子组件的数据?答案是父组件。
组件作用域简单地说是:
父组件模板的内容在父组件作用域内编译;
子组件模板的内容在子组件作用域内编译。
7.3 、插槽的用法
父组件的内容与子组件相混合,从而弥补了视图的不足
1、单个插槽:
<div id="app">
<my-component>
<p>我是父组件的内容</p> //这是父组件插入的内容
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
Vue.component('my-component',{
template:'<div>\
<slot>\
如果父组件没有插入内容,我就作为默认值出现\
</slot>\
</div>',
})
var app = new Vue({
el: '#app',
data: {},
})
</script>
2、具名插槽
<div id="app">
<my-component>
<h3 slot=header>标题</h3> //标记
<p>内容</p>
<p slot=footer>结尾</p>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
Vue.component('my-component', {
template: '<div>\
<div class="header">\
<slot name="header">\ //关联
</slot>\
</div>\
<div class="container">\
<slot>\
</slot>\
</div>\
<div class="footer">\
<slot name="footer">\
</slot>\
</div>\
</div> ',
})
var app = new Vue({
el: '#app',
data: {},
})
</script>
7.4 、作用域插槽
作用域插槽是一种特殊的slot,使用一个可以复用的模板来替换已经渲染的元素
------从子组件获取数据
------template模板是不会被渲染的
<div id="app">
<my-component>
<template slot="abc" slot-scope="prop">
{{prop.text}}
{{prop.ss}} //子组件中的name中数据是关联用得,不能通过这样获取
</template>>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
Vue.component('my-component', {
template: '<div>\
<slot text="我是子组件的数据" ss="sdfsd" name="abc">\
</slot>\
</div> ',
})
var app = new Vue({
el: '#app',
data: {},
})
</script>
7.5、 访问slot
通过this.$slots.(NAME)
<div id="app">
<my-component>
<h3 slot=header>标题</h3>
<p slot=footer>结尾</p>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
Vue.component('my-component', {
template: '<div>\
<div class="header">\
<slot name="header">\
</slot>\
</div>\
<div class="footer">\
<slot name="footer">\
</slot>\
</div>\
</div> ',
mounted:function(){
var header=this.$slots.header
var text=header[0].elm.innerText //由DOM结构得来
console.log(header) //查看DOM结构
console.log(text)
}
})
var app = new Vue({
el: '#app',
data: {},
})
</script>
7.6、 组件高级用法–动态组件
VUE给我们提供 了一个元素叫
component
作用是: 用来动态的挂载不同的组件
实现:使用is特性来进行实现动态组件
1、需求:通过点击不同按钮切换不同视图
<div id="app">
<component :is=thisview></component>
<button @click="handleview('A')">第一句</button>
<button @click="handleview('B')">第二句</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
Vue.component('compA', {
template:'<div>山不在高<div>'
})
Vue.component('compB', {
template:'<div>有仙则名<div>'
})
var app = new Vue({
el: '#app',
data: {
thisview:'compA',
},
methods:{
handleview:function(tag){
this.thisview='comp'+tag
}
}
})
</script>
网友评论