为什么要使用组件
代码的复用性
组件的使用方法
1.全局注册
Vue.component('my-component',{
template:'<div>我是组件的内容</div>'
})
优点:所有的nue实例都可以用
缺点:权限太大,容错率降低
2.局部注册
var app = new Vue({
el:'#app',
components:{
'my-component':{
template: '<div>我是组件的内容</div>'
}
}
})
- vue组件的模板在某些情况下会受到html标签的限制,比如 <table> 中只能还
有 <tr> , <td> 这些元素,所以直接在table中使用组件是无效的,此时可以使用is属
性来挂载组件
<table>
<tbody is="my-component"></tbody>
</table>
组件使用的技巧
- 推荐使用小写字母加进行命名(必须) child, mycomponnet命名组件
- template中的内容必须被一个DOM元素包括 ,也可以嵌套
- 在组件的定义中,除了template之外的其他选项—data,computed,methods
- data必须是一个方法
var app = new Vue({
el: '#app',
components: {
"app-component": {
template: '<div>我是app局部注册的一个组件</div>'
},
'btn-component': {
template: '<button @click="count++">{{count}}</button>',
data: function () {
return {
count: 0
}
}
}
},
}
})
在data中定义一个方法返回的对象可以是一个component
父组件向子组件儿子传递数组
- 在组件中使用props来从父亲组件接收参数,注意,在props中定义的属性,都可以在组件中直接使用
- propps来自父级,而组件中data return的数据就是组件自己的数据,两种情况作用域就是组件本身,可以在template,computed,methods中直接使用
<div id="app" style='border: 2px solid blue;height: 400px;'>
<h5 style="text-align: center;">我是父组件</h5>
<child-component msg="我是来自父组件的内容"></child-component>
<hr>
</div>
var app = new Vue({
el: '#app',
data: {
parentmsg: '今天月亮真圆'
},
components: {
'child-component': {
props: ['msg'],
template: '<div style="border: 2px solid red;height: 80px">{{msg}}</div>',
data: function () {
return {
count: 1
}
}
}
})
- props的值有两种,一种是字符串数组,一种是对象,本节先只讲数组
- 可以使用vbind动态绑定父组件来的内容
<div id="app" style='border: 2px solid blue;height: 400px;'>
使用v-bind进行数据的动态绑定,把input中的msg传递给子组件
<input type="text" v-model="parentmsg">
<bind-component v-bind:msg='parentmsg'></bind-component>
</div>
var app = new Vue({
el: '#app',
data: {
parentmsg: '今天月亮真圆'
},
components: {
'bind-component': {
props: ['msg'],
template: '<div style="border: 2px solid red;height: 80px">{{msg}}</div>',
data: function () {
return {
count: 1
}
}
}
}
})
单项数据流
解释 : 通过 props 传递数据 是单向的了, 也就是父组件数据变化时会传递给子组
件,但是反过来不行。
目的 :是尽可能将父子组件解稿,避免子组件无意中修改了父组件的状态。
应用场景: 业务中会经常遇到两种需要改变 prop 的情况
一种是父组件传递初始值进来,子组件将它作为初始值保存起来,在自己的作用域
下可以随意使用和修改。这种情况可以在组件 data 内再声明一个数据,引用父组件
的 prop
步骤一:注册组件
步骤二:将父组件的数据传递进来,并在子组件中用props接收
步骤三:将传递进来的数据通过初始值保存起来
<my-component msg="我是父组件传递的数据"></my-component>
Vue.component('my-component', {
props: ['msg'],
template: '<div>{{count}}</div>',
data: function () {
return {
// props中的值可以通过this.xxx直接获取
count: this.msg
}
}
})
var app = new Vue({
el: '#app',
data: {
width: 0
}
})
另一种情况就是 prop 作为需要被转变的原始值传入。这种情况用计算属性就可以了
步骤一:注册组件
步骤二:将父组件的数据传递进来,并在子组件中用props接收
步骤三:将传递进来的数据通过计算属性进行重新计算
<input type="text" v-model='width'>
<width-component :width='width'></width-component>
Vue.component('width-component', {
props: ['width'],
template: '<div :style="style"></div>',
computed: {
style: function () {
return {
width: this.width + 'px',
background: 'red',
height: '60px'
}
}
}
})
数据验证
命名规则
@ 在html中, myMessage 和 mymessage 是一致的,,因此在组件中的html
中使用必须使用kebabcase(短横线)命名方式。在html中不允许使用驼
峰!!!!!!
@ 在组件中, 父组件给子组件传递数据必须用短横线。在template中,必
须使用驼峰命名方式,若为短横线的命名方式。则会直接保错。
@ 在组件的data中,用this.XXX引用时,只能是驼峰命名方式。若为短横线
的命名方式,则会报错。
数据验证
验证的 type 类型可以是:
• String
• Number
• Boolean
• Object
• Array
• Function
<type-component :a="a" :b='666' :c="c" :d='d' :f='f' :g='g'></type-component>
Vue.component('type-component', {
props: {
a: String,
b: [String, Number],
c: {
type: Boolean,
default: true //默认值
},
d: {
type: String,
required: true
},
e: {
type: Array,
default: function () {
return [666];
}
},
f: {
validator: function (value) {
return value > 10
}
},
g: {
type: Function
}
},
template: '<div>{{a}}--{{b}}--{{c}}--{{d}}--{{e[0]}}</div>',
data: function () {
return {
abc: this.myMsg
}
}
})
var app = new Vue({
el: '#app',
data: {
a: "1",
b: "666",
c: "",
d: "32423",
e: [],
f: 88,
g: console.log(123)
}
})
组件通信
子组件给父组件传递数据
第一步:自定义事件
第二步: 在子组件中用$emit触发事件,第一个参数是事件名,后边的参数是要传递的数据
第三步:在自定义事件中用一个参数来接受
<div id="app">
您现在的银行卡余额是{{total}}
<son-component @change='handleTotal'></son-component> //第一步:自定义事件
</div>
Vue.component('son-component', {
template: '<div>\
<button @click="handleincrease">+1000</button>\
<button @click="handlereduse">-1000</button>\
</div>',
data: function () {
return {
count: 1000
}
},
methods: {
handleincrease: function () {
this.count = this.count + 1000
this.$emit('change', this.count) //第二步: 在子组件中用$emit触发事件,第一个参数是事件名,后边的参数是要传递的数据
},
handlereduse: function () {
this.count = this.count - 1000
this.$emit('change', this.count) //第二步: 在子组件中用$emit触发事件,第一个参数是事件名,后边的参数是要传递的数据
},
}
})
var app = new Vue({
el: '#app',
data: {
total: 2000
},
methods: {
handleTotal: function (value) {
//第三步:在自定义事件中用一个参数来接受
this.total = value
}
}
})
在组件中使用v-model
v-model其实就是绑定了input事件,当触发input时候,input事件就会自动接受传递过来的参数,并赋值给已经绑定的total
vmodel 其实是一个语法糖,这背后其实做了两个操作
- vbind 绑定一个 value 属性
- von 指令给当前元素绑定 input 事件
要使用vmodel,要做到: - 接收一个 value 属性。
- 在有新的 value 时触发 input 事件
<son-component v-model='total'></son-component> //接收一个 value 属性。
Vue.component('son-component', {
template: '<div>\
<button @click="handleincrease">+1000</button>\
</div>',
data: function () {
return {
count: 1000
}
},
methods: {
handleincrease: function () {
this.count = this.count + 1000
this.$emit('input', this.count) //在有新的 value 时触发 input 事件
}
}
})
var app = new Vue({
el: '#app',
data: {
total: 2000
}
})
非父组子件之间的通信
子组件之间的通信
<div id="app">
<my-acomponent ref='a'></my-acomponent>
<my-bcomponent ref='b'></my-bcomponent>
</div>
<script>
Vue.component('my-acomponent',{
template:'<div><button @click="handle">点击我向B组件传递数据</b
utton></div>',
data:function () {
return{
aaa:'我是来自A组件的内容'
}
},
methods:{
handle:function () {
this.$root.bus.$emit('lala',this.aaa);
}
}
})
Vue.component('my-bcomponent',{
template:'<div></div>',
created:function () {
//A组件在实例创建的时候就监听事件---lala事件
this.$root.bus.$on('lala',function (value) {
alert(value)
});
}
})
父链:this.$parent
Vue.component('child-component',{
template:'<button @click="setFatherData">通过点击我修改父亲的数
据</button>',
methods:{
setFatherData:function () {
this.$parent.msg = '数据已经修改了'
}
}
})
子链:this.$refs
提供了为子组件提供索引的方法,用特殊的属性ref为其增加一个索引
var app = new Vue({
el:'#app',
data:{
//bus中介
bus:new Vue(),
msg:'数据还未修改',
formchild:'还未拿到'
},
methods:{
getChildData:function () {
//用来拿子组件中的内容 ---- $refs
this.formchild = this.$refs.c.msg;
}
}
})
插槽
编译的作用域
父组件模板的内容在父组件作用域内编译;
子组件模板的内容在子组件作用域内编译。
Vue.component('my-component', {
template: '<div v-show="childshow">我是一个组件</div>',
data: function () {
return {
message: '我是子组件的内容',
childshow: false
}
}
})
var app = new Vue({
el: '#app',
data: {
message: '我是父组件的内容',
childshow: true
}
})
<div id="app">
<my-component>
</my-component>
</div>
无法得到子组件的内容,因为子组件的childshow为false
插槽的用法
单个插槽的用法
混合父组件的内容和子组件的模板
<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>
具名插槽的用法
<name-component>
<h3 slot='header'>我是标题</h3>
<h3 slot='header'>我是副标题</h3>
<p>我是正文内容</p>
<p>正文内容有两段</p>
<p slot="footer">我是底部信息</p>
</name-component>
Vue.component('name-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>',
})
作用域插槽
从子组件中获取数据
<div id="app">
<my-component>
<!-- <template slot='abc' slot-scope='prop'>
{{prop.text}}
{{prop.ss}}
</template> -->
<p slot='abc' slot-scope='prop'>
{{prop.text}}
{{prop.ss}}
</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 text="我是来自子组件的数据" ss="fdk" name="abc">\
</slot>\
</div>',
})
var app = new Vue({
el: '#app',
data: {}
})
</script>
访问slot的方式
通过this.$slots.(NAME)
<div id="app">
<my-component>
<p>我是父组件插入的内容</p>
</my-component>
<hr>
<name-component>
<h3 slot='header'>
<span>
我是标题
</span>
</h3>
<h3 slot='header'>我是副标题</h3>
<p>我是正文内容</p>
<p>正文内容有两段</p>
<p slot="footer">我是底部信息</p>
</name-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>',
})
Vue.component('name-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>',
mounted: function () {
//访问插槽
var header = this.$slots.header;
var text = header[0].elm.innerText;
var html = header[0].elm.innerHTML;
console.log(html)
console.log(text)
console.log(header)
}
})
var app = new Vue({
el: '#app',
data: {}
})
</script>
组件的高级用法--动态组件
VUE给我们提供 了一个元素叫component
作用是: 用来动态的挂载不同的组件
实现:使用is特性来进行实现的
<div id="app">
<component :is="thisView">
</component>
<button @click="handleView('A')">第一句</button>
<button @click="handleView('B')">第二句</button>
<button @click="handleView('C')">第三句</button>
<button @click="handleView('D')">第四句</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>',
})
Vue.component('compC', {
template: '<div>野花烧不尽</div>',
})
Vue.component('compD', {
template: '<div>春风吹又生</div>',
})
var app = new Vue({
el: '#app',
data: {
thisView: "compA"
},
methods: {
handleView: function (tag) {
this.thisView = 'comp' + tag
}
}
})
</script>