Vue
组件
组件注册
全局组件
<body>
<div id="app">
<b>这是一个html中的b标签</b>
<!-- 这里面将存放一个全局组件 -->
<hr>
<aa></aa>
<hr>
<aa-1></aa-1>
<!--PascalCase写法使用时必须使用kebab-case来获取 这里获取不到-->
<hr>
<AaAa2></AaAa2>
<hr>
<!--正确的引用方式-->
<aa-aa2></aa-aa2>
</div>
</body>
全局组件注册:
Vue.component
(‘需要注册的组件名’,{
“选项对象”
});
注意事项:
- 注册全局组件时 V需要同
Vue
实例一样 必须大写 且要放在Vue
实例之前 - 全局组件只能在
Vue
根实例绑定的标签内中使用
<script src="/lib/vue-2.6.12.js"></script>
<script>
// Vue.component('组件名',{"选项对象"})
Vue.component('aa', {
template: `<b>这是一个全局组件的b标签</b>`
})
// kebab-case写法
Vue.component('aa-1', {
template: `<b>这是kebab-case全局组件的定义放式</b>`
})
// PascalCase写法
Vue.component('AaAa2', {
template: `<b>这是PascalCase全局组件的定义放式</b>`
})
new Vue({
el: '#app',
});
</script>
全局组件命名规则及获取方式
命名规则
// kebab-case写法
Vue.component('aa-1', {
template: `<b>这是kebab-case全局组件的定义放式</b>`
})
// PascalCase写法
Vue.component('AaAa2', {
template: `<b>这是PascalCase全局组件的定义放式</b>`
})
获取方式
注意:
无论哪种命名方式 在body中获取时都只能采用kebab-case
方式进行获取 因为html
不区分大小写PascalCase
方式获取不到
<!--PascalCase写法使用时必须使用kebab-case来获取 这里获取不到-->
<hr>
<AaAa2></AaAa2>
<hr>
<!--正确的引用方式-->
<aa-aa2></aa-aa2>
组件内容描述
组件选项
template选项
用来设置组件结构最终可以被引入根实例或者其他组件中
// template选项用来设置组件结构 最终可以被引入根实例或者其他组件之中
Vue.component('aa1', {
template: `<b>这是第b一个组件</b>`
});
template选项注意事项
template
中不能有平级的根实例 如果有多个平级的div 只会显示第一个div
Vue.component('aa2', {
template: `
<div>
<b>这是组件内div中的第一个b的标签</b>
<b>这是组件内div中的第二个b的标签</b>
</div>
`
});
Vue.component('aa3', {
template: `
<div>
<b>这是第一个div中的b</b>
</div>
<div>
<b>这是第二个div中的b</b>
</div>
`
});
##### data选项
用来存储组件中的数据
与根实例data不同的是 组件中的data选项必须设置为函数 数据设置在返回值对象中
为什么组件data选项使用函数写法?
**使用函数的目的是因为data中定义的每个变量都是独立的存在 **
用来保证每个实例都有独立选项 其中一个发生改变 其他不受影响
<aa4></aa4>
<hr>
<b1></b1>
<hr>
<b1></b1>
<hr>
<b1></b1>
Vue.component('b1', {
template: '<b>{{age}}</b>',
data: function () {
return {
age: Math.floor(Math.random() * 100 + 1) // 年龄随机,每个实例的年龄都不相同
}
}
})
Vue.component('aa4', {
template: `
<b>{{name}}</b>
`,
data: function () {
return {
name: 'aa'
}
}
})
如下图所示 三个随机数数据由data产生 每个实例都是独立的互不影响
局部组件
局部组件定义方式
直接书写组件选项
new Vue({
el: '#app',
....
components: {
'组件名': {/*组件选项*/},
'组件名': {/*组件选项*/},
....
}
单独配置组件选项
// 单独配置组件的选项对象
let aa = {/*组件选项*/};
new Vue({
el: '#app',
components: {
'组件名': aa
}
});
全局组件与局部组件区别
- 全局注册的组件能够被所有的根实例所使用
- 局部注册的组件只能够在当前根实例中使用
<div id="app">
<aa-bb></aa-bb>
<aa-cc></aa-cc>
</div>
<hr/>
<div id="app2">
<aa-cc></aa-cc>
<!-- 这里看不到效果,因为局部组件注册到了app中 -->
<aa-bb></aa-bb>
<!-- 全局组件在这里可以使用 因为全局组件能够被所有实例使用 -->
</div>
<script src="../js/vue.min.js"></script>
<script>
Vue.component('aa-bb',{
template: '<b>全局组件</b>'
});
new Vue({
el: '#app',
components: {
'aa-cc': {
template: '<b>局部组件</b>'
}
}
});
new Vue({
el: '#app2'
});
</script>
组件通信
父组件向子组件传值
通过子组件的props选项接收父组件的值
注意事项:
- 子组件的props选项中不要存在与子组件中的data中同名选项
- props是一个数组形式 其中的值(prop)可以看成是组件(自定义标签的属性)
- 父子组件中的prop所有prop都是单向绑定的 只能由父组件向子组件传值
- 动态绑定以:prop 或者
v-bind:prop
命名 (prop是在props中定义的值)在此处相当于 id name 等
<body>
<!-- 父组件 -->
<div id="app">
<!-- 三个子组件 -->
<!-- 静态内容写法 -->
<aa id="2" name="张三" did="20" dname="销售部"></aa>
<hr>
<!-- 动态绑定写法 传递静态内容 -->
<aa v-bind:id="3" name="李四" did-="30" dname="财务部"></aa>
<hr>
<!-- 动态绑定写法 父组件给子组件传值 -->
<aa :id="id" :name="name" :did="dept.id" :dname="dept.dname"></aa>
</div>
</body>
<script src="/lib/vue-2.6.12.js"></script>
<script>
Vue.component('aa', {
props:['id','name','did','dname'],
template: `
<div>
<b>编号:{{ id }}</b><br/>
<b>姓名:{{ name }}</b><br/>
<b>部门编号:{{ did }}</b><br/>
<b>部门名称:{{ dname }}</b>
</div>
`
});
new Vue({
el: '#app',
data: {
id: 1,
name: '王五',
dept: {
id: 10,
dname: '研发部'
}
}
});
</script>
props命名规则
- 建议prop的命名使用
camelCase
方式 父组件绑定时使用kebab-case
方式 - 因为在props中定义是属于
javaScript
中的 区分大小写 - 页面中是属于
html
范畴的 不区分大小写
子组件向父组件传值
子组件通过自定义事件的方式向父组件传值
<body>
<div id="app">
<b>{{number1}}</b>
<aa @ff="addNumber1()"></aa>
</div>
</body>
<script src="/lib/vue-2.6.12.js"></script>
<!-- 子组件通过自定义事件向子组件传值 -->
<!--
子组件通过事件向父组件传值
1、当点击子组件的+1按钮时,触发了函数 addNumber2
2、在函数 addNumber2 中执行了子组件变量 number2 自增和触发了自定义事件 ff
3、@ff 事件触发后执行了函数 addNumber1 自增了 number1的值
-->
<script>
// 第一个组件,当这个组件文本框的值发生改变时 ,将文本框的值传递给父组件
Vue.component('aa', {
data() {
return {
number2: 1
}
},
template: `
<div>
<b>{{ number2 }}</b>
<button @click="addNumber2">+1</button>
</div>
`,
methods: {
addNumber2() {
// 触发自定义事件 ff
this.$emit('ff');
this.number2++;
}
}
});
new Vue({
el: '#app',
data() {
return {
number1: 1
}
},
methods: {
addNumber1() {
this.number1++;
}
}
});
</script>
注:
- 实现方式其实就是在页面加载后显示子组件内容
- 点击子组件按钮 调用子组件
addNumber2
事件 在子组件addNumber2
触发自定义事件ff
让子组件中数据++ - 触发事件后 父组件数据调用 自身事件 实现逻辑
子组件向父组件传值的具体实现
在上面的案例中、是通过调用事件实现逻辑的 下面将演示如何触发事件的同时实现参数传递
<div id="app">
传递过来的值:{{ num3}}
</div>
//传值
Vue.component('a-a3', {
template: `
<div>
<input @input="addNumber2">
</div>
`,
methods: {
// 第一个值为当前文本框值 和一个常量字符串
addNumber2(e) {
console.log(e)
this.$emit('ff2', e.target.value, 'aa');
}
}
});
new Vue({
el: '#app',
data() {
return {
num3: ''
}
},
methods: {
pastNum(a, b) {
console.log(a)
this.num3 = a + ',' + b;
},
}
});
具体实现方式:
- 在页面加载后显示了子组件内容 当文本框中输入内容后 调用子组件事件
addNumber2
- 子组件事件内调用自定义事件
ff2
并传递两个值 第一个值为当前文本框值 第二个值为一个常量字符串 - 在父组件内 接收两个值 并赋给
num3
实现数值传递
事件调用注意事项:
Vue
中事件绑定加括号和不加括号区别
@click="fun"
不带括号 不写实参时 默认方式 默认会传递 event(事件对象)@click="fun(value)"
只要带括号 无论是否传值 都属于传递实参给函数 event(事件对象接收不到)- 如果需要实参 又需要event(事件对象)、就需要手动传入event(事件对象)
@click=“fun($event, value)”
兄弟组件传值
实现方式其实就是利用之前的两个知识 先使用子组件给父组件传值 然后父组件给子组件传值
<div id="app">
组件1
<a-a1 @ff="change01"></a-a1>
<br>
父组件:{{value}}<br />
第二个组件
<a-a2 :value02="value"></a-a2>
</div>
<script src="/lib/vue-2.6.12.js"></script>
<script>
//第一个组件 当这个组件的文本框的值发生改变时 将文本框的值传给父组件
Vue.component('a-a1', {
data() {
return {
value01: 'a'
}
},
template: `
<div>
<input v-model="value01"/>
<button @click="changeComponent">点击我</button>
</div>
`
,
methods: {
changeComponent() {
// 触发了ff事件 并将value的值传递出去了
this.$emit('ff', this.value01)
}
}
});
//第二个组件 负责接收父组件传递过来的值
Vue.component('a-a2', {
props: ['value02'],
template: `
<div>
{{value02}}
</div>
`
});
new Vue({
el: '#app',
data: {
value: '原始的值'
},
methods: {
change01(a) {
// 将传递过来的参数赋予变量value
this.value = a;
}
}
});
</script>
EventBus
传值
说明:
- 在之前的传值方式中 如果组件关系比较复杂 根据之前的知识 值传递起来也会比较复杂
- 组件数据中转过程中 data 中会存在 许多与当前组件功能无关的数据
EventBus
(事件总中心) 是一个独立的事件中心 可以管理不同组件传值问题
优点:
-
组件和组件之间不需要设置多余的 data 数据。
-
组件和组件不需要找到之间的关系,只需要
EventBus
中心中进行处理就行。 -
EventBus
仅仅存储的用来进行传值操作的事件功能 而不会进行存储操作 只是一个中转站 - -
Vue
通过创建一个新的Vue
实例来管理组件传值操作,组件通过给实例注册事件、调用事件来实现数据传递
// EventBus 通过一个新的 Vue 实例来管理,新的 Vue 实例不需要设置事件选项。空的 Vue 实例。
let bus = new Vue();
实现步骤:
- 发送数据的组件触发 bus 事件,接收的组件给 bus 注册对应事件。
- 接收事件的组件给 bus 注册对应事件通过 $on() 操作。
注意事项:
//传值的组件中
函数(){
bus.$emit('事件名',参数列表);
}
// 接收的组件中 一般写入到组件选项的 created 中
created(){
bus.$on('事件名',(参数列表)=>{函数体});
}
具体实现:
<body>
<div id="app">
<a-a1></a-a1>
<hr>
<a-a2></a-a2>
</div>
</body>
<script src="/lib/vue-2.6.12.js"></script>
<script>
let bus = new Vue();
Vue.component('a-a1', {
data() {
return {
count: 1
}
},
template: `
<div>
<p>{{ count }}</p>
<button @click="changeCount">+1</button>
</div>
`,
methods: {
changeCount() {
this.count++;
bus.$emit('ff', this.count)
}
}
});
Vue.component('a-a2',{
data(){
return{
count:1
}
},
template:`
<b>{{count}}</b>
`,
created(){
bus.$on('ff',(yourCount)=>{
this.count=yourCount
})
}
});
new Vue({
el: '#app'
});
</script>
组件插槽
快捷的设置组件内容
单个插槽
说明:
- 组件标签可以像 HTML 标签一样设置内容,那么组件的使用灵活度会很高。
- 但是问题在于 如果在html中书写组件内容 自定义组件内容会被抛弃
- 如果需要组件内部生效 就需要使用组件插槽实现可以通过 进行插槽设置。
- 代表的是组件的内容区域, 标签内部书写的内容会自动替换 位置的内容,
- 这样在多次使用 自定义标签时,可以传递不同的内容来达到快速传值的目的。
- 有点像我们在 Java 中学习的占位符效果, 就是占位符,自定义中的内容就是要传递的值。
<body>
<div id="app">
<!-- 组件插槽可以快捷的设置组件内容。 -->
<!--组件-->
<a-a1>我是一个内容</a-a1>
<hr>
<a-a1>
另一段内容<br />
<span>组件的主体内容</span>
</a-a1>
<hr>
<a-a1>
<!--只能获取到父组件的 data 数据-->
{{content}}
</a-a1>
</div>
</body>
<script src="/lib/vue-2.6.12.js"></script>
<script>
Vue.component('a-a1', {
template: `
<div>
<b>我是组件的内容</b>
<slot>我是插槽的默认值</slot>
</div>
`
});
new Vue({
el: '#app',
data() {
return {
content: 1
}
},
});
</script>
具名插槽
如果组件中由多个位置需要设置插槽 需要给设置name 这种具有名称的插槽,称为具名插槽
<body>
<div id="app">
<a-a1>
<!--template标记没有其他作用 就是标识当前内容是赋予那个slot。v-slot:名字-->
<template v-slot:top>
{{title}}
</template>
<template v-slot:default>
{{content}}
</template>
<template v-slot:bottom>
{{bottom}}
</template>
<hr>
<!-- 具名插槽缩写形式 -->
<!-- <template #top>
{{title}}
</template>
{{content}}
<template #bottom>
{{bottom}}
</template> -->
</a-a1>
</body>
<script src="/lib/vue-2.6.12.js"></script>
<script>
Vue.component('a-a1', {
template: `
<div>
<h1>我是头部部分</h1>
<slot name="top"></slot>
<h1>我是中间部分</h1>
<slot>我的默认名字是default</slot>
<h1>我是底部部分</h1>
<slot name="bottom"></slot>
</div>
`});
new Vue({
el: '#app',
});
</script>
作用域插槽
特点:
- 解决之前插槽中只能使用父组件data数据
- 能够在插槽中使用子组件data数据
- 组件将需要被插槽使用的数据通过 v-bind:要传递的变量名=“要传递的变量名” 绑定给
- 这种用于给插槽传递数据的属性称为插槽 prop
<body>
<div id="app">
<guanwei>
<!--gwObj是子组件的实例 可以通过子组件的实例获取数据-->
<template v-slot:default="gwObj12">
父组件内容:{{content}}<br/>
子组件内容:{{gwObj12.content}}
</template>
</guanwei>
</div>
</body>
<script src="/lib/vue-2.6.12.js"></script>
<script>
Vue.component('guanwei', {
template: `
<div>
<h3>v-bind:变量名绑定要使用的数据 前后 content 建议一致</h3>
<h4>第一个 content 是我们起的名称供 template 调用,第二个是 变量名</h4>
<slot v-bind:content="content"></slot>
</div>
`,
data() {
return {
title: '子组件的标题',
content: '子组件的内容'
}
}
});
new Vue({
el: '#app',
data: {
title: '父组件的标题',
content: '父组件的内容'
}
});
</script>
内置组件
动态组件
特点:
- 动态适用于多个组件的频繁切换处理
- 用于将一个"元组件" 渲染为动态组件 以is属性值决定渲染哪个组件 类似于v-if v-show的效果
<body>
<div id="app">
<!--注意这里组件名如果是常量字符串 必须加入''-->
<!-- 实现多个组件快速切换 -->
<component :is="name">{{name}}</component>
<br>
<button @click="changeName('a-a1')">a-a1</button>
<button @click="changeName('a-a2')">a-a2</button>
<button @click="changeName('a-a3')">a-a3</button>
</div>
</body>
<script src="/lib/vue-2.6.12.js"></script>
<script>
Vue.component('a-a1', { template: '<div><b>这是第一个组件</b><slot></slot></div>' })
Vue.component('a-a2', { template: '<div><b>这是第二个组件</b><slot></slot></div>' })
Vue.component('a-a3', { template: '<div><b>这是第三个组件</b><slot></slot></div>' })
// Vue根实例
new Vue({
el: '#app',
data: {
name: 'ff01'
},
methods: {
changeName(n) {
this.name = n;
}
}
});
</script>